diff options
31 files changed, 4272 insertions, 0 deletions
@@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/LICENSING b/LICENSING new file mode 100644 index 0000000..0ebe6bb --- /dev/null +++ b/LICENSING @@ -0,0 +1,11 @@ +librfid is licensed under GNU General Public License, Version 2 as published +by the Free Software Foundation (see the file COPYING). + +This means that as soon as you wish to distribute a program that links to +librfid, that other program has to be licensed under the GPL or a compatible +license, too. + +However, an alternative (royalty-based) licensing is possible. If you want to +create a proprieatary program based on librfid, contact Harald Welte +<hwelte@hmw-consulting.de> for licensing details. + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..bcf5f44 --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +CFLAGS:=-Wall -g -I/usr/local/include -Iinclude +LDFLAGS:=-lopenct -lusb + +all: openct-escape + +openct-escape: openct-escape.o rfid_layer2.o rfid_layer2_iso14443a.o rfid_layer2_iso14443b.o rfid_asic_rc632.o rfid_reader_cm5121.o rfid.o rfid_protocol.o rfid_proto_tcl.o rfid_iso14443_common.o rfid_reader.o + $(CC) $(LDFLAGS) -o $@ $^ + +%.o: %.c + $(CC) $(CFLAGS) -o $@ -c $^ + +clean: + rm -f *.o openct-escape @@ -0,0 +1,52 @@ +librfid - low-level RFID access library +(C) 2005 by Harald Welte <laforge@gnumonks.org> +====================================================================== + +This library intends to provide a reader- and (as much as possible) +PICC / tag independent API for RFID applications. + +1. Supported Prodocols: + +At this early stage of implementaition, it offers only ISO 14443-2, ISO 14443-3 +A and B as well as ISO 14443-4 (T=CL) support. Other protocols, both open +(such as ISO 15693) and proprietary are to be added as soon as I find some more +time. + +2. Supported Readers: + +At this time only the Omnikey Cardman 5121 reader is supported. + +The cm5121 is a relatively stupid piece of hardware. Basically a contact-based +cm3121 that was enhanced by putting a Philips CL RC632 reader ASIC next to it. +There is no RFID protocol implementation on the cm5121, everything is done on +the host (PC) software. Four primitives (read/write byte/fifo) are provided +via simple PC_to_RDR_Escape CCID messages. + +This makes it the ideal device to learn and play with RFID, since you don't +have any (proprietary) software interfere and puts you in full control of +everything. + +Support for more devices shouldn't be too difficult to add, provided the +devices are stupid enough. More sophisticated readers like Integrated +Engineering or Philips Pegoda do much of the protocol handling in firmware on a +Microcontroller. This makes them (at least till now) faster, but also of +limited use, especially in education and research. + +So if you happen to run into any other dumb RFID readers, especially those +based on Philips CL RC531 and RC632, adding support should be very +straightforward. If you want to contract me for implementing a driver backend, +don't hesitate to contact me. + +3. Installation + +In order to run librfid, you need to provide a PC_to_RDR_Escape function to it. +This is the low-level transport function for communicating. Usually that function would point to a CCID device driver. + +My svn repository at +https://svn.gnumonks.org/trunk/omnikey_cardman/new/userspace/ has an openct +fork with a modified CCID driver. It allows you to use the contact based part +via PC/SC, CT-API, and the contactless part via librfid simultaneously. + + +-- Harald Welte <laforge@gnumonks.org> + @@ -0,0 +1,23 @@ +rc632: +- fix handling of timeout (program timer of RC632) + +iso14443a: +- test anticollision, resolve remaining bugs + +iso14443b: +- implement 'option 2' frame markers +- test anticollission (need multiple tags) + +tcl: +- implement chaining +- implement wait time extension + +openct: +- add ifdhandler driver + +other: +- implementation of various tags +- documentation +- homepage +- mailinglist(s) +- move to new 'librfid' svn repository diff --git a/include/rfid/rfid.h b/include/rfid/rfid.h new file mode 100644 index 0000000..bf8d799 --- /dev/null +++ b/include/rfid/rfid.h @@ -0,0 +1,12 @@ +#ifndef _RFID_H +#define _RFID_H + +#include <stdio.h> + + +#define DEBUGP(x, args ...) fprintf(stderr, "%s(%d):%s: " x, __FILE__, __LINE__, __FUNCTION__, ## args) +extern const char *rfid_hexdump(const void *data, unsigned int len); + +int rfid_init(); + +#endif /* _RFID_H */ diff --git a/include/rfid/rfid_asic.h b/include/rfid/rfid_asic.h new file mode 100644 index 0000000..e336d01 --- /dev/null +++ b/include/rfid/rfid_asic.h @@ -0,0 +1,43 @@ +#ifndef _RFID_ASIC_H +#define _RFID_ASIC_H + +#include <rfid/rfid_asic_rc632.h> + +struct rfid_asic_transport { + char *name; + union { + struct rfid_asic_rc632_transport rc632; + } priv; +}; + +struct rfid_asic_transport_handle { + void *data; /* handle to stuff like even lower layers */ + + struct rfid_asic_transport *rat; +}; + + +struct rfid_asic_handle { + struct rfid_asic_transport_handle *rath; + unsigned int fc; + unsigned int mtu; + unsigned int mru; + + union { + struct rfid_asic_rc632_handle rc632; + //struct rfid_asic_rc531_handle rc531; + } priv; + struct rfid_asic *asic; +}; + + +struct rfid_asic { + char *name; + unsigned int fc; /* carrier frequency */ + union { + struct rfid_asic_rc632 rc632; + //struct rfid_asic_rc531 rc531; + } priv; +}; + +#endif /* _RFID_ASIC_H */ diff --git a/include/rfid/rfid_asic_rc632.h b/include/rfid/rfid_asic_rc632.h new file mode 100644 index 0000000..f4c9fa1 --- /dev/null +++ b/include/rfid/rfid_asic_rc632.h @@ -0,0 +1,141 @@ +#ifndef _RFID_ASIC_RC632_H +#define _RFID_ASIC_RC632_H + +struct rfid_asic_transport_handle; + +struct rfid_asic_rc632_transport { + struct { + int (*reg_write)(struct rfid_asic_transport_handle *rath, + unsigned char reg, + unsigned char value); + int (*reg_read)(struct rfid_asic_transport_handle *rath, + unsigned char reg, + unsigned char *value); + int (*fifo_write)(struct rfid_asic_transport_handle *rath, + unsigned char len, + const unsigned char *buf, + unsigned char flags); + int (*fifo_read)(struct rfid_asic_transport_handle *rath, + unsigned char len, + unsigned char *buf); + } fn; +}; + +struct rfid_asic_handle; + +struct iso14443a_atqua; +struct iso14443a_anticol_cmd; + +struct rfid_asic_rc632 { + struct { + int (*power_up)(struct rfid_asic_handle *h); + int (*power_down)(struct rfid_asic_handle *h); + int (*turn_on_rf)(struct rfid_asic_handle *h); + int (*turn_off_rf)(struct rfid_asic_handle *h); + int (*transcieve)(struct rfid_asic_handle *h, + const unsigned char *tx_buf, + unsigned int tx_len, + unsigned char *rx_buf, + unsigned int *rx_len, + unsigned int timeout, + unsigned int flags); + struct { + int (*init)(struct rfid_asic_handle *h); + int (*transcieve_sf)(struct rfid_asic_handle *h, + unsigned char cmd, + struct iso14443a_atqa *atqa); + int (*transcieve_acf)(struct rfid_asic_handle *h, + struct iso14443a_anticol_cmd *cmd, + unsigned int *bit_of_col); + } iso14443a; + struct { + int (*init)(struct rfid_asic_handle *h); + } iso14443b; + } fn; +}; + +struct rc632_transport_handle { +}; + +/* A handle to a specific RC632 chip */ +struct rfid_asic_rc632_handle { + struct rc632_transport_handle th; +}; + +int +rc632_reg_write(struct rfid_asic_handle *handle, + unsigned char reg, + unsigned char val); + +int +rc632_reg_read(struct rfid_asic_handle *handle, + unsigned char reg, + unsigned char *val); +int +rc632_fifo_write(struct rfid_asic_handle *handle, + unsigned char len, + const unsigned char *buf, + unsigned char flags); + +int +rc632_fifo_read(struct rfid_asic_handle *handle, + unsigned char len, + unsigned char *buf); + +int +rc632_set_bits(struct rfid_asic_handle *handle, unsigned char reg, + unsigned char val); + +int +rc632_clear_bits(struct rfid_asic_handle *handle, unsigned char reg, + unsigned char val); + + +int +rc632_turn_on_rf(struct rfid_asic_handle *handle); + + +int +rc632_turn_off_rf(struct rfid_asic_handle *handle); + +int +rc632_power_up(struct rfid_asic_handle *handle); + +int +rc632_power_down(struct rfid_asic_handle *handle); + + +int +rc632_wait_idle(struct rfid_asic_handle *handle, unsigned int time); + +int +rc632_transmit(struct rfid_asic_handle *handle, + const unsigned char *buf, + unsigned char len, + unsigned int timeout); + +int +rc632_transcieve(struct rfid_asic_handle *handle, + const unsigned char *tx_buf, + unsigned char tx_len, + unsigned char *rx_buf, + unsigned char *rx_len, + unsigned int timer, + unsigned int toggle); + +int +rc632_read_eeprom(struct rfid_asic_handle *handle); + + +int +rc632_calc_crc16_from(struct rfid_asic_handle *handle); + +int +rc632_register_dump(struct rfid_asic_handle *handle, unsigned char *buf); + + +//struct rfid_asic_handle * rc632_open(struct rc632_transport *transport, void *data); + + +extern struct rfid_asic rc632; +#endif diff --git a/include/rfid/rfid_layer2.h b/include/rfid/rfid_layer2.h new file mode 100644 index 0000000..40b9bff --- /dev/null +++ b/include/rfid/rfid_layer2.h @@ -0,0 +1,56 @@ +#ifndef _RFID_LAYER2_H +#define _RFID_LAYER2_H + +struct rfid_layer2_handle; +struct rfid_reader_handle; + +#include <rfid/rfid_layer2_iso14443a.h> +#include <rfid/rfid_layer2_iso14443b.h> + + +struct rfid_layer2 { + unsigned int id; + char *name; + + struct { + struct rfid_layer2_handle *(*init)(struct rfid_reader_handle *h); + int (*open)(struct rfid_layer2_handle *h); + int (*transcieve)(struct rfid_layer2_handle *h, + const unsigned char *tx_buf, + unsigned int tx_len, unsigned char *rx_buf, + unsigned int *rx_len, unsigned int timeout, + unsigned int flags); + int (*close)(struct rfid_layer2_handle *h); + int (*fini)(struct rfid_layer2_handle *h); + } fn; + struct rfid_layer2 *next; +}; + +struct rfid_layer2_handle { + struct rfid_reader_handle *rh; + union { + struct iso14443a_handle iso14443a; + struct iso14443b_handle iso14443b; + //struct iso15693_handle iso15693; + } priv; + struct rfid_layer2 *l2; +}; + +enum rfid_layer2_id { + RFID_LAYER2_NONE, + RFID_LAYER2_ISO14443A, + RFID_LAYER2_ISO14443B, + RFID_LAYER2_ISO15693, +}; + +struct rfid_layer2_handle *rfid_layer2_init(struct rfid_reader_handle *rh, + unsigned int id); +int rfid_layer2_open(struct rfid_layer2_handle *l2h); +int rfid_layer2_transcieve(struct rfid_layer2_handle *l2h, + const unsigned char *tx_buf, unsigned int tx_len, + unsigned char *rx_buf, unsigned int *rx_len, + unsigned int timeout, unsigned int flags); +int rfid_layer2_close(struct rfid_layer2_handle *l2h); +int rfid_layer2_fini(struct rfid_layer2_handle *l2h); + +#endif diff --git a/include/rfid/rfid_layer2_iso14443a.h b/include/rfid/rfid_layer2_iso14443a.h new file mode 100644 index 0000000..400f951 --- /dev/null +++ b/include/rfid/rfid_layer2_iso14443a.h @@ -0,0 +1,93 @@ +#ifndef _RFID_ISO14443A_H +#define _RFID_ISO14443A_H + +#include <sys/types.h> + +/* protocol definitions */ + +/* ISO 14443-3, Chapter 6.3.1 */ +enum iso14443a_sf_cmd { + ISO14443A_SF_CMD_REQA = 0x26, + ISO14443A_SF_CMD_WUPA = 0x52, + ISO14443A_SF_CMD_OPT_TIMESLOT = 0x35, /* Annex C */ + /* 40 to 4f and 78 to 7f: proprietary */ +}; + +struct iso14443a_atqa { + u_int8_t bf_anticol:5, + rfu1:1, + uid_size:2; + u_int8_t proprietary:4, + rfu2:4; +}; + +#define ISO14443A_HLTA 0x5000 + +/* ISO 14443-3, Chapter 6.3.2 */ +struct iso14443a_anticol_cmd { + unsigned char sel_code; + unsigned char nvb; + unsigned char uid_bits[5]; +}; + +enum iso14443a_anticol_sel_code { + ISO14443A_AC_SEL_CODE_CL1 = 0x93, + ISO14443A_AC_SEL_CODE_CL2 = 0x95, + ISO14443A_AC_SEL_CODE_CL3 = 0x97, +}; + +#define ISO14443A_BITOFCOL_NONE 0xffffffff + +struct iso14443a_handle; + +struct iso14443a_transport { + unsigned char *name; + + struct { + int (*init)(struct iso14443a_handle *handle); + int (*fini)(struct iso14443a_handle *handle); + + int (*transcieve_sf)(struct iso14443a_handle *handle, + unsigned char cmd, + struct iso14443a_atqa *atqa); + int (*transcieve_acf)(struct iso14443a_handle *handle, + struct iso14443a_anticol_cmd *acf, + unsigned int *bit_of_col); + int (*transcieve)(struct iso14443a_handle *handle, + const unsigned char *tx_buf, + unsigned int tx_len, + unsigned char *rx_buf, + unsigned int *rx_len); + } fn; + + union { + } priv; +}; + +struct iso14443a_handle { + unsigned int state; + unsigned int level; + unsigned int tcl_capable; +}; + +enum iso14443a_level { + ISO14443A_LEVEL_NONE, + ISO14443A_LEVEL_CL1, + ISO14443A_LEVEL_CL2, + ISO14443A_LEVEL_CL3, +}; + +enum iso14443a_state { + ISO14443A_STATE_ERROR, + ISO14443A_STATE_NONE, + ISO14443A_STATE_REQA_SENT, + ISO14443A_STATE_ATQA_RCVD, + ISO14443A_STATE_NO_BITFRAME_ANTICOL, + ISO14443A_STATE_ANTICOL_RUNNING, + ISO14443A_STATE_SELECTED, +}; + +#include <rfid/rfid_layer2.h> +struct rfid_layer2 rfid_layer2_iso14443a; + +#endif /* _ISO14443A_H */ diff --git a/include/rfid/rfid_layer2_iso14443b.h b/include/rfid/rfid_layer2_iso14443b.h new file mode 100644 index 0000000..72e6155 --- /dev/null +++ b/include/rfid/rfid_layer2_iso14443b.h @@ -0,0 +1,83 @@ +#ifndef _RFID_LAYER2_ISO14443B_H +#define _RFID_LAYER2_ISO14443B_H + +struct iso14443b_atqb { + unsigned char fifty; + unsigned char pupi[4]; + unsigned char app_data[4]; + struct { + unsigned char bit_rate_capability; + unsigned char protocol_type:4, + max_frame_size:4; + unsigned char fo:2, + adc:2, + fwi:4; + } protocol_info; +}; + +struct iso14443b_attrib_hdr { + unsigned char one_d; + unsigned char identifier[4]; + struct { + unsigned char rfu:2, + sof:1, + eof:1, + min_tr1:2, + min_tr0:2; + } param1; + struct { + unsigned char fsdi:4, + spd_out:2, + spd_in:2; + } param2; + struct { + unsigned char protocol_type:4, + rfu:4; + } param3; + struct { + unsigned char cid:4, + rfu:4; + } param4; +}; + +struct iso14443b_handle { + unsigned int tcl_capable; /* do we support T=CL */ + + unsigned char pupi[4]; /* Pseudo-Unique PICC Identifier */ + unsigned int cid; /* Card ID */ + + unsigned int fsc; /* max. frame size card */ + unsigned int fsd; /* max. frame size reader */ + + unsigned int fwt; /* frame waiting time */ + + unsigned int mbl; /* maximum buffer length */ + + unsigned int tr0; /* pcd-eof to picc-subcarrier-on */ + unsigned int tr1; /* picc-subcarrier-on to picc-sof */ + + unsigned int flags; + unsigned int state; +}; + +enum { + ISO14443B_CID_SUPPORTED = 0x01, + ISO14443B_NAD_SUPPORTED = 0x02, +}; + +enum { + ISO14443B_STATE_ERROR, + ISO14443B_STATE_NONE, + ISO14443B_STATE_REQB_SENT, + ISO14443B_STATE_ATQB_RCVD, + ISO14443B_STATE_ATTRIB_SENT, + ISO14443B_STATE_SELECTED, + ISO14443B_STATE_HLTB_SENT, + ISO14443B_STATE_HALTED, +}; + + +#include <rfid/rfid_layer2.h> +struct rfid_layer2 rfid_layer2_iso14443b; + +#endif diff --git a/include/rfid/rfid_protocol.h b/include/rfid/rfid_protocol.h new file mode 100644 index 0000000..93b89c3 --- /dev/null +++ b/include/rfid/rfid_protocol.h @@ -0,0 +1,53 @@ +#ifndef _RFID_PROTOCOL_H +#define _RFID_PROTOCOL_H + +#include <rfid/rfid_layer2.h> + +#include <rfid/rfid_protocol_tcl.h> + +struct rfid_protocol_handle; + +struct rfid_protocol { + struct rfid_protocol *next; + unsigned int id; + char *name; + struct { + struct rfid_protocol_handle *(*init)(struct rfid_layer2_handle *l2h); + int (*open)(struct rfid_protocol_handle *ph); + int (*close)(struct rfid_protocol_handle *ph); + int (*fini)(struct rfid_protocol_handle *ph); + int (*transcieve)(struct rfid_protocol_handle *ph, + const unsigned char *tx_buf, + unsigned int tx_len, + unsigned char *rx_buf, + unsigned int *rx_len, + unsigned int timeout, + unsigned int flags); + } fn; +}; + +struct rfid_protocol_handle { + struct rfid_layer2_handle *l2h; + union { + struct tcl_handle tcl; + } priv; + struct rfid_protocol *proto; +}; + +struct rfid_protocol_handle * +rfid_protocol_init(struct rfid_layer2_handle *l2h, unsigned int id); +int rfid_protocol_open(struct rfid_protocol_handle *ph); +int rfid_protocol_transcieve(struct rfid_protocol_handle *ph, + const unsigned char *tx_buf, unsigned int tx_len, + unsigned char *rx_buf, unsigned int *rx_len, + unsigned int timeout, unsigned int flags); +int rfid_protocol_fini(struct rfid_protocol_handle *ph); +int rfid_protocol_close(struct rfid_protocol_handle *ph); + +int rfid_protocol_register(struct rfid_protocol *p); + +enum rfid_protocol_id { + RFID_PROTOCOL_UNKNOWN, + RFID_PROTOCOL_TCL, +}; +#endif diff --git a/include/rfid/rfid_protocol_tcl.h b/include/rfid/rfid_protocol_tcl.h new file mode 100644 index 0000000..b913e80 --- /dev/null +++ b/include/rfid/rfid_protocol_tcl.h @@ -0,0 +1,65 @@ +#ifndef _RFID_PROTOCOL_TCL_H +#define _RFID_PROTOCOL_TCL_H + +enum tcl_transport_rate { + TCL_RATE_106 = 0x01, + TCL_RATE_212 = 0x02, + TCL_RATE_424 = 0x04, + TCL_RATE_848 = 0x08, +}; + +enum tcl_transport_transcieve_flags { + TCL_TRANSP_F_TX_CRC = 0x01, /* transport adds TX CRC */ + TCL_TRANSP_F_RX_CRC = 0x02, +}; + + +struct tcl_handle { + /* derived from ats */ + unsigned char *historical_bytes; /* points into ats */ + unsigned int historical_len; + + unsigned int fsc; /* max frame size accepted by card */ + unsigned int fsd; /* max frame size accepted by reader */ + unsigned int fwt; /* frame waiting time */ + unsigned char ta; /* divisor information */ + unsigned char sfgt; /* start-up frame guard time */ + + /* otherwise determined */ + unsigned int cid; /* Card ID */ + unsigned int nad; /* Node Address */ + + unsigned int flags; + unsigned int state; /* protocol state */ + + unsigned int ats_len; + unsigned char ats[0]; +}; + +enum tcl_handle_flags { + TCL_HANDLE_F_NAD_SUPPORTED = 0x0001, + TCL_HANDLE_F_CID_SUPPORTED = 0x0002, + TCL_HANDLE_F_NAD_USED = 0x0010, + TCL_HANDLE_F_CID_USED = 0x0020, +}; + + +enum tcl_pcb_bits { + TCL_PCB_CID_FOLLOWING = 0x08, + TCL_PCB_NAD_FOLLOWING = 0x04, +}; + +enum tcl_pcd_state { + TCL_STATE_NONE = 0x00, + TCL_STATE_INITIAL, + TCL_STATE_RATS_SENT, /* waiting for ATS */ + TCL_STATE_ATS_RCVD, /* ATS received */ + TCL_STATE_PPS_SENT, /* waiting for PPS response */ + TCL_STATE_ESTABLISHED, /* xchg transparent data */ + TCL_STATE_DESELECT_SENT, /* waiting for DESELECT response */ + TCL_STATE_DESELECTED, /* card deselected or HLTA'd */ +}; + +struct rfid_protocol rfid_protocol_tcl; + +#endif diff --git a/include/rfid/rfid_reader.h b/include/rfid/rfid_reader.h new file mode 100644 index 0000000..d6ad3a1 --- /dev/null +++ b/include/rfid/rfid_reader.h @@ -0,0 +1,50 @@ +#ifndef _RFID_READER_H +#define _RFID_READER_H + +#include <rfid/rfid_asic.h> +#include <rfid/rfid_layer2_iso14443a.h> + +struct rfid_reader_handle; + +struct rfid_reader { + char *name; + unsigned int id; + int (*transcieve)(struct rfid_reader_handle *h, + const unsigned char *tx_buf, unsigned int tx_len, + unsigned char *rx_buf, unsigned int *rx_len, + unsigned int timeout, unsigned int flags); + struct rfid_reader_handle * (*open)(void *data); + int (*close)(void *data); + + struct rfid_14443a_reader { + int (*init)(struct rfid_reader_handle *h); + int (*transcieve_sf)(struct rfid_reader_handle *h, + unsigned char cmd, + struct iso14443a_atqa *atqa); + int (*transcieve_acf)(struct rfid_reader_handle *h, + struct iso14443a_anticol_cmd *cmd, + unsigned int *bit_of_col); + } iso14443a; + struct rfid_14443b_reader { + int (*init)(struct rfid_reader_handle *rh); + } iso14443b; + struct rfid_15693_reader { + + } iso15693; + struct rfid_reader *next; +}; + +enum rfid_reader_id { + RFID_READER_CM5121, + RFID_READER_PEGODA, +}; + +struct rfid_reader_handle { + struct rfid_asic_handle *ah; + + union { + + } priv; + struct rfid_reader *reader; +}; +#endif diff --git a/include/rfid/rfid_reader_cm5121.h b/include/rfid/rfid_reader_cm5121.h new file mode 100644 index 0000000..8d9a312 --- /dev/null +++ b/include/rfid/rfid_reader_cm5121.h @@ -0,0 +1,21 @@ +#ifndef _RFID_READER_CM5121_H +#define _RFID_READER_CM5121_H + +#define CM5121_CW_CONDUCTANCE 0x3f +#define CM5121_MOD_CONDUCTANCE 0x3f +#define CM5121_14443A_BITPHASE 0xa9 +#define CM5121_14443A_THRESHOLD 0xff + +#define CM5121_14443B_BITPHASE 0xad +#define CM5121_14443B_THRESHOLD 0xff + + +extern int +PC_to_RDR_Escape(void *handle, + const unsigned char *tx_buf, unsigned int tx_len, + unsigned char *rx_buf, unsigned int *rx_len); + +extern struct rfid_reader rfid_reader_cm5121; +// extern struct rfid_asic_transport cm5121_ccid; + +#endif diff --git a/openct-escape.c b/openct-escape.c new file mode 100644 index 0000000..ed28c8d --- /dev/null +++ b/openct-escape.c @@ -0,0 +1,120 @@ +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <openct/openct.h> + +#include <rfid/rfid.h> +#include <rfid/rfid_reader.h> +#include <rfid/rfid_layer2.h> +#include <rfid/rfid_protocol.h> +#include <rfid/rfid_reader_cm5121.h> + +static int slot = 1; +static ct_handle *h; +static ct_lock_handle lock; + +static struct rfid_reader_handle *rh; +static struct rfid_layer2_handle *l2h; +static struct rfid_protocol_handle *ph; + + +/* 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) +{ + ct_handle *h = (ct_handle *) handle; + int rc; + + rc = ct_card_transact(h, 1, tx_buf, tx_len, rx_buf, *rx_len); + if (rc >= 0) { + *rx_len = rc; + return 0; + } + + return rc; +} + + + +static int init() +{ + unsigned char buf[0x3f]; + unsigned char atr[64]; + unsigned + int rc; + + 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; + } + + rfid_init(); + + printf("opening reader handle\n"); + rh = rfid_reader_open(h, RFID_READER_CM5121); + if (!rh) { + fprintf(stderr, "error, no cm5121 handle\n"); + return -1; + } + + printf("opening layer2 handle\n"); + //l2h = rfid_layer2_init(rh, RFID_LAYER2_ISO14443A); + l2h = rfid_layer2_init(rh, RFID_LAYER2_ISO14443B); + if (!l2h) { + fprintf(stderr, "error during iso14443a_init\n"); + return -1; + } + + //rc632_register_dump(rh->ah, buf); + + printf("running layer2 anticol\n"); + rc = rfid_layer2_open(l2h); + if (rc < 0) { + fprintf(stderr, "error during layer2_open\n"); + return rc; + } + + printf("running layer3 (ats)\n"); + ph = rfid_protocol_init(l2h, RFID_PROTOCOL_TCL); + if (!ph) { + fprintf(stderr, "error during protocol_init\n"); + return -1; + } + if (rfid_protocol_open(ph) < 0) { + fprintf(stderr, "error during protocol_open\n"); + return -1; + } + + return 0; +} + + +int main(int argc, char **argv) +{ + int rc; + char buf[0x40]; + + if (init() < 0) + exit(1); + + /* we've established T=CL at this point */ + + rfid_reader_close(rh); + + exit(0); +} @@ -0,0 +1,209 @@ +/* Register definitions for Philips CL RC632 RFID Reader IC + * + * (C) 2005 Harald Welte <laforge@gnumonks.org> + * + * 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, + RC632_CDRCTRL_RATE_424K = 0x80, + 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, +}; + + @@ -0,0 +1,39 @@ + +#include <stdio.h> +#include <string.h> + +#include <rfid/rfid_reader_cm5121.h> +#include <rfid/rfid_protocol.h> +#include <rfid/rfid_protocol_tcl.h> + +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); + + return 0; +} + +void rfid_fini() +{ + /* FIXME: implementation */ +} diff --git a/rfid_asic_rc632.c b/rfid_asic_rc632.c new file mode 100644 index 0000000..3d5b621 --- /dev/null +++ b/rfid_asic_rc632.c @@ -0,0 +1,833 @@ +/* Generic Philips CL RC632 Routines + * + * (C) Harald Welte <laforge@gnumonks.org> + * + * Licensed under GNU General Public License, Version 2 + */ + +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include <rfid/rfid.h> +#include <rfid/rfid_asic.h> +#include <rfid/rfid_asic_rc632.h> +#include <rfid/rfid_reader_cm5121.h> +#include <rfid/rfid_layer2_iso14443a.h> + +#include "rfid_iso14443_common.h" +#include "rc632.h" +//#include "rc632_14443a.h" + + +#define ENTER() DEBUGP("entering\n") +struct rfid_asic rc632; + +/* Register and FIFO Access functions */ +int +rc632_reg_write(struct rfid_asic_handle *handle, + unsigned char reg, + unsigned char val) +{ + return handle->rath->rat->priv.rc632.fn.reg_write(handle->rath, reg, val); +} + +int +rc632_reg_read(struct rfid_asic_handle *handle, + unsigned char reg, + unsigned char *val) +{ + return handle->rath->rat->priv.rc632.fn.reg_read(handle->rath, reg, val); +} + +int +rc632_fifo_write(struct rfid_asic_handle *handle, + unsigned char len, + const unsigned char *buf, + unsigned char flags) +{ + return handle->rath->rat->priv.rc632.fn.fifo_write(handle->rath, + len, buf, flags); +} + +int +rc632_fifo_read(struct rfid_asic_handle *handle, + unsigned char len, + unsigned char *buf) +{ + return handle->rath->rat->priv.rc632.fn.fifo_read(handle->rath, len, buf); +} + + +int +rc632_set_bits(struct rfid_asic_handle *handle, + unsigned char reg, + unsigned char val) +{ + int ret; + unsigned char 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); +} + +int +rc632_clear_bits(struct rfid_asic_handle *handle, + unsigned char reg, + unsigned char val) +{ + int ret; + unsigned char 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); +} + + + +int +rc632_turn_on_rf(struct rfid_asic_handle *handle) +{ + ENTER(); + return rc632_set_bits(handle, RC632_REG_TX_CONTROL, 0x03); +} + +int +rc632_turn_off_rf(struct rfid_asic_handle *handle) +{ + ENTER(); + return rc632_clear_bits(handle, RC632_REG_TX_CONTROL, 0x03); +} + +int +rc632_power_up(struct rfid_asic_handle *handle) +{ + ENTER(); + return rc632_clear_bits(handle, RC632_REG_CONTROL, + RC632_CONTROL_POWERDOWN); +} + +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" */ +int +rc632_wait_idle(struct rfid_asic_handle *handle, unsigned int time) +{ + unsigned char 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; + } + + { + unsigned char 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; +} + +int +rc632_transmit(struct rfid_asic_handle *handle, + const unsigned char *buf, + unsigned char len, + unsigned int 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; +} + +int +rc632_transcieve(struct rfid_asic_handle *handle, + const unsigned char *tx_buf, + unsigned char tx_len, + unsigned char *rx_buf, + unsigned char *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) { + unsigned char 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); +} + +int +rc632_read_eeprom(struct rfid_asic_handle *handle) +{ + unsigned char recvbuf[60]; + unsigned char 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; +} + +int +rc632_calc_crc16_from(struct rfid_asic_handle *handle) +{ + unsigned char sndbuf[2] = { 0x01, 0x02 }; + unsigned char 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, unsigned char *buf) +{ + int ret; + unsigned char 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 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 <laforge@gnumonks.org> + * + */ + +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; + + 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; +} + + +/* 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; + +#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; + + 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; +} + +/* trasncieve 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); + +#if 0 + 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)); +#endif + ret = rc632_set_bits(handle, RC632_REG_CHANNEL_REDUNDANCY, + RC632_CR_TX_CRC_ENABLE|RC632_CR_TX_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; + + /* 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, (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; +} + +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)<<RC632_BPSKD_TAUB_SHIFT | + (0x3 & RC632_BPSKD_TAUD_MASK)<<RC632_BPSKD_TAUD_SHIFT | + RC632_BPSKD_FILTER_AMP_DETECT | + RC632_BPSKD_NO_RX_EOF | + RC632_BPSKD_NO_RX_EGT)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_RX_CONTROL2, + (RC632_RXCTRL2_AUTO_PD | + RC632_RXCTRL2_DECSRC_INT)); + 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_TX_CRC_ENABLE | + RC632_CR_RX_CRC_ENABLE | + RC632_CR_CRC3309)); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_LSB, 0xff); + if (ret < 0) + return ret; + + ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_MSB, 0xff); + 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, + .fn.power_down = &rc632_power_down, + .fn.turn_on_rf = &rc632_turn_on_rf, + .fn.turn_off_rf = &rc632_turn_off_rf, + .fn.transcieve = &rc632_iso14443a_transcieve, + .fn.iso14443a = { + .init = &rc632_iso14443a_init, + .transcieve_sf = &rc632_iso14443a_transcieve_sf, + .transcieve_acf = &rc632_iso14443a_transcieve_acf, + }, + .fn.iso14443b = { + .init = &rc632_iso14443b_init, + }, + }, +}; + + diff --git a/rfid_asic_rc632_14443a.c b/rfid_asic_rc632_14443a.c new file mode 100644 index 0000000..d6c0358 --- /dev/null +++ b/rfid_asic_rc632_14443a.c @@ -0,0 +1,393 @@ +/* + * Philips CL RC632 primitives for ISO 14443-A compliant PICC's + * + * (C) 2005 by Harald Welte <laforge@gnumonks.org> + * + */ + +#include <unistd.h> +#include <stdlib.h> +#include <string.h> + +#include <rfid/rfid.h> +#include <rfid/rfid_asic_rc632.h> +#include <rfid/rfid_layer2_iso14443a.h> + +#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; + + 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; +} + +/* trasncieve 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/rfid_asic_rc632_14443b.c b/rfid_asic_rc632_14443b.c new file mode 100644 index 0000000..62aa224 --- /dev/null +++ b/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)<<RC632_BPSKD_TAUB_SHIFT | + (0x11 & RC632_BPSKD_TAUD_MASK)<<RC632_BPSKD_TAUD_SHIFT | + RC632_BPSKD_FILTER_AMP_DETECT | + RC632_BPSKD_NO_RX_EOF | + RC632_BPSKD_NO_RX_EGT)); + + ret = rc632_reg_write(handle, RC632_REG_RX_CONTROL2, + (RC632_RXCTRL2_AUTO_PD | + RC632_RXCTRL2_DECSRC_INT)); + + ret = rc632_reg_write(handle, RC632_REG_RX_WAIT, 0x03); + + ret = rc632_reg_write(handle, RC632_REG_CHANNEL_RDUNDANCY, + (RC632_CR_TX_CRC_ENABLE | + RC632_CR_RX_CRC_ENABLE | + RC632_CR_CR3309)); + + ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_LSB, 0xff); + + ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_MSB, 0xff); + +} + diff --git a/rfid_asic_rc632_mifare.c b/rfid_asic_rc632_mifare.c new file mode 100644 index 0000000..9bfb0ae --- /dev/null +++ b/rfid_asic_rc632_mifare.c @@ -0,0 +1,25 @@ + +int +rc632_mifare_read16() +{ + unsigned char sndbuf[2]; + unsigned char recvbuf[0x40]; + unsigned char recvlen = sizeof(recvbuf); + + int ret; + + sndbuf[0] = 0x30; + sndbuf[1] = arg_4; + + memset(recvbuf, 0, sizeof(recvbuf)); + + ret = rc632_transcieve(handle, sndbuf, sizeof(sndbuf), + recvbuf, &recvlen, 0x32, 0); + if (ret < 0) + return ret; + + if (recvlen != 0x10) + return -1; + + return 0; +} diff --git a/rfid_iso14443_common.c b/rfid_iso14443_common.c new file mode 100644 index 0000000..aacb45d --- /dev/null +++ b/rfid_iso14443_common.c @@ -0,0 +1,41 @@ +static unsigned int fsdi_table[] = { 16, 24, 32, 40, 48, 64, 96, 128, 256 }; + +int iso14443_fsdi_to_fsd(unsigned int *fsd, unsigned char fsdi) +{ + /* ISO 14443-4:2000(E) Section 5.1. */ + if (fsdi > 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/rfid_iso14443_common.h b/rfid_iso14443_common.h new file mode 100644 index 0000000..848d983 --- /dev/null +++ b/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/rfid_layer2.c b/rfid_layer2.c new file mode 100644 index 0000000..eb7cb2d --- /dev/null +++ b/rfid_layer2.c @@ -0,0 +1,59 @@ +/* librfid - layer 2 protocol handler + * (C) 2005 by Harald Welte <laforge@gnumonks.org> + */ +#include <stdlib.h> +#include <stdio.h> + +#include <rfid/rfid.h> +#include <rfid/rfid_layer2.h> + +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, + const unsigned char *tx_buf, unsigned int len, + unsigned char *rx_buf, unsigned int *rx_len, + unsigned int timeout, unsigned int flags) +{ + return ph->l2->fn.transcieve(ph, 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/rfid_layer2_iso14443a.c b/rfid_layer2_iso14443a.c new file mode 100644 index 0000000..fbad9d8 --- /dev/null +++ b/rfid_layer2_iso14443a.c @@ -0,0 +1,277 @@ +/* ISO 14443-3 A anticollision implementation + * + * (C) 2005 by Harald Welte <laforge@gnumonks.org> + * + */ + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <rfid/rfid.h> +#include <rfid/rfid_layer2.h> +#include <rfid/rfid_reader.h> +#include <rfid/rfid_layer2_iso14443a.h> + +#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, + const unsigned char *tx_buf, unsigned int tx_len, + unsigned char *rx_buf, unsigned int *rx_len, + unsigned int timeout, 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; + + memset(uid, 0, sizeof(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) { + 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); + + 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; +} + +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/rfid_layer2_iso14443b.c b/rfid_layer2_iso14443b.c new file mode 100644 index 0000000..c785826 --- /dev/null +++ b/rfid_layer2_iso14443b.c @@ -0,0 +1,309 @@ +/* ISO 14443-3 B anticollision implementation + * + * (C) 2005 by Harald Welte <laforge@gnumonks.org> + * + */ + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <rfid/rfid.h> +#include <rfid/rfid_layer2.h> +#include <rfid/rfid_reader.h> +#include <rfid/rfid_layer2_iso14443b.h> + +#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) +{ + if (fwi > 14) + return -1; + + return (256 * 16 / h->rh->ah->asic->fc) * 2 ^ fwi; +} + +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->priv.iso14443b.pupi, atqb->pupi, + sizeof(h->priv.iso14443b.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] |= 0x80; + + ret = h->rh->reader->transcieve(h->rh, 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 %u\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->priv.iso14443b.pupi, 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, (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->priv.iso14443b.pupi, 4); + + ret = h->rh->reader->transcieve(h->rh, 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; + 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, + const unsigned char *tx_buf, unsigned int tx_len, + unsigned char *rx_buf, unsigned int *rx_len, + unsigned int timeout, unsigned int flags) +{ + return handle->rh->reader->transcieve(handle->rh, 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/rfid_proto_tcl.c b/rfid_proto_tcl.c new file mode 100644 index 0000000..299360e --- /dev/null +++ b/rfid_proto_tcl.c @@ -0,0 +1,448 @@ +/* ISO 14443-4 (T=CL) implementation, PCD side. + * + * (C) 2005 by Harald Welte <laforge@gnumonks.org> + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <rfid/rfid.h> +#include <rfid/rfid_protocol_tcl.h> +#include <rfid/rfid_protocol.h> +#include <rfid/rfid_layer2.h> +#include <rfid/rfid_layer2_iso14443b.h> + +#include <rfid/rfid_asic.h> +#include <rfid/rfid_reader.h> + +#include "rfid_iso14443_common.h" + + +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); +} + +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); +} + +#define activation_fwt(x) (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; + + if (len == 1) { + /* FIXME: assume some default values */ + h->priv.tcl.fsc = 32; + h->priv.tcl.ta = 0; + h->priv.tcl.sfgt = sfgi_to_sfgt(h, 0); + if (1 /* FIXME: is_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 */ + } + 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, 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; +} +/* start a PSS run (autimatically configure highest possible speed */ +static int +tcl_do_pss(struct rfid_protocol_handle *h) +{ + unsigned char ppss[3]; + unsigned char pps_response[1]; + + if (h->priv.tcl.state != TCL_STATE_ATS_RCVD) + 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: finish + + return -1; + + h->priv.tcl.state = TCL_STATE_ESTABLISHED; +} + + +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->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: */ + 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; + + if (0 /* FIXME */) { + ret = tcl_do_pss(h); + if (ret < 0) + return -1; + } + 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->priv.iso14443b.pupi, 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, 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; +} + +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 int prlg_len; + struct tcl_handle *th = &h->priv.tcl; + + 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); + + ret = h->l2h->l2->fn.transcieve(h->l2h, tx_buf, tx_len+prlg_len, + rx_buf, rx_len, th->fwt, 0); + if (ret < 0) + goto out_rxb; + + + memcpy(rx_data, rx_buf, *rx_len); + +out_rxb: + free(rx_buf); +out_txb: + free(tx_buf); +out: + return ret; +} + +#if 0 +int +tcl_send(struct tcl_handle *th) +{ + return -1; +} + +int +tcl_recv() +{ + return -1; +} +#endif + +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->l2h = l2h; + th->proto = &rfid_protocol_tcl; + + 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/rfid_protocol.c b/rfid_protocol.c new file mode 100644 index 0000000..33aa10c --- /dev/null +++ b/rfid_protocol.c @@ -0,0 +1,59 @@ +/* librfid - layer 3 protocol handler + * (C) 2005 by Harald Welte <laforge@gnumonks.org> + */ + +#include <stdlib.h> +#include <unistd.h> + +#include <rfid/rfid_layer2.h> +#include <rfid/rfid_protocol.h> + +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; + + for (p = rfid_protocol_list; p; p = p->next) + if (p->id == id) + return p->fn.init(l2h); + + return NULL; +} + +int +rfid_protocol_open(struct rfid_protocol_handle *ph) +{ + return ph->proto->fn.open(ph); +} + +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_fini(struct rfid_protocol_handle *ph) +{ + return ph->proto->fn.fini(ph); +} + +int +rfid_protocol_close(struct rfid_protocol_handle *ph) +{ + return ph->proto->fn.close(ph); +} + +int +rfid_protocol_register(struct rfid_protocol *p) +{ + p->next = rfid_protocol_list; + rfid_protocol_list = p; + + return 0; +} diff --git a/rfid_reader.c b/rfid_reader.c new file mode 100644 index 0000000..834f926 --- /dev/null +++ b/rfid_reader.c @@ -0,0 +1,48 @@ +/* librfid - core reader handling + * (C) 2005 by Harald Welte <laforge@gnumonks.org> + */ +#include <stdlib.h> +#include <stdio.h> + +#include <rfid/rfid.h> +#include <rfid/rfid_reader.h> + +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, + const unsigned char *tx_buf, unsigned int len, + unsigned char *rx_buf, unsigned int *rx_len, + unsigned int timeout, unsigned int flags) +{ + return rh->reader->transcieve(rh, tx_buf, len, rx_buf, rx_len, + timeout, flags); +} + +int +rfid_reader_close(struct rfid_reader_handle *rh) +{ + return 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/rfid_reader_cm5121.c b/rfid_reader_cm5121.c new file mode 100644 index 0000000..30d1c67 --- /dev/null +++ b/rfid_reader_cm5121.c @@ -0,0 +1,276 @@ +/* Omnikey CardMan 5121 specific RC632 transport layer + * + * (C) 2005 by Harald Welte <laforge@gnumonks.org> + * + * 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. + * + */ + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <rfid/rfid.h> +#include <rfid/rfid_reader.h> +#include <rfid/rfid_asic.h> +#include <rfid/rfid_asic_rc632.h> +#include <rfid/rfid_reader_cm5121.h> + +#define SENDBUF_LEN 40 +#define RECVBUF_LEN 40 + +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\n", reg, value); + + if (PC_to_RDR_Escape(rath->data, sndbuf, 8, rcvbuf, + &retlen) == 0) + return 0; + + 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\n", reg, *value); + return 0; + } + + 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; + + if (PC_to_RDR_Escape(rath->data, sndbuf, 7, recvbuf, &retlen) == 0) { + DEBUGP("%s\n", rfid_hexdump(recvbuf+1, num_bytes)); + memcpy(buf, recvbuf+1, num_bytes); // len == 0x7f + return 0; + } + + 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("%s\n", rfid_hexdump(bytes, len)); + + memcpy(sndbuf+7, bytes, len); + + if (PC_to_RDR_Escape(rath->data, sndbuf, len+7, recvbuf, &retlen) == 0) { + return 0; + } + + 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, + const unsigned char *tx_data, unsigned int tx_len, + unsigned char *rx_data, unsigned int *rx_len, + unsigned int timeout, unsigned int flags) +{ + return rh->ah->asic->priv.rc632.fn.transcieve(rh->ah, 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, + (unsigned char *) 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); +} + + +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 %d 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; + rath->data = data; + + rh->reader = &rfid_reader_cm5121; + + 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, + }, + .iso14443b = { + .init = &cm5121_14443b_init, + }, +}; + + |