--- /dev/null
+ 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.
+\f
+ 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.)
+\f
+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.
+\f
+ 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.
+\f
+ 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
+\f
+ 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.
--- /dev/null
+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.
+
--- /dev/null
+AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
+
+SUBDIRS = include src utils
+LINKOPTS = -lusb
+
+$(OBJECTS): libtool
+libtool: $(LIBTOOL_DEPS)
+ $(SHELL) ./config.status --recheck
--- /dev/null
+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>
+
--- /dev/null
+rc632:
+- fix handling of timeout (program timer of RC632)
+
+cm5121:
+- fix handling of TX or RX > 0x7f [buffer length in atmel chip?]
+
+iso14443a:
+[none]
+
+iso14443b:
+- implement 'option 2' frame markers
+- test anticollission (need multiple tags)
+
+iso15693:
+- implement anticollision
+- implement all the rest
+
+mifare_clasic:
+- figure out why authentication doensn't work, even though it is exactly like in other drivers
+
+tcl:
+- implement pps for asymmetric (rx/tx) speeds
+- test pps
+
+openct:
+- add ifdhandler driver
+
+other:
+- implementation of code for various passive tags
+- documentation
--- /dev/null
+very important note!
+--------------------
+
+author: hackbard@hackdaworld.org
+
+librfid (openmrtd.org) is the project of 'Harald Welte' (laforge@gnumonks.org). i just created that repository as i want to add support for the gemini2k rfid
+devices and it is much more easier to do development via cvs.
+
+hackbard
--- /dev/null
+#!/bin/sh
+
+run ()
+{
+ echo "running: $*"
+ eval $*
+
+ if test $? != 0 ; then
+ echo "error: while running '$*'"
+ exit 1
+ fi
+}
+
+run aclocal
+#run autoheader
+run libtoolize -f
+run automake -a
+run autoconf
--- /dev/null
+/* ccid-driver.c - USB ChipCardInterfaceDevices driver
+ * Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+ * Written by Werner Koch.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ *
+ * ALTERNATIVELY, this file may be distributed under the terms of the
+ * following license, in which case the provisions of this license are
+ * required INSTEAD OF the GNU General Public License. If you wish to
+ * allow use of your version of this file only under the terms of the
+ * GNU General Public License, and not to allow others to use your
+ * version of this file under the terms of the following license,
+ * indicate your decision by deleting this paragraph and the license
+ * below.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Date: 2006-01-19 23:21:46 $
+ */
+
+
+/* CCID (ChipCardInterfaceDevices) is a specification for accessing
+ smartcard via a reader connected to the USB.
+
+ This is a limited driver allowing to use some CCID drivers directly
+ without any other specila drivers. This is a fallback driver to be
+ used when nothing else works or the system should be kept minimal
+ for security reasons. It makes use of the libusb library to gain
+ portable access to USB.
+
+ This driver has been tested with the SCM SCR335 and SPR532
+ smartcard readers and requires that a reader implements the TPDU
+ level exchange and does fully automatic initialization.
+*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined(HAVE_LIBUSB) || defined(TEST)
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <usb.h>
+
+#include "ccid-driver.h"
+
+#define DRVNAME "ccid-driver: "
+
+
+/* Depending on how this source is used we either define our error
+ output to go to stderr or to the jnlib based logging functions. We
+ use the latter when GNUPG_MAJOR_VERSION is defines or when both,
+ GNUPG_SCD_MAIN_HEADER and HAVE_JNLIB_LOGGING are defined.
+*/
+#if defined(GNUPG_MAJOR_VERSION) \
+ || (defined(GNUPG_SCD_MAIN_HEADER) && defined(HAVE_JNLIB_LOGGING))
+
+#if defined(GNUPG_SCD_MAIN_HEADER)
+# include GNUPG_SCD_MAIN_HEADER
+#elif GNUPG_MAJOR_VERSION == 1 /* GnuPG Version is < 1.9. */
+# include "options.h"
+# include "util.h"
+# include "memory.h"
+# include "cardglue.h"
+# else /* This is the modularized GnuPG 1.9 or later. */
+# include "scdaemon.h"
+#endif
+
+
+# define DEBUGOUT(t) do { if (debug_level) \
+ log_debug (DRVNAME t); } while (0)
+# define DEBUGOUT_1(t,a) do { if (debug_level) \
+ log_debug (DRVNAME t,(a)); } while (0)
+# define DEBUGOUT_2(t,a,b) do { if (debug_level) \
+ log_debug (DRVNAME t,(a),(b)); } while (0)
+# define DEBUGOUT_3(t,a,b,c) do { if (debug_level) \
+ log_debug (DRVNAME t,(a),(b),(c));} while (0)
+# define DEBUGOUT_4(t,a,b,c,d) do { if (debug_level) \
+ log_debug (DRVNAME t,(a),(b),(c),(d));} while (0)
+# define DEBUGOUT_CONT(t) do { if (debug_level) \
+ log_printf (t); } while (0)
+# define DEBUGOUT_CONT_1(t,a) do { if (debug_level) \
+ log_printf (t,(a)); } while (0)
+# define DEBUGOUT_CONT_2(t,a,b) do { if (debug_level) \
+ log_printf (t,(a),(b)); } while (0)
+# define DEBUGOUT_CONT_3(t,a,b,c) do { if (debug_level) \
+ log_printf (t,(a),(b),(c)); } while (0)
+# define DEBUGOUT_LF() do { if (debug_level) \
+ log_printf ("\n"); } while (0)
+
+#else /* Other usage of this source - don't use gnupg specifics. */
+
+# define DEBUGOUT(t) do { if (debug_level) \
+ fprintf (stderr, DRVNAME t); } while (0)
+# define DEBUGOUT_1(t,a) do { if (debug_level) \
+ fprintf (stderr, DRVNAME t, (a)); } while (0)
+# define DEBUGOUT_2(t,a,b) do { if (debug_level) \
+ fprintf (stderr, DRVNAME t, (a), (b)); } while (0)
+# define DEBUGOUT_3(t,a,b,c) do { if (debug_level) \
+ fprintf (stderr, DRVNAME t, (a), (b), (c)); } while (0)
+# define DEBUGOUT_4(t,a,b,c,d) do { if (debug_level) \
+ fprintf (stderr, DRVNAME t, (a), (b), (c), (d));} while(0)
+# define DEBUGOUT_CONT(t) do { if (debug_level) \
+ fprintf (stderr, t); } while (0)
+# define DEBUGOUT_CONT_1(t,a) do { if (debug_level) \
+ fprintf (stderr, t, (a)); } while (0)
+# define DEBUGOUT_CONT_2(t,a,b) do { if (debug_level) \
+ fprintf (stderr, t, (a), (b)); } while (0)
+# define DEBUGOUT_CONT_3(t,a,b,c) do { if (debug_level) \
+ fprintf (stderr, t, (a), (b), (c)); } while (0)
+# define DEBUGOUT_LF() do { if (debug_level) \
+ putc ('\n', stderr); } while (0)
+
+#endif /* This source not used by scdaemon. */
+
+
+
+enum {
+ RDR_to_PC_NotifySlotChange= 0x50,
+ RDR_to_PC_HardwareError = 0x51,
+
+ PC_to_RDR_SetParameters = 0x61,
+ PC_to_RDR_IccPowerOn = 0x62,
+ PC_to_RDR_IccPowerOff = 0x63,
+ PC_to_RDR_GetSlotStatus = 0x65,
+ PC_to_RDR_Secure = 0x69,
+ PC_to_RDR_T0APDU = 0x6a,
+ PC_to_RDR_Escape = 0x6b,
+ PC_to_RDR_GetParameters = 0x6c,
+ PC_to_RDR_ResetParameters = 0x6d,
+ PC_to_RDR_IccClock = 0x6e,
+ PC_to_RDR_XfrBlock = 0x6f,
+ PC_to_RDR_Mechanical = 0x71,
+ PC_to_RDR_Abort = 0x72,
+ PC_to_RDR_SetDataRate = 0x73,
+
+ RDR_to_PC_DataBlock = 0x80,
+ RDR_to_PC_SlotStatus = 0x81,
+ RDR_to_PC_Parameters = 0x82,
+ RDR_to_PC_Escape = 0x83,
+ RDR_to_PC_DataRate = 0x84
+};
+
+
+/* Two macro to detect whether a CCID command has failed and to get
+ the error code. These macros assume that we can access the
+ mandatory first 10 bytes of a CCID message in BUF. */
+#define CCID_COMMAND_FAILED(buf) ((buf)[7] & 0x40)
+#define CCID_ERROR_CODE(buf) (((unsigned char *)(buf))[8])
+
+
+/* We need to know the vendor to do some hacks. */
+enum {
+ VENDOR_SCM = 0x04e6,
+ VENDOR_CHERRY = 0x046a,
+ VENDOR_OMNIKEY= 0x076b,
+ VENDOR_GEMPC = 0x08e6
+};
+
+
+/* Store information on the driver's state. A pointer to such a
+ structure is used as handle for most functions. */
+struct ccid_driver_s
+{
+ usb_dev_handle *idev;
+ char *rid;
+ unsigned short id_vendor;
+ unsigned short id_product;
+ unsigned short bcd_device;
+ int ifc_no;
+ int ep_bulk_out;
+ int ep_bulk_in;
+ int ep_intr;
+ int seqno;
+ unsigned char t1_ns;
+ unsigned char t1_nr;
+ int nonnull_nad;
+ int auto_ifsd;
+ int max_ifsd;
+ int ifsd;
+ int powered_off;
+ int has_pinpad;
+ int apdu_level; /* Reader supports short APDU level exchange. */
+};
+
+
+static int initialized_usb; /* Tracks whether USB has been initialized. */
+static int debug_level; /* Flag to control the debug output.
+ 0 = No debugging
+ 1 = USB I/O info
+ 2 = T=1 protocol tracing
+ */
+
+
+static unsigned int compute_edc (const unsigned char *data, size_t datalen,
+ int use_crc);
+static int bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen);
+static int bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
+ size_t *nread, int expected_type, int seqno, int timeout,
+ int no_debug);
+
+/* Convert a little endian stored 4 byte value into an unsigned
+ integer. */
+static unsigned int
+convert_le_u32 (const unsigned char *buf)
+{
+ return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+}
+
+static void
+set_msg_len (unsigned char *msg, unsigned int length)
+{
+ msg[1] = length;
+ msg[2] = length >> 8;
+ msg[3] = length >> 16;
+ msg[4] = length >> 24;
+}
+
+
+/* Pint an error message for a failed CCID command including a textual
+ error code. MSG is shall be the CCID message of at least 10 bytes. */
+static void
+print_command_failed (const unsigned char *msg)
+{
+ const char *t;
+ char buffer[100];
+ int ec;
+
+ if (!debug_level)
+ return;
+
+ ec = CCID_ERROR_CODE (msg);
+ switch (ec)
+ {
+ case 0x00: t = "Command not supported"; break;
+
+ case 0xE0: t = "Slot busy"; break;
+ case 0xEF: t = "PIN cancelled"; break;
+ case 0xF0: t = "PIN timeout"; break;
+
+ case 0xF2: t = "Automatic sequence ongoing"; break;
+ case 0xF3: t = "Deactivated Protocol"; break;
+ case 0xF4: t = "Procedure byte conflict"; break;
+ case 0xF5: t = "ICC class not supported"; break;
+ case 0xF6: t = "ICC protocol not supported"; break;
+ case 0xF7: t = "Bad checksum in ATR"; break;
+ case 0xF8: t = "Bad TS in ATR"; break;
+
+ case 0xFB: t = "An all inclusive hardware error occurred"; break;
+ case 0xFC: t = "Overrun error while talking to the ICC"; break;
+ case 0xFD: t = "Parity error while talking to the ICC"; break;
+ case 0xFE: t = "CCID timed out while talking to the ICC"; break;
+ case 0xFF: t = "Host aborted the current activity"; break;
+
+ default:
+ if (ec > 0 && ec < 128)
+ sprintf (buffer, "Parameter error at offset %d", ec);
+ else
+ sprintf (buffer, "Error code %02X", ec);
+ t = buffer;
+ break;
+ }
+ DEBUGOUT_1 ("CCID command failed: %s\n", t);
+}
+
+
+
+
+/* Parse a CCID descriptor, optionally print all available features
+ and test whether this reader is usable by this driver. Returns 0
+ if it is usable.
+
+ Note, that this code is based on the one in lsusb.c of the
+ usb-utils package, I wrote on 2003-09-01. -wk. */
+static int
+parse_ccid_descriptor (ccid_driver_t handle,
+ const unsigned char *buf, size_t buflen)
+{
+ unsigned int i;
+ unsigned int us;
+ int have_t1 = 0, have_tpdu=0, have_auto_conf = 0;
+
+
+ handle->nonnull_nad = 0;
+ handle->auto_ifsd = 0;
+ handle->max_ifsd = 32;
+ handle->ifsd = 0;
+ handle->has_pinpad = 0;
+ handle->apdu_level = 0;
+ DEBUGOUT_3 ("idVendor: %04X idProduct: %04X bcdDevice: %04X\n",
+ handle->id_vendor, handle->id_product, handle->bcd_device);
+ if (buflen < 54 || buf[0] < 54)
+ {
+ DEBUGOUT ("CCID device descriptor is too short\n");
+ return -1;
+ }
+
+ DEBUGOUT ("ChipCard Interface Descriptor:\n");
+ DEBUGOUT_1 (" bLength %5u\n", buf[0]);
+ DEBUGOUT_1 (" bDescriptorType %5u\n", buf[1]);
+ DEBUGOUT_2 (" bcdCCID %2x.%02x", buf[3], buf[2]);
+ if (buf[3] != 1 || buf[2] != 0)
+ DEBUGOUT_CONT(" (Warning: Only accurate for version 1.0)");
+ DEBUGOUT_LF ();
+
+ DEBUGOUT_1 (" nMaxSlotIndex %5u\n", buf[4]);
+ DEBUGOUT_2 (" bVoltageSupport %5u %s\n",
+ buf[5], (buf[5] == 1? "5.0V" : buf[5] == 2? "3.0V"
+ : buf[5] == 3? "1.8V":"?"));
+
+ us = convert_le_u32 (buf+6);
+ DEBUGOUT_1 (" dwProtocols %5u ", us);
+ if ((us & 1))
+ DEBUGOUT_CONT (" T=0");
+ if ((us & 2))
+ {
+ DEBUGOUT_CONT (" T=1");
+ have_t1 = 1;
+ }
+ if ((us & ~3))
+ DEBUGOUT_CONT (" (Invalid values detected)");
+ DEBUGOUT_LF ();
+
+ us = convert_le_u32(buf+10);
+ DEBUGOUT_1 (" dwDefaultClock %5u\n", us);
+ us = convert_le_u32(buf+14);
+ DEBUGOUT_1 (" dwMaxiumumClock %5u\n", us);
+ DEBUGOUT_1 (" bNumClockSupported %5u\n", buf[18]);
+ us = convert_le_u32(buf+19);
+ DEBUGOUT_1 (" dwDataRate %7u bps\n", us);
+ us = convert_le_u32(buf+23);
+ DEBUGOUT_1 (" dwMaxDataRate %7u bps\n", us);
+ DEBUGOUT_1 (" bNumDataRatesSupp. %5u\n", buf[27]);
+
+ us = convert_le_u32(buf+28);
+ DEBUGOUT_1 (" dwMaxIFSD %5u\n", us);
+ handle->max_ifsd = us;
+
+ us = convert_le_u32(buf+32);
+ DEBUGOUT_1 (" dwSyncProtocols %08X ", us);
+ if ((us&1))
+ DEBUGOUT_CONT ( " 2-wire");
+ if ((us&2))
+ DEBUGOUT_CONT ( " 3-wire");
+ if ((us&4))
+ DEBUGOUT_CONT ( " I2C");
+ DEBUGOUT_LF ();
+
+ us = convert_le_u32(buf+36);
+ DEBUGOUT_1 (" dwMechanical %08X ", us);
+ if ((us & 1))
+ DEBUGOUT_CONT (" accept");
+ if ((us & 2))
+ DEBUGOUT_CONT (" eject");
+ if ((us & 4))
+ DEBUGOUT_CONT (" capture");
+ if ((us & 8))
+ DEBUGOUT_CONT (" lock");
+ DEBUGOUT_LF ();
+
+ us = convert_le_u32(buf+40);
+ DEBUGOUT_1 (" dwFeatures %08X\n", us);
+ if ((us & 0x0002))
+ {
+ DEBUGOUT (" Auto configuration based on ATR\n");
+ have_auto_conf = 1;
+ }
+ if ((us & 0x0004))
+ DEBUGOUT (" Auto activation on insert\n");
+ if ((us & 0x0008))
+ DEBUGOUT (" Auto voltage selection\n");
+ if ((us & 0x0010))
+ DEBUGOUT (" Auto clock change\n");
+ if ((us & 0x0020))
+ DEBUGOUT (" Auto baud rate change\n");
+ if ((us & 0x0040))
+ DEBUGOUT (" Auto parameter negotation made by CCID\n");
+ else if ((us & 0x0080))
+ DEBUGOUT (" Auto PPS made by CCID\n");
+ else if ((us & (0x0040 | 0x0080)))
+ DEBUGOUT (" WARNING: conflicting negotation features\n");
+
+ if ((us & 0x0100))
+ DEBUGOUT (" CCID can set ICC in clock stop mode\n");
+ if ((us & 0x0200))
+ {
+ DEBUGOUT (" NAD value other than 0x00 accepted\n");
+ handle->nonnull_nad = 1;
+ }
+ if ((us & 0x0400))
+ {
+ DEBUGOUT (" Auto IFSD exchange\n");
+ handle->auto_ifsd = 1;
+ }
+
+ if ((us & 0x00010000))
+ {
+ DEBUGOUT (" TPDU level exchange\n");
+ have_tpdu = 1;
+ }
+ else if ((us & 0x00020000))
+ {
+ DEBUGOUT (" Short APDU level exchange\n");
+ handle->apdu_level = 1;
+ }
+ else if ((us & 0x00040000))
+ {
+ DEBUGOUT (" Short and extended APDU level exchange\n");
+ handle->apdu_level = 1;
+ }
+ else if ((us & 0x00070000))
+ DEBUGOUT (" WARNING: conflicting exchange levels\n");
+
+ us = convert_le_u32(buf+44);
+ DEBUGOUT_1 (" dwMaxCCIDMsgLen %5u\n", us);
+
+ DEBUGOUT ( " bClassGetResponse ");
+ if (buf[48] == 0xff)
+ DEBUGOUT_CONT ("echo\n");
+ else
+ DEBUGOUT_CONT_1 (" %02X\n", buf[48]);
+
+ DEBUGOUT ( " bClassEnvelope ");
+ if (buf[49] == 0xff)
+ DEBUGOUT_CONT ("echo\n");
+ else
+ DEBUGOUT_CONT_1 (" %02X\n", buf[48]);
+
+ DEBUGOUT ( " wlcdLayout ");
+ if (!buf[50] && !buf[51])
+ DEBUGOUT_CONT ("none\n");
+ else
+ DEBUGOUT_CONT_2 ("%u cols %u lines\n", buf[50], buf[51]);
+
+ DEBUGOUT_1 (" bPINSupport %5u ", buf[52]);
+ if ((buf[52] & 1))
+ {
+ DEBUGOUT_CONT ( " verification");
+ handle->has_pinpad |= 1;
+ }
+ if ((buf[52] & 2))
+ {
+ DEBUGOUT_CONT ( " modification");
+ handle->has_pinpad |= 2;
+ }
+ DEBUGOUT_LF ();
+
+ DEBUGOUT_1 (" bMaxCCIDBusySlots %5u\n", buf[53]);
+
+ if (buf[0] > 54) {
+ DEBUGOUT (" junk ");
+ for (i=54; i < buf[0]-54; i++)
+ DEBUGOUT_CONT_1 (" %02X", buf[i]);
+ DEBUGOUT_LF ();
+ }
+
+ if (!have_t1 || !(have_tpdu || handle->apdu_level) || !have_auto_conf)
+ {
+ DEBUGOUT ("this drivers requires that the reader supports T=1, "
+ "TPDU or APDU level exchange and auto configuration - "
+ "this is not available\n");
+ return -1;
+ }
+
+
+ /* SCM drivers get stuck in their internal USB stack if they try to
+ send a frame of n*wMaxPacketSize back to us. Given that
+ wMaxPacketSize is 64 for these readers we set the IFSD to a value
+ lower than that:
+ 64 - 10 CCID header - 4 T1frame - 2 reserved = 48
+ Product Ids:
+ 0xe001 - SCR 331
+ 0x5111 - SCR 331-DI
+ 0x5115 - SCR 335
+ 0xe003 - SPR 532
+ */
+ if (handle->id_vendor == VENDOR_SCM
+ && handle->max_ifsd > 48
+ && ( (handle->id_product == 0xe001 && handle->bcd_device < 0x0516)
+ ||(handle->id_product == 0x5111 && handle->bcd_device < 0x0620)
+ ||(handle->id_product == 0x5115 && handle->bcd_device < 0x0514)
+ ||(handle->id_product == 0xe003 && handle->bcd_device < 0x0504)
+ ))
+ {
+ DEBUGOUT ("enabling workaround for buggy SCM readers\n");
+ handle->max_ifsd = 48;
+ }
+
+
+ return 0;
+}
+
+
+static char *
+get_escaped_usb_string (usb_dev_handle *idev, int idx,
+ const char *prefix, const char *suffix)
+{
+ int rc;
+ unsigned char buf[280];
+ unsigned char *s;
+ unsigned int langid;
+ size_t i, n, len;
+ char *result;
+
+ if (!idx)
+ return NULL;
+
+ /* Fixme: The next line is for the current Valgrid without support
+ for USB IOCTLs. */
+ memset (buf, 0, sizeof buf);
+
+ /* First get the list of supported languages and use the first one.
+ If we do don't find it we try to use English. Note that this is
+ all in a 2 bute Unicode encoding using little endian. */
+ rc = usb_control_msg (idev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
+ (USB_DT_STRING << 8), 0,
+ (char*)buf, sizeof buf, 1000 /* ms timeout */);
+ if (rc < 4)
+ langid = 0x0409; /* English. */
+ else
+ langid = (buf[3] << 8) | buf[2];
+
+ rc = usb_control_msg (idev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
+ (USB_DT_STRING << 8) + idx, langid,
+ (char*)buf, sizeof buf, 1000 /* ms timeout */);
+ if (rc < 2 || buf[1] != USB_DT_STRING)
+ return NULL; /* Error or not a string. */
+ len = buf[0];
+ if (len > rc)
+ return NULL; /* Larger than our buffer. */
+
+ for (s=buf+2, i=2, n=0; i+1 < len; i += 2, s += 2)
+ {
+ if (s[1])
+ n++; /* High byte set. */
+ else if (*s <= 0x20 || *s >= 0x7f || *s == '%' || *s == ':')
+ n += 3 ;
+ else
+ n++;
+ }
+
+ result = malloc (strlen (prefix) + n + strlen (suffix) + 1);
+ if (!result)
+ return NULL;
+
+ strcpy (result, prefix);
+ n = strlen (prefix);
+ for (s=buf+2, i=2; i+1 < len; i += 2, s += 2)
+ {
+ if (s[1])
+ result[n++] = '\xff'; /* High byte set. */
+ else if (*s <= 0x20 || *s >= 0x7f || *s == '%' || *s == ':')
+ {
+ sprintf (result+n, "%%%02X", *s);
+ n += 3;
+ }
+ else
+ result[n++] = *s;
+ }
+ strcpy (result+n, suffix);
+
+ return result;
+}
+
+/* This function creates an reader id to be used to find the same
+ physical reader after a reset. It returns an allocated and possibly
+ percent escaped string or NULL if not enough memory is available. */
+static char *
+make_reader_id (usb_dev_handle *idev,
+ unsigned int vendor, unsigned int product,
+ unsigned char serialno_index)
+{
+ char *rid;
+ char prefix[20];
+
+ sprintf (prefix, "%04X:%04X:", (vendor & 0xfff), (product & 0xffff));
+ rid = get_escaped_usb_string (idev, serialno_index, prefix, ":0");
+ if (!rid)
+ {
+ rid = malloc (strlen (prefix) + 3 + 1);
+ if (!rid)
+ return NULL;
+ strcpy (rid, prefix);
+ strcat (rid, "X:0");
+ }
+ return rid;
+}
+
+
+/* Helper to find the endpoint from an interface descriptor. */
+static int
+find_endpoint (struct usb_interface_descriptor *ifcdesc, int mode)
+{
+ int no;
+ int want_bulk_in = 0;
+
+ if (mode == 1)
+ want_bulk_in = 0x80;
+ for (no=0; no < ifcdesc->bNumEndpoints; no++)
+ {
+ struct usb_endpoint_descriptor *ep = ifcdesc->endpoint + no;
+ if (ep->bDescriptorType != USB_DT_ENDPOINT)
+ ;
+ else if (mode == 2
+ && ((ep->bmAttributes & USB_ENDPOINT_TYPE_MASK)
+ == USB_ENDPOINT_TYPE_INTERRUPT)
+ && (ep->bEndpointAddress & 0x80))
+ return (ep->bEndpointAddress & 0x0f);
+ else if (((ep->bmAttributes & USB_ENDPOINT_TYPE_MASK)
+ == USB_ENDPOINT_TYPE_BULK)
+ && (ep->bEndpointAddress & 0x80) == want_bulk_in)
+ return (ep->bEndpointAddress & 0x0f);
+ }
+ /* Should never happen. */
+ return mode == 2? 0x83 : mode == 1? 0x82 :1;
+}
+
+
+
+/* Combination function to either scan all CCID devices or to find and
+ open one specific device.
+
+ With READERNO = -1 and READERID is NULL, scan mode is used and
+ R_RID should be the address where to store the list of reader_ids
+ we found. If on return this list is empty, no CCID device has been
+ found; otherwise it points to an allocated linked list of reader
+ IDs. Note that in this mode the function always returns NULL.
+
+ With READERNO >= 0 or READERID is not NULL find mode is used. This
+ uses the same algorithm as the scan mode but stops and returns at
+ the entry number READERNO and return the handle for the the opened
+ USB device. If R_ID is not NULL it will receive the reader ID of
+ that device. If R_DEV is not NULL it will the device pointer of
+ that device. If IFCDESC_EXTRA is NOT NULL it will receive a
+ malloced copy of the interfaces "extra: data filed;
+ IFCDESC_EXTRA_LEN receive the lengtyh of this field. If there is
+ no reader with number READERNO or that reader is not usable by our
+ implementation NULL will be returned. The caller must close a
+ returned USB device handle and free (if not passed as NULL) the
+ returned reader ID info as well as the IFCDESC_EXTRA. On error
+ NULL will get stored at R_RID, R_DEV, IFCDESC_EXTRA and
+ IFCDESC_EXTRA_LEN. With READERID being -1 the function stops if
+ the READERID was found.
+
+ Note that the first entry of the returned reader ID list in scan mode
+ corresponds with a READERNO of 0 in find mode.
+*/
+static usb_dev_handle *
+scan_or_find_devices (int readerno, const char *readerid,
+ char **r_rid,
+ struct usb_device **r_dev,
+ unsigned char **ifcdesc_extra,
+ size_t *ifcdesc_extra_len,
+ int *interface_number,
+ int *ep_bulk_out, int *ep_bulk_in, int *ep_intr)
+{
+ char *rid_list = NULL;
+ int count = 0;
+ struct usb_bus *busses, *bus;
+ struct usb_device *dev = NULL;
+ usb_dev_handle *idev = NULL;
+ int scan_mode = (readerno == -1 && !readerid);
+
+ /* Set return values to a default. */
+ if (r_rid)
+ *r_rid = NULL;
+ if (r_dev)
+ *r_dev = NULL;
+ if (ifcdesc_extra)
+ *ifcdesc_extra = NULL;
+ if (ifcdesc_extra_len)
+ *ifcdesc_extra_len = 0;
+ if (interface_number)
+ *interface_number = 0;
+
+ /* See whether we want scan or find mode. */
+ if (scan_mode)
+ {
+ assert (r_rid);
+ }
+
+ usb_find_busses();
+ usb_find_devices();
+
+#ifdef HAVE_USB_GET_BUSSES
+ busses = usb_get_busses();
+#else
+ busses = usb_busses;
+#endif
+
+ for (bus = busses; bus; bus = bus->next)
+ {
+ for (dev = bus->devices; dev; dev = dev->next)
+ {
+ int cfg_no;
+
+ for (cfg_no=0; cfg_no < dev->descriptor.bNumConfigurations; cfg_no++)
+ {
+ struct usb_config_descriptor *config = dev->config + cfg_no;
+ int ifc_no;
+
+ if(!config)
+ continue;
+
+ for (ifc_no=0; ifc_no < config->bNumInterfaces; ifc_no++)
+ {
+ struct usb_interface *interface
+ = config->interface + ifc_no;
+ int set_no;
+
+ if (!interface)
+ continue;
+
+ for (set_no=0; set_no < interface->num_altsetting; set_no++)
+ {
+ struct usb_interface_descriptor *ifcdesc
+ = interface->altsetting + set_no;
+ char *rid;
+
+ /* The second condition is for some SCM Micro
+ SPR 532 which does not know about the
+ assigned CCID class. Instead of trying to
+ interpret the strings we simply look at the
+ product ID. */
+ if (ifcdesc && ifcdesc->extra
+ && ( (ifcdesc->bInterfaceClass == 11
+ && ifcdesc->bInterfaceSubClass == 0
+ && ifcdesc->bInterfaceProtocol == 0)
+ || (ifcdesc->bInterfaceClass == 255
+ && dev->descriptor.idVendor == 0x04e6
+ && dev->descriptor.idProduct == 0xe003)))
+ {
+ idev = usb_open (dev);
+ if (!idev)
+ {
+ DEBUGOUT_1 ("usb_open failed: %s\n",
+ strerror (errno));
+ continue;
+ }
+
+ rid = make_reader_id (idev,
+ dev->descriptor.idVendor,
+ dev->descriptor.idProduct,
+ dev->descriptor.iSerialNumber);
+ if (rid)
+ {
+ if (scan_mode)
+ {
+ char *p;
+
+ /* We are collecting infos about all
+ available CCID readers. Store
+ them and continue. */
+ DEBUGOUT_2 ("found CCID reader %d "
+ "(ID=%s)\n",
+ count, rid );
+ if ((p = malloc ((rid_list?
+ strlen (rid_list):0)
+ + 1 + strlen (rid)
+ + 1)))
+ {
+ *p = 0;
+ if (rid_list)
+ {
+ strcat (p, rid_list);
+ free (rid_list);
+ }
+ strcat (p, rid);
+ strcat (p, "\n");
+ rid_list = p;
+ }
+ else /* Out of memory. */
+ free (rid);
+ rid = NULL;
+ count++;
+ }
+ else if (!readerno
+ || (readerno < 0
+ && readerid
+ && !strcmp (readerid, rid)))
+ {
+ /* We found the requested reader. */
+ if (ifcdesc_extra && ifcdesc_extra_len)
+ {
+ *ifcdesc_extra = malloc (ifcdesc
+ ->extralen);
+ if (!*ifcdesc_extra)
+ {
+ usb_close (idev);
+ free (rid);
+ return NULL; /* Out of core. */
+ }
+ memcpy (*ifcdesc_extra, ifcdesc->extra,
+ ifcdesc->extralen);
+ *ifcdesc_extra_len = ifcdesc->extralen;
+ }
+ if (interface_number)
+ *interface_number = (ifcdesc->
+ bInterfaceNumber);
+ if (ep_bulk_out)
+ *ep_bulk_out = find_endpoint (ifcdesc, 0);
+ if (ep_bulk_in)
+ *ep_bulk_in = find_endpoint (ifcdesc, 1);
+ if (ep_intr)
+ *ep_intr = find_endpoint (ifcdesc, 2);
+
+
+ if (r_dev)
+ *r_dev = dev;
+ if (r_rid)
+ {
+ *r_rid = rid;
+ rid = NULL;
+ }
+ else
+ free (rid);
+ return idev; /* READY. */
+ }
+ else
+ {
+ /* This is not yet the reader we
+ want. fixme: We could avoid the
+ extra usb_open in this case. */
+ if (readerno >= 0)
+ readerno--;
+ }
+ free (rid);
+ }
+
+ usb_close (idev);
+ idev = NULL;
+ goto next_device;
+ }
+ }
+ }
+ }
+ next_device:
+ ;
+ }
+ }
+
+ if (scan_mode)
+ *r_rid = rid_list;
+
+ return NULL;
+}
+
+
+/* Set the level of debugging to to usea dn return the old level. -1
+ just returns the old level. A level of 0 disables debugging, 1
+ enables debugging, 2 enables additional tracing of the T=1
+ protocol, other values are not yet defined. */
+int
+ccid_set_debug_level (int level)
+{
+ int old = debug_level;
+ if (level != -1)
+ debug_level = level;
+ return old;
+}
+
+
+char *
+ccid_get_reader_list (void)
+{
+ char *reader_list;
+
+ if (!initialized_usb)
+ {
+ usb_init ();
+ initialized_usb = 1;
+ }
+
+ scan_or_find_devices (-1, NULL, &reader_list, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ return reader_list;
+}
+
+
+/* Open the reader with the internal number READERNO and return a
+ pointer to be used as handle in HANDLE. Returns 0 on success. */
+int
+ccid_open_reader (ccid_driver_t *handle, const char *readerid)
+{
+ int rc = 0;
+ struct usb_device *dev = NULL;
+ usb_dev_handle *idev = NULL;
+ char *rid = NULL;
+ unsigned char *ifcdesc_extra = NULL;
+ size_t ifcdesc_extra_len;
+ int readerno;
+ int ifc_no, ep_bulk_out, ep_bulk_in, ep_intr;
+
+ *handle = NULL;
+
+ if (!initialized_usb)
+ {
+ usb_init ();
+ initialized_usb = 1;
+ }
+
+ /* See whether we want to use the reader ID string or a reader
+ number. A readerno of -1 indicates that the reader ID string is
+ to be used. */
+ if (readerid && strchr (readerid, ':'))
+ readerno = -1; /* We want to use the readerid. */
+ else if (readerid)
+ {
+ readerno = atoi (readerid);
+ if (readerno < 0)
+ {
+ DEBUGOUT ("no CCID readers found\n");
+ rc = CCID_DRIVER_ERR_NO_READER;
+ goto leave;
+ }
+ }
+ else
+ readerno = 0; /* Default. */
+
+ idev = scan_or_find_devices (readerno, readerid, &rid, &dev,
+ &ifcdesc_extra, &ifcdesc_extra_len,
+ &ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr);
+ if (!idev)
+ {
+ if (readerno == -1)
+ DEBUGOUT_1 ("no CCID reader with ID %s\n", readerid );
+ else
+ DEBUGOUT_1 ("no CCID reader with number %d\n", readerno );
+ rc = CCID_DRIVER_ERR_NO_READER;
+ goto leave;
+ }
+
+ /* Okay, this is a CCID reader. */
+ *handle = calloc (1, sizeof **handle);
+ if (!*handle)
+ {
+ DEBUGOUT ("out of memory\n");
+ rc = CCID_DRIVER_ERR_OUT_OF_CORE;
+ goto leave;
+ }
+ (*handle)->idev = idev;
+ (*handle)->rid = rid;
+ (*handle)->id_vendor = dev->descriptor.idVendor;
+ (*handle)->id_product = dev->descriptor.idProduct;
+ (*handle)->bcd_device = dev->descriptor.bcdDevice;
+ (*handle)->ifc_no = ifc_no;
+ (*handle)->ep_bulk_out = ep_bulk_out;
+ (*handle)->ep_bulk_in = ep_bulk_in;
+ (*handle)->ep_intr = ep_intr;
+
+ DEBUGOUT_2 ("using CCID reader %d (ID=%s)\n", readerno, rid );
+
+
+ if (parse_ccid_descriptor (*handle, ifcdesc_extra, ifcdesc_extra_len))
+ {
+ DEBUGOUT ("device not supported\n");
+ rc = CCID_DRIVER_ERR_NO_READER;
+ goto leave;
+ }
+
+ rc = usb_claim_interface (idev, ifc_no);
+ if (rc)
+ {
+ DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc);
+ rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
+ goto leave;
+ }
+
+ leave:
+ free (ifcdesc_extra);
+ if (rc)
+ {
+ free (rid);
+ if (idev)
+ usb_close (idev);
+ free (*handle);
+ *handle = NULL;
+ }
+
+ return rc;
+}
+
+
+static void
+do_close_reader (ccid_driver_t handle)
+{
+ int rc;
+ unsigned char msg[100];
+ size_t msglen;
+ unsigned char seqno;
+
+ if (!handle->powered_off)
+ {
+ msg[0] = PC_to_RDR_IccPowerOff;
+ msg[5] = 0; /* slot */
+ msg[6] = seqno = handle->seqno++;
+ msg[7] = 0; /* RFU */
+ msg[8] = 0; /* RFU */
+ msg[9] = 0; /* RFU */
+ set_msg_len (msg, 0);
+ msglen = 10;
+
+ rc = bulk_out (handle, msg, msglen);
+ if (!rc)
+ bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus,
+ seqno, 2000, 0);
+ handle->powered_off = 1;
+ }
+ if (handle->idev)
+ {
+ usb_release_interface (handle->idev, handle->ifc_no);
+ usb_close (handle->idev);
+ handle->idev = NULL;
+ }
+}
+
+
+/* Reset a reader on HANDLE. This is useful in case a reader has been
+ plugged of and inserted at a different port. By resetting the
+ handle, the same reader will be get used. Note, that on error the
+ handle won't get released.
+
+ This does not return an ATR, so ccid_get_atr should be called right
+ after this one.
+*/
+int
+ccid_shutdown_reader (ccid_driver_t handle)
+{
+ int rc = 0;
+ struct usb_device *dev = NULL;
+ usb_dev_handle *idev = NULL;
+ unsigned char *ifcdesc_extra = NULL;
+ size_t ifcdesc_extra_len;
+ int ifc_no, ep_bulk_out, ep_bulk_in, ep_intr;
+
+ if (!handle || !handle->rid)
+ return CCID_DRIVER_ERR_INV_VALUE;
+
+ do_close_reader (handle);
+
+ idev = scan_or_find_devices (-1, handle->rid, NULL, &dev,
+ &ifcdesc_extra, &ifcdesc_extra_len,
+ &ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr);
+ if (!idev)
+ {
+ DEBUGOUT_1 ("no CCID reader with ID %s\n", handle->rid);
+ return CCID_DRIVER_ERR_NO_READER;
+ }
+
+
+ handle->idev = idev;
+ handle->ifc_no = ifc_no;
+ handle->ep_bulk_out = ep_bulk_out;
+ handle->ep_bulk_in = ep_bulk_in;
+ handle->ep_intr = ep_intr;
+
+ if (parse_ccid_descriptor (handle, ifcdesc_extra, ifcdesc_extra_len))
+ {
+ DEBUGOUT ("device not supported\n");
+ rc = CCID_DRIVER_ERR_NO_READER;
+ goto leave;
+ }
+
+ rc = usb_claim_interface (idev, ifc_no);
+ if (rc)
+ {
+ DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc);
+ rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
+ goto leave;
+ }
+
+ leave:
+ free (ifcdesc_extra);
+ if (rc)
+ {
+ usb_close (handle->idev);
+ handle->idev = NULL;
+ }
+
+ return rc;
+
+}
+
+
+/* Close the reader HANDLE. */
+int
+ccid_close_reader (ccid_driver_t handle)
+{
+ if (!handle || !handle->idev)
+ return 0;
+
+ do_close_reader (handle);
+ free (handle->rid);
+ free (handle);
+ return 0;
+}
+
+
+/* Return False if a card is present and powered. */
+int
+ccid_check_card_presence (ccid_driver_t handle)
+{
+
+ return -1;
+}
+
+
+/* Write a MSG of length MSGLEN to the designated bulk out endpoint.
+ Returns 0 on success. */
+static int
+bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen)
+{
+ int rc;
+
+ rc = usb_bulk_write (handle->idev,
+ handle->ep_bulk_out,
+ (char*)msg, msglen,
+ 1000 /* ms timeout */);
+ if (rc == msglen)
+ return 0;
+
+ if (rc == -1)
+ DEBUGOUT_1 ("usb_bulk_write error: %s\n", strerror (errno));
+ else
+ DEBUGOUT_1 ("usb_bulk_write failed: %d\n", rc);
+ return CCID_DRIVER_ERR_CARD_IO_ERROR;
+}
+
+
+/* Read a maximum of LENGTH bytes from the bulk in endpoint into
+ BUFFER and return the actual read number if bytes in NREAD. SEQNO
+ is the sequence number used to send the request and EXPECTED_TYPE
+ the type of message we expect. Does checks on the ccid
+ header. TIMEOUT is the timeout value in ms. NO_DEBUG may be set to
+ avoid debug messages in case of no error. Returns 0 on success. */
+static int
+bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
+ size_t *nread, int expected_type, int seqno, int timeout,
+ int no_debug)
+{
+ int i, rc;
+ size_t msglen;
+
+ /* Fixme: The next line for the current Valgrind without support
+ for USB IOCTLs. */
+ memset (buffer, 0, length);
+ retry:
+ rc = usb_bulk_read (handle->idev,
+ handle->ep_bulk_in,
+ (char*)buffer, length,
+ timeout);
+ if (rc < 0)
+ {
+ DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno));
+ return CCID_DRIVER_ERR_CARD_IO_ERROR;
+ }
+
+ *nread = msglen = rc;
+
+ if (msglen < 10)
+ {
+ DEBUGOUT_1 ("bulk-in msg too short (%u)\n", (unsigned int)msglen);
+ return CCID_DRIVER_ERR_INV_VALUE;
+ }
+ if (buffer[0] != expected_type)
+ {
+ DEBUGOUT_1 ("unexpected bulk-in msg type (%02x)\n", buffer[0]);
+ return CCID_DRIVER_ERR_INV_VALUE;
+ }
+ if (buffer[5] != 0)
+ {
+ DEBUGOUT_1 ("unexpected bulk-in slot (%d)\n", buffer[5]);
+ return CCID_DRIVER_ERR_INV_VALUE;
+ }
+ if (buffer[6] != seqno)
+ {
+ DEBUGOUT_2 ("bulk-in seqno does not match (%d/%d)\n",
+ seqno, buffer[6]);
+ return CCID_DRIVER_ERR_INV_VALUE;
+ }
+
+ if ( !(buffer[7] & 0x03) && (buffer[7] & 0xC0) == 0x80)
+ {
+ /* Card present and active, time extension requested. */
+ DEBUGOUT_2 ("time extension requested (%02X,%02X)\n",
+ buffer[7], buffer[8]);
+ goto retry;
+ }
+
+ if (!no_debug)
+ {
+ DEBUGOUT_3 ("status: %02X error: %02X octet[9]: %02X\n"
+ " data:", buffer[7], buffer[8], buffer[9] );
+ for (i=10; i < msglen; i++)
+ DEBUGOUT_CONT_1 (" %02X", buffer[i]);
+ DEBUGOUT_LF ();
+ }
+ if (CCID_COMMAND_FAILED (buffer))
+ print_command_failed (buffer);
+
+ /* Check whether a card is at all available. Note: If you add new
+ error codes here, check whether they need to be ignored in
+ send_escape_cmd. */
+ switch ((buffer[7] & 0x03))
+ {
+ case 0: /* no error */ break;
+ case 1: return CCID_DRIVER_ERR_CARD_INACTIVE;
+ case 2: return CCID_DRIVER_ERR_NO_CARD;
+ case 3: /* RFU */ break;
+ }
+ return 0;
+}
+
+
+/* Note that this function won't return the error codes NO_CARD or
+ CARD_INACTIVE. IF RESULT is not NULL, the result from the
+ operation will get returned in RESULT and its length in RESULTLEN.
+ If the response is larger than RESULTMAX, an error is returned and
+ the required buffer length returned in RESULTLEN. */
+static int
+send_escape_cmd (ccid_driver_t handle,
+ const unsigned char *data, size_t datalen,
+ unsigned char *result, size_t resultmax, size_t *resultlen)
+{
+ int i, rc;
+ unsigned char msg[100];
+ size_t msglen;
+ unsigned char seqno;
+
+ if (resultlen)
+ *resultlen = 0;
+
+ if (datalen > sizeof msg - 10)
+ return CCID_DRIVER_ERR_INV_VALUE; /* Escape data too large. */
+
+ msg[0] = PC_to_RDR_Escape;
+ msg[5] = 0; /* slot */
+ msg[6] = seqno = handle->seqno++;
+ msg[7] = 0; /* RFU */
+ msg[8] = 0; /* RFU */
+ msg[9] = 0; /* RFU */
+ memcpy (msg+10, data, datalen);
+ msglen = 10 + datalen;
+ set_msg_len (msg, datalen);
+
+ DEBUGOUT ("sending");
+ for (i=0; i < msglen; i++)
+ DEBUGOUT_CONT_1 (" %02X", msg[i]);
+ DEBUGOUT_LF ();
+ rc = bulk_out (handle, msg, msglen);
+ if (rc)
+ return rc;
+ rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Escape,
+ seqno, 5000, 0);
+ if (result)
+ switch (rc)
+ {
+ /* We need to ignore certain errorcode here. */
+ case 0:
+ case CCID_DRIVER_ERR_CARD_INACTIVE:
+ case CCID_DRIVER_ERR_NO_CARD:
+ {
+ if (msglen < 10 || (msglen-10) > resultmax )
+ rc = CCID_DRIVER_ERR_INV_VALUE; /* Invalid length of response. */
+ else
+ {
+ memcpy (result, msg+10, msglen-10);
+ *resultlen = msglen-10;
+ }
+ rc = 0;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return rc;
+}
+
+
+int
+ccid_transceive_escape (ccid_driver_t handle,
+ const unsigned char *data, size_t datalen,
+ unsigned char *resp, size_t maxresplen, size_t *nresp)
+{
+ return send_escape_cmd (handle, data, datalen, resp, maxresplen, nresp);
+}
+
+
+
+/* experimental */
+int
+ccid_poll (ccid_driver_t handle)
+{
+ int rc;
+ unsigned char msg[10];
+ size_t msglen;
+ int i, j;
+
+ rc = usb_bulk_read (handle->idev,
+ handle->ep_intr,
+ (char*)msg, sizeof msg,
+ 0 /* ms timeout */ );
+ if (rc < 0 && errno == ETIMEDOUT)
+ return 0;
+
+ if (rc < 0)
+ {
+ DEBUGOUT_1 ("usb_intr_read error: %s\n", strerror (errno));
+ return CCID_DRIVER_ERR_CARD_IO_ERROR;
+ }
+
+ msglen = rc;
+ rc = 0;
+
+ if (msglen < 1)
+ {
+ DEBUGOUT ("intr-in msg too short\n");
+ return CCID_DRIVER_ERR_INV_VALUE;
+ }
+
+ if (msg[0] == RDR_to_PC_NotifySlotChange)
+ {
+ DEBUGOUT ("notify slot change:");
+ for (i=1; i < msglen; i++)
+ for (j=0; j < 4; j++)
+ DEBUGOUT_CONT_3 (" %d:%c%c",
+ (i-1)*4+j,
+ (msg[i] & (1<<(j*2)))? 'p':'-',
+ (msg[i] & (2<<(j*2)))? '*':' ');
+ DEBUGOUT_LF ();
+ }
+ else if (msg[0] == RDR_to_PC_HardwareError)
+ {
+ DEBUGOUT ("hardware error occured\n");
+ }
+ else
+ {
+ DEBUGOUT_1 ("unknown intr-in msg of type %02X\n", msg[0]);
+ }
+
+ return 0;
+}
+
+
+/* Note that this fucntion won't return the error codes NO_CARD or
+ CARD_INACTIVE */
+int
+ccid_slot_status (ccid_driver_t handle, int *statusbits)
+{
+ int rc;
+ unsigned char msg[100];
+ size_t msglen;
+ unsigned char seqno;
+ int retries = 0;
+
+ retry:
+ msg[0] = PC_to_RDR_GetSlotStatus;
+ msg[5] = 0; /* slot */
+ msg[6] = seqno = handle->seqno++;
+ msg[7] = 0; /* RFU */
+ msg[8] = 0; /* RFU */
+ msg[9] = 0; /* RFU */
+ set_msg_len (msg, 0);
+
+ rc = bulk_out (handle, msg, 10);
+ if (rc)
+ return rc;
+ /* Note that we set the NO_DEBUG flag here, so that the logs won't
+ get cluttered up by a ticker function checking for the slot
+ status and debugging enabled. */
+ rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus,
+ seqno, retries? 1000 : 200, 1);
+ if (rc == CCID_DRIVER_ERR_CARD_IO_ERROR && retries < 3)
+ {
+ if (!retries)
+ {
+ DEBUGOUT ("USB: CALLING USB_CLEAR_HALT\n");
+ usb_clear_halt (handle->idev, handle->ep_bulk_in);
+ usb_clear_halt (handle->idev, handle->ep_bulk_out);
+ }
+ else
+ DEBUGOUT ("USB: RETRYING bulk_in AGAIN\n");
+ retries++;
+ goto retry;
+ }
+ if (rc && rc != CCID_DRIVER_ERR_NO_CARD
+ && rc != CCID_DRIVER_ERR_CARD_INACTIVE)
+ return rc;
+ *statusbits = (msg[7] & 3);
+
+ return 0;
+}
+
+
+int
+ccid_get_atr (ccid_driver_t handle,
+ unsigned char *atr, size_t maxatrlen, size_t *atrlen)
+{
+ int rc;
+ int statusbits;
+ unsigned char msg[100];
+ unsigned char *tpdu;
+ size_t msglen, tpdulen;
+ unsigned char seqno;
+ int use_crc = 0;
+ unsigned int edc;
+ int i;
+ int tried_iso = 0;
+
+ /* First check whether a card is available. */
+ rc = ccid_slot_status (handle, &statusbits);
+ if (rc)
+ return rc;
+ if (statusbits == 2)
+ return CCID_DRIVER_ERR_NO_CARD;
+
+ /* For an inactive and also for an active card, issue the PowerOn
+ command to get the ATR. */
+ again:
+ msg[0] = PC_to_RDR_IccPowerOn;
+ msg[5] = 0; /* slot */
+ msg[6] = seqno = handle->seqno++;
+ msg[7] = 0; /* power select (0=auto, 1=5V, 2=3V, 3=1.8V) */
+ msg[8] = 0; /* RFU */
+ msg[9] = 0; /* RFU */
+ set_msg_len (msg, 0);
+ msglen = 10;
+
+ rc = bulk_out (handle, msg, msglen);
+ if (rc)
+ return rc;
+ rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_DataBlock,
+ seqno, 5000, 0);
+ if (rc)
+ return rc;
+ if (!tried_iso && CCID_COMMAND_FAILED (msg) && CCID_ERROR_CODE (msg) == 0xbb
+ && ((handle->id_vendor == VENDOR_CHERRY
+ && handle->id_product == 0x0005)
+ || (handle->id_vendor == VENDOR_GEMPC
+ && handle->id_product == 0x4433)
+ ))
+ {
+ tried_iso = 1;
+ /* Try switching to ISO mode. */
+ if (!send_escape_cmd (handle, (const unsigned char*)"\xF1\x01", 2,
+ NULL, 0, NULL))
+ goto again;
+ }
+ else if (CCID_COMMAND_FAILED (msg))
+ return CCID_DRIVER_ERR_CARD_IO_ERROR;
+
+
+ handle->powered_off = 0;
+
+ if (atr)
+ {
+ size_t n = msglen - 10;
+
+ if (n > maxatrlen)
+ n = maxatrlen;
+ memcpy (atr, msg+10, n);
+ *atrlen = n;
+ }
+
+ /* Setup parameters to select T=1. */
+ msg[0] = PC_to_RDR_SetParameters;
+ msg[5] = 0; /* slot */
+ msg[6] = seqno = handle->seqno++;
+ msg[7] = 1; /* Select T=1. */
+ msg[8] = 0; /* RFU */
+ msg[9] = 0; /* RFU */
+
+ /* FIXME: Get those values from the ATR. */
+ msg[10]= 0x01; /* Fi/Di */
+ msg[11]= 0x10; /* LRC, direct convention. */
+ msg[12]= 0; /* Extra guardtime. */
+ msg[13]= 0x41; /* BWI/CWI */
+ msg[14]= 0; /* No clock stoppping. */
+ msg[15]= 254; /* IFSC */
+ msg[16]= 0; /* Does not support non default NAD values. */
+ set_msg_len (msg, 7);
+ msglen = 10 + 7;
+
+ DEBUGOUT ("sending");
+ for (i=0; i < msglen; i++)
+ DEBUGOUT_CONT_1 (" %02X", msg[i]);
+ DEBUGOUT_LF ();
+
+ rc = bulk_out (handle, msg, msglen);
+ if (rc)
+ return rc;
+ /* Note that we ignore the error code on purpose. */
+ bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters,
+ seqno, 5000, 0);
+
+ handle->t1_ns = 0;
+ handle->t1_nr = 0;
+
+ /* Send an S-Block with our maximun IFSD to the CCID. */
+ if (!handle->auto_ifsd)
+ {
+ tpdu = msg+10;
+ /* NAD: DAD=1, SAD=0 */
+ tpdu[0] = handle->nonnull_nad? ((1 << 4) | 0): 0;
+ tpdu[1] = (0xc0 | 0 | 1); /* S-block request: change IFSD */
+ tpdu[2] = 1;
+ tpdu[3] = handle->max_ifsd? handle->max_ifsd : 32;
+ tpdulen = 4;
+ edc = compute_edc (tpdu, tpdulen, use_crc);
+ if (use_crc)
+ tpdu[tpdulen++] = (edc >> 8);
+ tpdu[tpdulen++] = edc;
+
+ msg[0] = PC_to_RDR_XfrBlock;
+ msg[5] = 0; /* slot */
+ msg[6] = seqno = handle->seqno++;
+ msg[7] = 0;
+ msg[8] = 0; /* RFU */
+ msg[9] = 0; /* RFU */
+ set_msg_len (msg, tpdulen);
+ msglen = 10 + tpdulen;
+
+ DEBUGOUT ("sending");
+ for (i=0; i < msglen; i++)
+ DEBUGOUT_CONT_1 (" %02X", msg[i]);
+ DEBUGOUT_LF ();
+
+ if (debug_level > 1)
+ DEBUGOUT_3 ("T=1: put %c-block seq=%d%s\n",
+ ((msg[11] & 0xc0) == 0x80)? 'R' :
+ (msg[11] & 0x80)? 'S' : 'I',
+ ((msg[11] & 0x80)? !!(msg[11]& 0x10)
+ : !!(msg[11] & 0x40)),
+ (!(msg[11] & 0x80) && (msg[11] & 0x20)? " [more]":""));
+
+ rc = bulk_out (handle, msg, msglen);
+ if (rc)
+ return rc;
+
+
+ rc = bulk_in (handle, msg, sizeof msg, &msglen,
+ RDR_to_PC_DataBlock, seqno, 5000, 0);
+ if (rc)
+ return rc;
+
+ tpdu = msg + 10;
+ tpdulen = msglen - 10;
+
+ if (tpdulen < 4)
+ return CCID_DRIVER_ERR_ABORTED;
+
+ if (debug_level > 1)
+ DEBUGOUT_4 ("T=1: got %c-block seq=%d err=%d%s\n",
+ ((msg[11] & 0xc0) == 0x80)? 'R' :
+ (msg[11] & 0x80)? 'S' : 'I',
+ ((msg[11] & 0x80)? !!(msg[11]& 0x10)
+ : !!(msg[11] & 0x40)),
+ ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0,
+ (!(msg[11] & 0x80) && (msg[11] & 0x20)? " [more]":""));
+
+ if ((tpdu[1] & 0xe0) != 0xe0 || tpdu[2] != 1)
+ {
+ DEBUGOUT ("invalid response for S-block (Change-IFSD)\n");
+ return -1;
+ }
+ DEBUGOUT_1 ("IFSD has been set to %d\n", tpdu[3]);
+ }
+
+ return 0;
+}
+
+
+
+
+static unsigned int
+compute_edc (const unsigned char *data, size_t datalen, int use_crc)
+{
+ if (use_crc)
+ {
+ return 0x42; /* Not yet implemented. */
+ }
+ else
+ {
+ unsigned char crc = 0;
+
+ for (; datalen; datalen--)
+ crc ^= *data++;
+ return crc;
+ }
+}
+
+
+/* Helper for ccid_transceive used for APDU level exchanges. */
+static int
+ccid_transceive_apdu_level (ccid_driver_t handle,
+ const unsigned char *apdu_buf, size_t apdu_buflen,
+ unsigned char *resp, size_t maxresplen,
+ size_t *nresp)
+{
+ int rc;
+ unsigned char send_buffer[10+259], recv_buffer[10+259];
+ const unsigned char *apdu;
+ size_t apdulen;
+ unsigned char *msg;
+ size_t msglen;
+ unsigned char seqno;
+ int i;
+
+ msg = send_buffer;
+
+ apdu = apdu_buf;
+ apdulen = apdu_buflen;
+ assert (apdulen);
+
+ if (apdulen > 254)
+ return CCID_DRIVER_ERR_INV_VALUE; /* Invalid length. */
+
+ msg[0] = PC_to_RDR_XfrBlock;
+ msg[5] = 0; /* slot */
+ msg[6] = seqno = handle->seqno++;
+ msg[7] = 4; /* bBWI */
+ msg[8] = 0; /* RFU */
+ msg[9] = 0; /* RFU */
+ memcpy (msg+10, apdu, apdulen);
+ set_msg_len (msg, apdulen);
+ msglen = 10 + apdulen;
+
+ DEBUGOUT ("sending");
+ for (i=0; i < msglen; i++)
+ DEBUGOUT_CONT_1 (" %02X", msg[i]);
+ DEBUGOUT_LF ();
+
+ rc = bulk_out (handle, msg, msglen);
+ if (rc)
+ return rc;
+
+ msg = recv_buffer;
+ rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
+ RDR_to_PC_DataBlock, seqno, 5000, 0);
+ if (rc)
+ return rc;
+
+ apdu = msg + 10;
+ apdulen = msglen - 10;
+
+ if (resp)
+ {
+ if (apdulen > maxresplen)
+ {
+ DEBUGOUT_2 ("provided buffer too short for received data "
+ "(%u/%u)\n",
+ (unsigned int)apdulen, (unsigned int)maxresplen);
+ return CCID_DRIVER_ERR_INV_VALUE;
+ }
+
+ memcpy (resp, apdu, apdulen);
+ *nresp = apdulen;
+ }
+
+ return 0;
+}
+
+
+
+/*
+ Protocol T=1 overview
+
+ Block Structure:
+ Prologue Field:
+ 1 byte Node Address (NAD)
+ 1 byte Protocol Control Byte (PCB)
+ 1 byte Length (LEN)
+ Information Field:
+ 0-254 byte APDU or Control Information (INF)
+ Epilogue Field:
+ 1 byte Error Detection Code (EDC)
+
+ NAD:
+ bit 7 unused
+ bit 4..6 Destination Node Address (DAD)
+ bit 3 unused
+ bit 2..0 Source Node Address (SAD)
+
+ If node adresses are not used, SAD and DAD should be set to 0 on
+ the first block sent to the card. If they are used they should
+ have different values (0 for one is okay); that first block sets up
+ the addresses of the nodes.
+
+ PCB:
+ Information Block (I-Block):
+ bit 7 0
+ bit 6 Sequence number (yep, that is modulo 2)
+ bit 5 Chaining flag
+ bit 4..0 reserved
+ Received-Ready Block (R-Block):
+ bit 7 1
+ bit 6 0
+ bit 5 0
+ bit 4 Sequence number
+ bit 3..0 0 = no error
+ 1 = EDC or parity error
+ 2 = other error
+ other values are reserved
+ Supervisory Block (S-Block):
+ bit 7 1
+ bit 6 1
+ bit 5 clear=request,set=response
+ bit 4..0 0 = resyncronisation request
+ 1 = information field size request
+ 2 = abort request
+ 3 = extension of BWT request
+ 4 = VPP error
+ other values are reserved
+
+*/
+
+int
+ccid_transceive (ccid_driver_t handle,
+ const unsigned char *apdu_buf, size_t apdu_buflen,
+ unsigned char *resp, size_t maxresplen, size_t *nresp)
+{
+ int rc;
+ unsigned char send_buffer[10+259], recv_buffer[10+259];
+ const unsigned char *apdu;
+ size_t apdulen;
+ unsigned char *msg, *tpdu, *p;
+ size_t msglen, tpdulen, last_tpdulen, n;
+ unsigned char seqno;
+ int i;
+ unsigned int edc;
+ int use_crc = 0;
+ size_t dummy_nresp;
+ int next_chunk = 1;
+ int sending = 1;
+ int retries = 0;
+
+ if (!nresp)
+ nresp = &dummy_nresp;
+ *nresp = 0;
+
+ /* Smarter readers allow to send APDUs directly; divert here. */
+ if (handle->apdu_level)
+ return ccid_transceive_apdu_level (handle, apdu_buf, apdu_buflen,
+ resp, maxresplen, nresp);
+
+ /* The other readers we support require sending TPDUs. */
+
+ tpdulen = 0; /* Avoid compiler warning about no initialization. */
+ msg = send_buffer;
+ for (;;)
+ {
+ if (next_chunk)
+ {
+ next_chunk = 0;
+
+ apdu = apdu_buf;
+ apdulen = apdu_buflen;
+ assert (apdulen);
+
+ /* Construct an I-Block. */
+ if (apdulen > 254)
+ return CCID_DRIVER_ERR_INV_VALUE; /* Invalid length. */
+
+ tpdu = msg+10;
+ /* NAD: DAD=1, SAD=0 */
+ tpdu[0] = handle->nonnull_nad? ((1 << 4) | 0): 0;
+ tpdu[1] = ((handle->t1_ns & 1) << 6); /* I-block */
+ if (apdulen > 128 /* fixme: replace by ifsc */)
+ {
+ apdulen = 128;
+ apdu_buf += 128;
+ apdu_buflen -= 128;
+ tpdu[1] |= (1 << 5); /* Set more bit. */
+ }
+ tpdu[2] = apdulen;
+ memcpy (tpdu+3, apdu, apdulen);
+ tpdulen = 3 + apdulen;
+ edc = compute_edc (tpdu, tpdulen, use_crc);
+ if (use_crc)
+ tpdu[tpdulen++] = (edc >> 8);
+ tpdu[tpdulen++] = edc;
+ }
+
+ msg[0] = PC_to_RDR_XfrBlock;
+ msg[5] = 0; /* slot */
+ msg[6] = seqno = handle->seqno++;
+ msg[7] = 4; /* bBWI */
+ msg[8] = 0; /* RFU */
+ msg[9] = 0; /* RFU */
+ set_msg_len (msg, tpdulen);
+ msglen = 10 + tpdulen;
+ last_tpdulen = tpdulen;
+
+ DEBUGOUT ("sending");
+ for (i=0; i < msglen; i++)
+ DEBUGOUT_CONT_1 (" %02X", msg[i]);
+ DEBUGOUT_LF ();
+
+ if (debug_level > 1)
+ DEBUGOUT_3 ("T=1: put %c-block seq=%d%s\n",
+ ((msg[11] & 0xc0) == 0x80)? 'R' :
+ (msg[11] & 0x80)? 'S' : 'I',
+ ((msg[11] & 0x80)? !!(msg[11]& 0x10)
+ : !!(msg[11] & 0x40)),
+ (!(msg[11] & 0x80) && (msg[11] & 0x20)? " [more]":""));
+
+ rc = bulk_out (handle, msg, msglen);
+ if (rc)
+ return rc;
+
+ msg = recv_buffer;
+ rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
+ RDR_to_PC_DataBlock, seqno, 5000, 0);
+ if (rc)
+ return rc;
+
+ tpdu = msg + 10;
+ tpdulen = msglen - 10;
+
+ if (tpdulen < 4)
+ {
+ usb_clear_halt (handle->idev, handle->ep_bulk_in);
+ return CCID_DRIVER_ERR_ABORTED;
+ }
+
+ if (debug_level > 1)
+ DEBUGOUT_4 ("T=1: got %c-block seq=%d err=%d%s\n",
+ ((msg[11] & 0xc0) == 0x80)? 'R' :
+ (msg[11] & 0x80)? 'S' : 'I',
+ ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)),
+ ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0,
+ (!(msg[11] & 0x80) && (msg[11] & 0x20)? " [more]":""));
+
+ if (!(tpdu[1] & 0x80))
+ { /* This is an I-block. */
+ retries = 0;
+ if (sending)
+ { /* last block sent was successful. */
+ handle->t1_ns ^= 1;
+ sending = 0;
+ }
+
+ if (!!(tpdu[1] & 0x40) != handle->t1_nr)
+ { /* Reponse does not match our sequence number. */
+ msg = send_buffer;
+ tpdu = msg+10;
+ /* NAD: DAD=1, SAD=0 */
+ tpdu[0] = handle->nonnull_nad? ((1 << 4) | 0): 0;
+ tpdu[1] = (0x80 | (handle->t1_nr & 1) << 4 | 2); /* R-block */
+ tpdu[2] = 0;
+ tpdulen = 3;
+ edc = compute_edc (tpdu, tpdulen, use_crc);
+ if (use_crc)
+ tpdu[tpdulen++] = (edc >> 8);
+ tpdu[tpdulen++] = edc;
+
+ continue;
+ }
+
+ handle->t1_nr ^= 1;
+
+ p = tpdu + 3; /* Skip the prologue field. */
+ n = tpdulen - 3 - 1; /* Strip the epilogue field. */
+ /* fixme: verify the checksum. */
+ if (resp)
+ {
+ if (n > maxresplen)
+ {
+ DEBUGOUT_2 ("provided buffer too short for received data "
+ "(%u/%u)\n",
+ (unsigned int)n, (unsigned int)maxresplen);
+ return CCID_DRIVER_ERR_INV_VALUE;
+ }
+
+ memcpy (resp, p, n);
+ resp += n;
+ *nresp += n;
+ maxresplen -= n;
+ }
+
+ if (!(tpdu[1] & 0x20))
+ return 0; /* No chaining requested - ready. */
+
+ msg = send_buffer;
+ tpdu = msg+10;
+ /* NAD: DAD=1, SAD=0 */
+ tpdu[0] = handle->nonnull_nad? ((1 << 4) | 0): 0;
+ tpdu[1] = (0x80 | (handle->t1_nr & 1) << 4); /* R-block */
+ tpdu[2] = 0;
+ tpdulen = 3;
+ edc = compute_edc (tpdu, tpdulen, use_crc);
+ if (use_crc)
+ tpdu[tpdulen++] = (edc >> 8);
+ tpdu[tpdulen++] = edc;
+ }
+ else if ((tpdu[1] & 0xc0) == 0x80)
+ { /* This is a R-block. */
+ if ( (tpdu[1] & 0x0f))
+ { /* Error: repeat last block */
+ if (++retries > 3)
+ {
+ DEBUGOUT ("3 failed retries\n");
+ return CCID_DRIVER_ERR_CARD_IO_ERROR;
+ }
+ msg = send_buffer;
+ tpdulen = last_tpdulen;
+ }
+ else if (sending && !!(tpdu[1] & 0x10) == handle->t1_ns)
+ { /* Response does not match our sequence number. */
+ DEBUGOUT ("R-block with wrong seqno received on more bit\n");
+ return CCID_DRIVER_ERR_CARD_IO_ERROR;
+ }
+ else if (sending)
+ { /* Send next chunk. */
+ retries = 0;
+ msg = send_buffer;
+ next_chunk = 1;
+ handle->t1_ns ^= 1;
+ }
+ else
+ {
+ DEBUGOUT ("unexpected ACK R-block received\n");
+ return CCID_DRIVER_ERR_CARD_IO_ERROR;
+ }
+ }
+ else
+ { /* This is a S-block. */
+ retries = 0;
+ DEBUGOUT_2 ("T=1 S-block %s received cmd=%d\n",
+ (tpdu[1] & 0x20)? "response": "request",
+ (tpdu[1] & 0x1f));
+ if ( !(tpdu[1] & 0x20) && (tpdu[1] & 0x1f) == 3 && tpdu[2])
+ { /* Wait time extension request. */
+ unsigned char bwi = tpdu[3];
+ msg = send_buffer;
+ tpdu = msg+10;
+ /* NAD: DAD=1, SAD=0 */
+ tpdu[0] = handle->nonnull_nad? ((1 << 4) | 0): 0;
+ tpdu[1] = (0xc0 | 0x20 | 3); /* S-block response */
+ tpdu[2] = 1;
+ tpdu[3] = bwi;
+ tpdulen = 4;
+ edc = compute_edc (tpdu, tpdulen, use_crc);
+ if (use_crc)
+ tpdu[tpdulen++] = (edc >> 8);
+ tpdu[tpdulen++] = edc;
+ DEBUGOUT_1 ("T=1 waittime extension of bwi=%d\n", bwi);
+ }
+ else
+ return CCID_DRIVER_ERR_CARD_IO_ERROR;
+ }
+ } /* end T=1 protocol loop. */
+
+ return 0;
+}
+
+
+/* Send the CCID Secure command to the reader. APDU_BUF should
+ contain the APDU template. PIN_MODE defines how the pin gets
+ formatted:
+
+ 1 := The PIN is ASCII encoded and of variable length. The
+ length of the PIN entered will be put into Lc by the reader.
+ The APDU should me made up of 4 bytes without Lc.
+
+ PINLEN_MIN and PINLEN_MAX define the limits for the pin length. 0
+ may be used t enable reasonable defaults. PIN_PADLEN should be 0.
+
+ When called with RESP and NRESP set to NULL, the function will
+ merely check whether the reader supports the secure command for the
+ given APDU and PIN_MODE. */
+int
+ccid_transceive_secure (ccid_driver_t handle,
+ const unsigned char *apdu_buf, size_t apdu_buflen,
+ int pin_mode, int pinlen_min, int pinlen_max,
+ int pin_padlen,
+ unsigned char *resp, size_t maxresplen, size_t *nresp)
+{
+ int rc;
+ unsigned char send_buffer[10+259], recv_buffer[10+259];
+ unsigned char *msg, *tpdu, *p;
+ size_t msglen, tpdulen, n;
+ unsigned char seqno;
+ int i;
+ size_t dummy_nresp;
+ int testmode;
+
+ testmode = !resp && !nresp;
+
+ if (!nresp)
+ nresp = &dummy_nresp;
+ *nresp = 0;
+
+ if (apdu_buflen >= 4 && apdu_buf[1] == 0x20 && (handle->has_pinpad & 1))
+ ;
+ else if (apdu_buflen >= 4 && apdu_buf[1] == 0x24 && (handle->has_pinpad & 2))
+ return CCID_DRIVER_ERR_NOT_SUPPORTED; /* Not yet by our code. */
+ else
+ return CCID_DRIVER_ERR_NO_KEYPAD;
+
+ if (pin_mode != 1)
+ return CCID_DRIVER_ERR_NOT_SUPPORTED;
+
+ if (pin_padlen != 0)
+ return CCID_DRIVER_ERR_NOT_SUPPORTED;
+
+ if (!pinlen_min)
+ pinlen_min = 1;
+ if (!pinlen_max)
+ pinlen_max = 25;
+
+ /* Note that the 25 is the maximum value the SPR532 allows. */
+ if (pinlen_min < 1 || pinlen_min > 25
+ || pinlen_max < 1 || pinlen_max > 25
+ || pinlen_min > pinlen_max)
+ return CCID_DRIVER_ERR_INV_VALUE;
+
+ /* We have only tested this with an SCM reader so better don't risk
+ anything and do not allow the use with other readers. */
+ if (handle->id_vendor != VENDOR_SCM)
+ return CCID_DRIVER_ERR_NOT_SUPPORTED;
+
+ if (testmode)
+ return 0; /* Success */
+
+ msg = send_buffer;
+ if (handle->id_vendor == VENDOR_SCM)
+ {
+ DEBUGOUT ("sending escape sequence to switch to a case 1 APDU\n");
+ rc = send_escape_cmd (handle, (const unsigned char*)"\x80\x02\x00", 3,
+ NULL, 0, NULL);
+ if (rc)
+ return rc;
+ }
+
+ msg[0] = PC_to_RDR_Secure;
+ msg[5] = 0; /* slot */
+ msg[6] = seqno = handle->seqno++;
+ msg[7] = 4; /* bBWI */
+ msg[8] = 0; /* RFU */
+ msg[9] = 0; /* RFU */
+ msg[10] = 0; /* Perform PIN verification. */
+ msg[11] = 0; /* Timeout in seconds. */
+ msg[12] = 0x82; /* bmFormatString: Byte, pos=0, left, ASCII. */
+ if (handle->id_vendor == VENDOR_SCM)
+ {
+ /* For the SPR532 the next 2 bytes need to be zero. We do this
+ for all SCM product. Kudos to Martin Paljak for this
+ hint. */
+ msg[13] = msg[14] = 0;
+ }
+ else
+ {
+ msg[13] = 0x00; /* bmPINBlockString:
+ 0 bits of pin length to insert.
+ 0 bytes of PIN block size. */
+ msg[14] = 0x00; /* bmPINLengthFormat:
+ Units are bytes, position is 0. */
+ }
+ msg[15] = pinlen_min; /* wPINMaxExtraDigit-Minimum. */
+ msg[16] = pinlen_max; /* wPINMaxExtraDigit-Maximum. */
+ msg[17] = 0x02; /* bEntryValidationCondition:
+ Validation key pressed */
+ if (pinlen_min && pinlen_max && pinlen_min == pinlen_max)
+ msg[17] |= 0x01; /* Max size reached. */
+ msg[18] = 0xff; /* bNumberMessage: Default. */
+ msg[19] = 0x04; /* wLangId-High. */
+ msg[20] = 0x09; /* wLangId-Low: English FIXME: use the first entry. */
+ msg[21] = 0; /* bMsgIndex. */
+ /* bTeoProlog follows: */
+ msg[22] = handle->nonnull_nad? ((1 << 4) | 0): 0;
+ msg[23] = ((handle->t1_ns & 1) << 6); /* I-block */
+ msg[24] = 4; /* apdulen. */
+ /* APDU follows: */
+ msg[25] = apdu_buf[0]; /* CLA */
+ msg[26] = apdu_buf[1]; /* INS */
+ msg[27] = apdu_buf[2]; /* P1 */
+ msg[28] = apdu_buf[3]; /* P2 */
+ msglen = 29;
+ set_msg_len (msg, msglen - 10);
+
+ DEBUGOUT ("sending");
+ for (i=0; i < msglen; i++)
+ DEBUGOUT_CONT_1 (" %02X", msg[i]);
+ DEBUGOUT_LF ();
+
+ rc = bulk_out (handle, msg, msglen);
+ if (rc)
+ return rc;
+
+ msg = recv_buffer;
+ rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
+ RDR_to_PC_DataBlock, seqno, 5000, 0);
+ if (rc)
+ return rc;
+
+ tpdu = msg + 10;
+ tpdulen = msglen - 10;
+
+ if (tpdulen < 4)
+ {
+ usb_clear_halt (handle->idev, handle->ep_bulk_in);
+ return CCID_DRIVER_ERR_ABORTED;
+ }
+ if (debug_level > 1)
+ DEBUGOUT_4 ("T=1: got %c-block seq=%d err=%d%s\n",
+ ((msg[11] & 0xc0) == 0x80)? 'R' :
+ (msg[11] & 0x80)? 'S' : 'I',
+ ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)),
+ ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0,
+ (!(msg[11] & 0x80) && (msg[11] & 0x20)? " [more]":""));
+
+ if (!(tpdu[1] & 0x80))
+ { /* This is an I-block. */
+ /* Last block sent was successful. */
+ handle->t1_ns ^= 1;
+
+ if (!!(tpdu[1] & 0x40) != handle->t1_nr)
+ { /* Reponse does not match our sequence number. */
+ DEBUGOUT ("I-block with wrong seqno received\n");
+ return CCID_DRIVER_ERR_CARD_IO_ERROR;
+ }
+
+ handle->t1_nr ^= 1;
+
+ p = tpdu + 3; /* Skip the prologue field. */
+ n = tpdulen - 3 - 1; /* Strip the epilogue field. */
+ /* fixme: verify the checksum. */
+ if (resp)
+ {
+ if (n > maxresplen)
+ {
+ DEBUGOUT_2 ("provided buffer too short for received data "
+ "(%u/%u)\n",
+ (unsigned int)n, (unsigned int)maxresplen);
+ return CCID_DRIVER_ERR_INV_VALUE;
+ }
+
+ memcpy (resp, p, n);
+ resp += n;
+ *nresp += n;
+ maxresplen -= n;
+ }
+
+ if (!(tpdu[1] & 0x20))
+ return 0; /* No chaining requested - ready. */
+
+ DEBUGOUT ("chaining requested but not supported for Secure operation\n");
+ return CCID_DRIVER_ERR_CARD_IO_ERROR;
+ }
+ else if ((tpdu[1] & 0xc0) == 0x80)
+ { /* This is a R-block. */
+ if ( (tpdu[1] & 0x0f))
+ { /* Error: repeat last block */
+ DEBUGOUT ("No retries supported for Secure operation\n");
+ return CCID_DRIVER_ERR_CARD_IO_ERROR;
+ }
+ else if (!!(tpdu[1] & 0x10) == handle->t1_ns)
+ { /* Reponse does not match our sequence number. */
+ DEBUGOUT ("R-block with wrong seqno received on more bit\n");
+ return CCID_DRIVER_ERR_CARD_IO_ERROR;
+ }
+ else
+ { /* Send next chunk. */
+ DEBUGOUT ("chaining not supported on Secure operation\n");
+ return CCID_DRIVER_ERR_CARD_IO_ERROR;
+ }
+ }
+ else
+ { /* This is a S-block. */
+ DEBUGOUT_2 ("T=1 S-block %s received cmd=%d for Secure operation\n",
+ (tpdu[1] & 0x20)? "response": "request",
+ (tpdu[1] & 0x1f));
+ return CCID_DRIVER_ERR_CARD_IO_ERROR;
+ }
+
+ return 0;
+}
+
+
+
+
+#ifdef TEST
+
+
+static void
+print_error (int err)
+{
+ const char *p;
+ char buf[50];
+
+ switch (err)
+ {
+ case 0: p = "success";
+ case CCID_DRIVER_ERR_OUT_OF_CORE: p = "out of core"; break;
+ case CCID_DRIVER_ERR_INV_VALUE: p = "invalid value"; break;
+ case CCID_DRIVER_ERR_NO_DRIVER: p = "no driver"; break;
+ case CCID_DRIVER_ERR_NOT_SUPPORTED: p = "not supported"; break;
+ case CCID_DRIVER_ERR_LOCKING_FAILED: p = "locking failed"; break;
+ case CCID_DRIVER_ERR_BUSY: p = "busy"; break;
+ case CCID_DRIVER_ERR_NO_CARD: p = "no card"; break;
+ case CCID_DRIVER_ERR_CARD_INACTIVE: p = "card inactive"; break;
+ case CCID_DRIVER_ERR_CARD_IO_ERROR: p = "card I/O error"; break;
+ case CCID_DRIVER_ERR_GENERAL_ERROR: p = "general error"; break;
+ case CCID_DRIVER_ERR_NO_READER: p = "no reader"; break;
+ case CCID_DRIVER_ERR_ABORTED: p = "aborted"; break;
+ default: sprintf (buf, "0x%05x", err); p = buf; break;
+ }
+ fprintf (stderr, "operation failed: %s\n", p);
+}
+
+static void
+print_data (const unsigned char *data, size_t length)
+{
+ if (length >= 2)
+ {
+ fprintf (stderr, "operation status: %02X%02X\n",
+ data[length-2], data[length-1]);
+ length -= 2;
+ }
+ if (length)
+ {
+ fputs (" returned data:", stderr);
+ for (; length; length--, data++)
+ fprintf (stderr, " %02X", *data);
+ putc ('\n', stderr);
+ }
+}
+
+static void
+print_result (int rc, const unsigned char *data, size_t length)
+{
+ if (rc)
+ print_error (rc);
+ else if (data)
+ print_data (data, length);
+}
+
+int
+main (int argc, char **argv)
+{
+ int rc;
+ ccid_driver_t ccid;
+ unsigned int slotstat;
+ unsigned char result[512];
+ size_t resultlen;
+ int no_pinpad = 0;
+ int verify_123456 = 0;
+ int did_verify = 0;
+ int no_poll = 0;
+
+ if (argc)
+ {
+ argc--;
+ argv++;
+ }
+
+ while (argc)
+ {
+ if ( !strcmp (*argv, "--list"))
+ {
+ char *p;
+ p = ccid_get_reader_list ();
+ if (!p)
+ return 1;
+ fputs (p, stderr);
+ free (p);
+ return 0;
+ }
+ else if ( !strcmp (*argv, "--debug"))
+ {
+ ccid_set_debug_level (1);
+ argc--; argv++;
+ }
+ else if ( !strcmp (*argv, "--no-poll"))
+ {
+ no_poll = 1;
+ argc--; argv++;
+ }
+ else if ( !strcmp (*argv, "--no-pinpad"))
+ {
+ no_pinpad = 1;
+ argc--; argv++;
+ }
+ else if ( !strcmp (*argv, "--verify-123456"))
+ {
+ verify_123456 = 1;
+ argc--; argv++;
+ }
+ else
+ break;
+ }
+
+ rc = ccid_open_reader (&ccid, argc? *argv:NULL);
+ if (rc)
+ return 1;
+
+ if (!no_poll)
+ ccid_poll (ccid);
+ fputs ("getting ATR ...\n", stderr);
+ rc = ccid_get_atr (ccid, NULL, 0, NULL);
+ if (rc)
+ {
+ print_error (rc);
+ return 1;
+ }
+
+ if (!no_poll)
+ ccid_poll (ccid);
+ fputs ("getting slot status ...\n", stderr);
+ rc = ccid_slot_status (ccid, &slotstat);
+ if (rc)
+ {
+ print_error (rc);
+ return 1;
+ }
+
+ if (!no_poll)
+ ccid_poll (ccid);
+
+ fputs ("selecting application OpenPGP ....\n", stderr);
+ {
+ static unsigned char apdu[] = {
+ 0, 0xA4, 4, 0, 6, 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01};
+ rc = ccid_transceive (ccid,
+ apdu, sizeof apdu,
+ result, sizeof result, &resultlen);
+ print_result (rc, result, resultlen);
+ }
+
+
+ if (!no_poll)
+ ccid_poll (ccid);
+
+ fputs ("getting OpenPGP DO 0x65 ....\n", stderr);
+ {
+ static unsigned char apdu[] = { 0, 0xCA, 0, 0x65, 254 };
+ rc = ccid_transceive (ccid, apdu, sizeof apdu,
+ result, sizeof result, &resultlen);
+ print_result (rc, result, resultlen);
+ }
+
+ if (!no_pinpad)
+ {
+ }
+
+ if (!no_pinpad)
+ {
+ static unsigned char apdu[] = { 0, 0x20, 0, 0x81 };
+
+
+ if (ccid_transceive_secure (ccid,
+ apdu, sizeof apdu,
+ 1, 0, 0, 0,
+ NULL, 0, NULL))
+ fputs ("can't verify using a PIN-Pad reader\n", stderr);
+ else
+ {
+ fputs ("verifying CHV1 using the PINPad ....\n", stderr);
+
+ rc = ccid_transceive_secure (ccid,
+ apdu, sizeof apdu,
+ 1, 0, 0, 0,
+ result, sizeof result, &resultlen);
+ print_result (rc, result, resultlen);
+ did_verify = 1;
+ }
+ }
+
+ if (verify_123456 && !did_verify)
+ {
+ fputs ("verifying that CHV1 is 123456....\n", stderr);
+ {
+ static unsigned char apdu[] = {0, 0x20, 0, 0x81,
+ 6, '1','2','3','4','5','6'};
+ rc = ccid_transceive (ccid, apdu, sizeof apdu,
+ result, sizeof result, &resultlen);
+ print_result (rc, result, resultlen);
+ }
+ }
+
+ if (!rc)
+ {
+ fputs ("getting OpenPGP DO 0x5E ....\n", stderr);
+ {
+ static unsigned char apdu[] = { 0, 0xCA, 0, 0x5E, 254 };
+ rc = ccid_transceive (ccid, apdu, sizeof apdu,
+ result, sizeof result, &resultlen);
+ print_result (rc, result, resultlen);
+ }
+ }
+
+ ccid_close_reader (ccid);
+
+ return 0;
+}
+
+/*
+ * Local Variables:
+ * compile-command: "gcc -DTEST -Wall -I/usr/local/include -lusb -g ccid-driver.c"
+ * End:
+ */
+#endif /*TEST*/
+#endif /*HAVE_LIBUSB*/
--- /dev/null
+/* ccid-driver.c - USB ChipCardInterfaceDevices driver
+ * Copyright (C) 2003 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ *
+ * ALTERNATIVELY, this file may be distributed under the terms of the
+ * following license, in which case the provisions of this license are
+ * required INSTEAD OF the GNU General Public License. If you wish to
+ * allow use of your version of this file only under the terms of the
+ * GNU General Public License, and not to allow others to use your
+ * version of this file under the terms of the following license,
+ * indicate your decision by deleting this paragraph and the license
+ * below.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: ccid-driver.h,v 1.1 2006-01-19 23:21:47 hackbard Exp $
+ */
+
+#ifndef CCID_DRIVER_H
+#define CCID_DRIVER_H
+
+/* The CID driver returns the same error codes as the status words
+ used by GnuPG's apdu.h. For ease of maintenance they should always
+ match. */
+#define CCID_DRIVER_ERR_OUT_OF_CORE 0x10001
+#define CCID_DRIVER_ERR_INV_VALUE 0x10002
+#define CCID_DRIVER_ERR_INCOMPLETE_CARD_RESPONSE = 0x10003
+#define CCID_DRIVER_ERR_NO_DRIVER 0x10004
+#define CCID_DRIVER_ERR_NOT_SUPPORTED 0x10005
+#define CCID_DRIVER_ERR_LOCKING_FAILED 0x10006
+#define CCID_DRIVER_ERR_BUSY 0x10007
+#define CCID_DRIVER_ERR_NO_CARD 0x10008
+#define CCID_DRIVER_ERR_CARD_INACTIVE 0x10009
+#define CCID_DRIVER_ERR_CARD_IO_ERROR 0x1000a
+#define CCID_DRIVER_ERR_GENERAL_ERROR 0x1000b
+#define CCID_DRIVER_ERR_NO_READER 0x1000c
+#define CCID_DRIVER_ERR_ABORTED 0x1000d
+#define CCID_DRIVER_ERR_NO_KEYPAD 0x1000e
+
+struct ccid_driver_s;
+typedef struct ccid_driver_s *ccid_driver_t;
+
+int ccid_set_debug_level (int level);
+char *ccid_get_reader_list (void);
+int ccid_open_reader (ccid_driver_t *handle, const char *readerid);
+int ccid_shutdown_reader (ccid_driver_t handle);
+int ccid_close_reader (ccid_driver_t handle);
+int ccid_get_atr (ccid_driver_t handle,
+ unsigned char *atr, size_t maxatrlen, size_t *atrlen);
+int ccid_slot_status (ccid_driver_t handle, int *statusbits);
+int ccid_transceive (ccid_driver_t handle,
+ const unsigned char *apdu, size_t apdulen,
+ unsigned char *resp, size_t maxresplen, size_t *nresp);
+int ccid_transceive_secure (ccid_driver_t handle,
+ const unsigned char *apdu, size_t apdulen,
+ int pin_mode,
+ int pinlen_min, int pinlen_max, int pin_padlen,
+ unsigned char *resp, size_t maxresplen, size_t *nresp);
+int ccid_transceive_escape (ccid_driver_t handle,
+ const unsigned char *data, size_t datalen,
+ unsigned char *resp, size_t maxresplen,
+ size_t *nresp);
+
+
+
+#endif /*CCID_DRIVER_H*/
+
+
+
--- /dev/null
+dnl Process this file with autoconf to create configure.
+
+AC_INIT
+
+AC_CANONICAL_SYSTEM
+
+AM_INIT_AUTOMAKE(librfid, 0.0.1)
+
+AC_PROG_CC
+AC_EXEEXT
+AM_PROG_LIBTOOL
+AC_SUBST(LIBTOOL_DEPS)
+
+dnl Output the makefile
+AC_OUTPUT(Makefile src/Makefile include/Makefile include/librfid/Makefile utils/Makefile)
--- /dev/null
+
+SUBDIRS = librfid
--- /dev/null
+
+pkginclude_HEADERS = rfid.h rfid_asic.h rfid_asic_rc632.h \
+ rfid_layer2.h rfid_layer2_iso14443a.h \
+ rfid_layer2_iso14443b.h rfid_layer2_iso15693.h \
+ rfid_protocol.h rfid_protocol_tcl.h \
+ rfid_protocol_mifare_ul.h \
+ rfid_protocol_mifare_classic.h \
+ rfid_reader.h \
+ rfid_reader_cm5121.h
+
--- /dev/null
+#ifndef _RFID_H
+#define _RFID_H
+
+#include <stdio.h>
+
+#ifdef __LIBRFID__
+
+enum rfid_frametype {
+ RFID_14443A_FRAME_REGULAR,
+ RFID_14443B_FRAME_REGULAR,
+ RFID_MIFARE_FRAME,
+};
+
+#if 0
+#define DEBUGP(x, args ...) fprintf(stderr, "%s(%d):%s: " x, __FILE__, __LINE__, __FUNCTION__, ## args)
+#define DEBUGPC(x, args ...) fprintf(stderr, x, ## args)
+#else
+#define DEBUGP(x, args ...)
+#define DEBUGPC(x, args ...)
+#endif
+
+extern const char *rfid_hexdump(const void *data, unsigned int len);
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+#endif /* __LIBRFID__ */
+
+int rfid_init();
+
+#endif /* _RFID_H */
--- /dev/null
+#ifndef _RFID_ASIC_H
+#define _RFID_ASIC_H
+
+enum rfid_frametype;
+
+#include <librfid/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 */
--- /dev/null
+#ifndef _RFID_ASIC_RC632_H
+#define _RFID_ASIC_RC632_H
+
+struct rfid_asic_transport_handle;
+
+#include <sys/types.h>
+#include <librfid/rfid_asic.h>
+
+struct rfid_asic_rc632_transport {
+ struct {
+ int (*reg_write)(struct rfid_asic_transport_handle *rath,
+ u_int8_t reg,
+ u_int8_t value);
+ int (*reg_read)(struct rfid_asic_transport_handle *rath,
+ u_int8_t reg,
+ u_int8_t *value);
+ int (*fifo_write)(struct rfid_asic_transport_handle *rath,
+ u_int8_t len,
+ const u_int8_t *buf,
+ u_int8_t flags);
+ int (*fifo_read)(struct rfid_asic_transport_handle *rath,
+ u_int8_t len,
+ u_int8_t *buf);
+ } fn;
+};
+
+struct rfid_asic_handle;
+
+struct iso14443a_atqa;
+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,
+ enum rfid_frametype,
+ const u_int32_t *tx_buf,
+ unsigned int tx_len,
+ u_int32_t *rx_buf,
+ unsigned int *rx_len,
+ u_int64_t timeout,
+ unsigned int flags);
+ struct {
+ int (*init)(struct rfid_asic_handle *h);
+ int (*transcieve_sf)(struct rfid_asic_handle *h,
+ u_int32_t cmd,
+ struct iso14443a_atqa *atqa);
+ int (*transcieve_acf)(struct rfid_asic_handle *h,
+ struct iso14443a_anticol_cmd *cmd,
+ unsigned int *bit_of_col);
+ int (*set_speed)(struct rfid_asic_handle *h,
+ unsigned int tx,
+ unsigned int speed);
+ } iso14443a;
+ struct {
+ int (*init)(struct rfid_asic_handle *h);
+ } iso14443b;
+ struct {
+ int (*init)(struct rfid_asic_handle *h);
+ } iso15693;
+ struct {
+ int (*setkey)(struct rfid_asic_handle *h,
+ const unsigned char *key);
+ int (*auth)(struct rfid_asic_handle *h, u_int8_t cmd,
+ u_int32_t serno, u_int8_t block);
+ } mifare_classic;
+ } fn;
+};
+
+struct rc632_transport_handle {
+};
+
+/* A handle to a specific RC632 chip */
+struct rfid_asic_rc632_handle {
+ struct rc632_transport_handle th;
+};
+
+#if 0
+int
+rc632_reg_write(struct rfid_asic_handle *handle,
+ u_int8_t reg,
+ u_int8_t val);
+
+int
+rc632_reg_read(struct rfid_asic_handle *handle,
+ u_int8_t reg,
+ u_int8_t *val);
+int
+rc632_fifo_write(struct rfid_asic_handle *handle,
+ u_int8_t len,
+ const u_int32_t *buf,
+ u_int8_t flags);
+
+int
+rc632_fifo_read(struct rfid_asic_handle *handle,
+ u_int8_t len,
+ u_int8_t *buf);
+
+int
+rc632_set_bits(struct rfid_asic_handle *handle, u_int8_t reg,
+ u_int82_t val);
+
+int
+rc632_clear_bits(struct rfid_asic_handle *handle, u_int32_t reg,
+ u_int32_t 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, u_int64_t time);
+
+int
+rc632_transmit(struct rfid_asic_handle *handle,
+ const u_int32_t *buf,
+ u_int32_t len,
+ u_int64_t timeout);
+
+int
+rc632_transcieve(struct rfid_asic_handle *handle,
+ const u_int32_t *tx_buf,
+ u_int32_t tx_len,
+ u_int32_t *rx_buf,
+ u_int32_t *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, u_int32_t *buf);
+
+
+struct rfid_asic_handle * rc632_open(struct rfid_asic_transport_handle *th);
+
+
+extern struct rfid_asic rc632;
+#endif
+
+#endif
--- /dev/null
+#ifndef _RFID_LAYER2_H
+#define _RFID_LAYER2_H
+
+#include <sys/types.h>
+#include <librfid/rfid.h>
+
+struct rfid_layer2_handle;
+struct rfid_reader_handle;
+
+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,
+ enum rfid_frametype frametype,
+ const unsigned char *tx_buf, unsigned int tx_len,
+ unsigned char *rx_buf, unsigned int *rx_len,
+ u_int64_t timeout, unsigned int flags);
+int rfid_layer2_close(struct rfid_layer2_handle *l2h);
+int rfid_layer2_fini(struct rfid_layer2_handle *l2h);
+int rfid_layer2_getopt(struct rfid_layer2_handle *ph, int optname,
+ void *optval, unsigned int *optlen);
+int rfid_layer2_setopt(struct rfid_layer2_handle *ph, int optname,
+ const void *optval, unsigned int optlen);
+
+#ifdef __LIBRFID__
+
+#include <librfid/rfid_layer2_iso14443a.h>
+#include <librfid/rfid_layer2_iso14443b.h>
+#include <librfid/rfid_layer2_iso15693.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,
+ enum rfid_frametype frametype,
+ const unsigned char *tx_buf,
+ unsigned int tx_len, unsigned char *rx_buf,
+ unsigned int *rx_len, u_int64_t timeout,
+ unsigned int flags);
+ int (*close)(struct rfid_layer2_handle *h);
+ int (*fini)(struct rfid_layer2_handle *h);
+ int (*getopt)(struct rfid_layer2_handle *h,
+ int optname, void *optval, unsigned int *optlen);
+ int (*setopt)(struct rfid_layer2_handle *h,
+ int optname, const void *optval,
+ unsigned int optlen);
+ } fn;
+ struct rfid_layer2 *next;
+};
+
+struct rfid_layer2_handle {
+ struct rfid_reader_handle *rh;
+ unsigned char uid[10]; /* triple size 14443a id is 10 bytes */
+ unsigned int uid_len;
+ union {
+ struct iso14443a_handle iso14443a;
+ struct iso14443b_handle iso14443b;
+ struct iso15693_handle iso15693;
+ } priv;
+ struct rfid_layer2 *l2;
+};
+
+#endif /* __LIBRFID__ */
+
+#endif
--- /dev/null
+#ifndef _RFID_ISO14443A_H
+#define _RFID_ISO14443A_H
+
+enum rfid_14443a_opt {
+ RFID_OPT_14443A_SPEED_RX = 0x00000001,
+ RFID_OPT_14443A_SPEED_TX = 0x00000002,
+};
+
+enum rfid_14443_opt_speed {
+ RFID_14443A_SPEED_106K = 0x01,
+ RFID_14443A_SPEED_212K = 0x02,
+ RFID_14443A_SPEED_424K = 0x04,
+ RFID_14443A_SPEED_848K = 0x08,
+};
+
+#ifdef __LIBRFID__
+
+#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 {
+ 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 <librfid/rfid_layer2.h>
+struct rfid_layer2 rfid_layer2_iso14443a;
+
+#endif /* __LIBRFID__ */
+
+
+#endif /* _ISO14443A_H */
--- /dev/null
+#ifndef _RFID_LAYER2_ISO14443B_H
+#define _RFID_LAYER2_ISO14443B_H
+
+#ifdef __LIBRFID__
+
+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 int cid; /* Card ID */
+
+ unsigned int fsc; /* max. frame size card */
+ unsigned int fsd; /* max. frame size reader */
+
+ unsigned int fwt; /* frame waiting time (in usec) */
+
+ 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 <librfid/rfid_layer2.h>
+struct rfid_layer2 rfid_layer2_iso14443b;
+
+#endif /* __LIBRFID__ */
+
+#endif
--- /dev/null
+#ifndef _RFID_ISO15693_H
+#define _RFID_ISO15693_H
+
+#include <sys/types.h>
+
+/*
+07h = TagIt
+04h = I.CODE
+05h = Infineon
+02h = ST
+*/
+
+/* protocol definitions */
+
+struct iso15693_handle;
+
+struct iso15693_transport {
+ unsigned char *name;
+
+ struct {
+ int (*init)(struct iso15693_handle *handle);
+ int (*fini)(struct iso15693_handle *handle);
+
+#if 0
+ 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);
+#endif
+ int (*transcieve)(struct iso15693_handle *handle,
+ const unsigned char *tx_buf,
+ unsigned int tx_len,
+ unsigned char *rx_buf,
+ unsigned int *rx_len);
+ } fn;
+
+ union {
+ } priv;
+};
+
+struct iso15693_handle {
+ unsigned int state;
+};
+
+enum iso15693_state {
+ ISO15693_STATE_ERROR,
+ ISO15693_STATE_NONE,
+};
+
+#include <librfid/rfid_layer2.h>
+extern struct rfid_layer2 rfid_layer2_iso15693;
+
+#endif /* _ISO15693_H */
--- /dev/null
+#ifndef _RFID_PROTOCOL_H
+#define _RFID_PROTOCOL_H
+
+#include <librfid/rfid_layer2.h>
+
+struct rfid_protocol_handle;
+
+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_read(struct rfid_protocol_handle *ph,
+ unsigned int page,
+ unsigned char *rx_data,
+ unsigned int *rx_len);
+
+int
+rfid_protocol_write(struct rfid_protocol_handle *ph,
+ unsigned int page,
+ unsigned char *tx_data,
+ unsigned int tx_len);
+
+int rfid_protocol_fini(struct rfid_protocol_handle *ph);
+int rfid_protocol_close(struct rfid_protocol_handle *ph);
+
+enum rfid_protocol_id {
+ RFID_PROTOCOL_UNKNOWN,
+ RFID_PROTOCOL_TCL,
+ RFID_PROTOCOL_MIFARE_UL,
+ RFID_PROTOCOL_MIFARE_CLASSIC,
+};
+
+
+#ifdef __LIBRFID__
+
+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);
+ /* transcieve for session based transport protocols */
+ 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);
+ /* read/write for synchronous memory cards */
+ int (*read)(struct rfid_protocol_handle *ph,
+ unsigned int page,
+ unsigned char *rx_data,
+ unsigned int *rx_len);
+ int (*write)(struct rfid_protocol_handle *ph,
+ unsigned int page,
+ unsigned char *tx_data,
+ unsigned int tx_len);
+ } fn;
+};
+
+int rfid_protocol_register(struct rfid_protocol *p);
+
+#include <librfid/rfid_protocol_tcl.h>
+#include <librfid/rfid_protocol_mifare_ul.h>
+#include <librfid/rfid_protocol_mifare_classic.h>
+
+struct rfid_protocol_handle {
+ struct rfid_layer2_handle *l2h;
+ struct rfid_protocol *proto;
+ union {
+ struct tcl_handle tcl;
+ } priv; /* priv has to be last, since
+ * it could contain additional
+ * private data over the end of
+ * sizeof(priv). */
+};
+
+#endif /* __LIBRFID__ */
+
+#endif /* _RFID_PROTOCOL_H */
--- /dev/null
+#ifndef _MIFARE_CLASSIC_H
+
+#define MIFARE_CL_KEYA_DEFAULT "\xa0\xa1\xa2\xa3\xa4\xa5"
+#define MIFARE_CL_KEYB_DEFAULT "\xb0\xb1\xb2\xb3\xb4\xb5"
+
+#define MIFARE_CL_KEYA_DEFAULT_INFINEON "\xff\xff\xff\xff\xff\xff"
+#define MIFARE_CL_KEYB_DEFAULT_INFINEON MIFARE_CL_KEYA_DEFAULT_INFINEON
+
+#define MIFARE_CL_PAGE_MAX 0xff
+
+#define RFID_CMD_MIFARE_AUTH1A 0x60
+#define RFID_CMD_MIFARE_AUTH1B 0x61
+
+#ifdef __LIBRFID__
+
+extern struct rfid_protocol rfid_protocol_mfcl;
+
+
+#define MIFARE_CL_CMD_WRITE16 0xA0
+#define MIFARE_CL_CMD_READ 0x30
+
+#define MIFARE_CL_RESP_ACK 0x0a
+#define MIFARE_CL_RESP_NAK 0x00
+
+
+#endif /* __LIBRFID__ */
+
+#endif /* _MIFARE_CLASSIC_H */
--- /dev/null
+#ifndef _RFID_PROTOCOL_MFUL_H
+#define _RFID_PROTOCOL_MFUL_H
+
+int rfid_mful_lock_page(struct rfid_protocol_handle *ph, unsigned int page);
+int rfid_mful_lock_otp(struct rfid_protocol_handle *ph);
+
+#define MIFARE_UL_PAGE_MAX 15
+
+#ifdef __LIBRFID__
+
+#define MIFARE_UL_CMD_WRITE 0xA2
+#define MIFARE_UL_CMD_READ 0x30
+
+#define MIFARE_UL_RESP_ACK 0x0a
+#define MIFARE_UL_RESP_NAK 0x00
+
+#define MIFARE_UL_PAGE_LOCK 2
+#define MIFARE_UL_PAGE_OTP 3
+
+extern struct rfid_protocol rfid_protocol_mful;
+
+#endif /* __LIBRFID__ */
+
+#endif
--- /dev/null
+#ifndef _RFID_PROTOCOL_TCL_H
+#define _RFID_PROTOCOL_TCL_H
+
+#ifdef __LIBRFID__
+
+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 (in usec)*/
+ unsigned char ta; /* divisor information */
+ unsigned char sfgt; /* start-up frame guard time (in usec) */
+
+ /* otherwise determined */
+ unsigned int cid; /* Card ID */
+ unsigned int nad; /* Node Address */
+
+ unsigned int flags;
+ unsigned int state; /* protocol state */
+
+ unsigned int toggle; /* send toggle with next frame */
+
+ 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 /* __LIBRFID__ */
+
+#endif
--- /dev/null
+#ifndef _RFID_READER_H
+#define _RFID_READER_H
+
+#include <librfid/rfid_asic.h>
+#include <librfid/rfid_layer2_iso14443a.h>
+
+struct rfid_reader_handle;
+
+struct rfid_reader {
+ char *name;
+ unsigned int id;
+ int (*transcieve)(struct rfid_reader_handle *h,
+ enum rfid_frametype frametype,
+ const unsigned char *tx_buf, unsigned int tx_len,
+ unsigned char *rx_buf, unsigned int *rx_len,
+ u_int64_t timeout, unsigned int flags);
+ struct rfid_reader_handle * (*open)(void *data);
+ void (*close)(struct rfid_reader_handle *h);
+
+ 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);
+ int (*set_speed)(struct rfid_reader_handle *h,
+ unsigned int tx,
+ unsigned int speed);
+ unsigned int speed;
+ } iso14443a;
+ struct rfid_14443b_reader {
+ int (*init)(struct rfid_reader_handle *rh);
+ unsigned int speed;
+ } iso14443b;
+ struct rfid_15693_reader {
+ int (*init)(struct rfid_reader_handle *rh);
+ } iso15693;
+ struct rfid_mifare_classic_reader {
+ int (*setkey)(struct rfid_reader_handle *h, unsigned char *key);
+ int (*auth)(struct rfid_reader_handle *h, u_int8_t cmd,
+ u_int32_t serno, u_int8_t block);
+ } mifare_classic;
+ 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;
+};
+
+
+extern struct rfid_reader_handle *
+rfid_reader_open(void *data, unsigned int id);
+
+extern void rfid_reader_close(struct rfid_reader_handle *rh);
+#endif
--- /dev/null
+#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
--- /dev/null
+
+all: pegoda
+
+pegoda: pegoda.o
+ $(CC) -lusb -o $@ $^
+
+clean:
+ rm -f pegoda *.o
--- /dev/null
+/*
+ * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <usb.h>
+#include "pegoda.h"
+
+const char *
+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;
+}
+
+struct pegoda_handle {
+ struct usb_dev_handle *handle;
+ unsigned char seq;
+ unsigned char snr[4];
+};
+
+
+struct usb_device *find_device(u_int16_t vendor, u_int16_t device)
+{
+ struct usb_bus *bus;
+
+ for (bus = usb_get_busses(); bus; bus = bus->next) {
+ struct usb_device *dev;
+ for (dev = bus->devices; dev; dev = dev->next) {
+ if (dev->descriptor.idVendor == vendor &&
+ dev->descriptor.idProduct == device) {
+ return dev;
+ }
+ }
+ }
+ return NULL;
+}
+
+int pegoda_transcieve(struct pegoda_handle *ph,
+ u_int8_t cmd, unsigned char *tx, unsigned int tx_len,
+ unsigned char *rx, unsigned int *rx_len)
+{
+ unsigned char txbuf[256];
+ unsigned char rxbuf[256];
+ int rc;
+ unsigned int len_expected;
+ struct pegoda_cmd_hdr *hdr = (struct pegoda_cmd_hdr *)txbuf;
+ struct pegoda_cmd_hdr *rxhdr = (struct pegoda_cmd_hdr *)rxbuf;
+
+ hdr->seq = ++(ph->seq);
+ hdr->cmd = cmd;
+ hdr->len = htons(tx_len);
+ memcpy(txbuf + sizeof(*hdr), tx, tx_len);
+
+ printf("tx [%u]: %s\n", tx_len+sizeof(*hdr),
+ hexdump(txbuf, tx_len + sizeof(*hdr)));
+ rc = usb_bulk_write(ph->handle, 0x02, (char *)txbuf,
+ tx_len + sizeof(*hdr), 0);
+ if (rc < 0)
+ return rc;
+
+ rc = usb_bulk_read(ph->handle, 0x81, (char *)rxbuf, sizeof(rxbuf), 0);
+ if (rc <= 0)
+ return rc;
+
+ if (rc != 2) {
+ fprintf(stderr, "unexpected: received %u bytes as length?\n");
+ return -EIO;
+ }
+ printf("len [%u]: %s\n", rc, hexdump(rxbuf, rc));
+
+ len_expected = rxbuf[0];
+
+ if (len_expected > sizeof(rxbuf))
+ return -EIO;
+
+ rc = usb_bulk_read(ph->handle, 0x81, (char *)rxbuf, len_expected, 0);
+ if (rc <= 0)
+ return rc;
+ printf("rx [%u]: %s\n", rc, hexdump(rxbuf, rc));
+
+ if (rc < 4)
+ return -EIO;
+
+ if (rxhdr->seq != hdr->seq)
+ return -EIO;
+
+ *rx_len = ntohs(rxhdr->len);
+
+ memcpy(rx, rxbuf+sizeof(*rxhdr), rc-sizeof(*rxhdr));
+
+ return 0;
+}
+
+struct pegoda_handle *pegoda_open(void)
+{
+ struct usb_device *pegoda;
+ unsigned char rbuf[16];
+ unsigned int rlen = sizeof(rbuf);
+ struct pegoda_handle *ph;
+
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+
+ pegoda = find_device(USB_VENDOR_PHILIPS, USB_DEVICE_PEGODA);
+
+ if (!pegoda)
+ return NULL;
+
+ ph = malloc(sizeof(*ph));
+ if (!ph)
+ return NULL;
+ memset(ph, 0, sizeof(*ph));
+
+ printf("found pegoda, %u configurations\n",
+ pegoda->descriptor.bNumConfigurations);
+
+ printf("config 2 [nr %u] has %u interfaces\n",
+ pegoda->config[1].bConfigurationValue,
+ pegoda->config[1].bNumInterfaces);
+
+ printf("config 2 interface 0 has %u altsettings\n",
+ pegoda->config[1].interface[0].num_altsetting);
+
+ ph->handle = usb_open(pegoda);
+ if (!ph->handle)
+ goto out_free;
+
+ if (usb_set_configuration(ph->handle, 2))
+ goto out_free;
+
+ printf("configuration 2 successfully set\n");
+
+ if (usb_claim_interface(ph->handle, 0))
+ goto out_free;
+
+ printf("interface 0 claimed\n");
+
+ if (usb_set_altinterface(ph->handle, 1))
+ goto out_free;
+
+ printf("alt setting 1 selected\n");
+
+ pegoda_transcieve(ph, PEGODA_CMD_PCD_CONFIG, NULL, 0, rbuf, &rlen);
+
+ return ph;
+out_free:
+ free(ph);
+ return NULL;
+}
+
+/* Transform crypto1 key from generic 6byte into rc632 specific 12byte */
+static int
+mifare_transform_key(const u_int8_t *key6, u_int8_t *key12)
+{
+ int i;
+ u_int8_t ln;
+ u_int8_t hn;
+
+ for (i = 0; i < 6; i++) {
+ ln = key6[i] & 0x0f;
+ hn = key6[i] >> 4;
+ key12[i * 2 + 1] = (~ln << 4) | ln;
+ key12[i * 2] = (~hn << 4) | hn;
+ }
+ return 0;
+}
+
+static int pegoda_auth_e2(struct pegoda_handle *ph,
+ u_int8_t keynr, u_int8_t sector)
+{
+ unsigned char buf[3];
+ unsigned char rbuf[16];
+ unsigned int rlen = sizeof(rbuf);
+
+ buf[0] = 0x60;
+ buf[1] = keynr; /* key number */
+ buf[2] = sector; /* sector */
+ rlen = sizeof(rbuf);
+ pegoda_transcieve(ph, PEGODA_CMD_PICC_AUTH, buf, 3, rbuf, &rlen);
+
+ /* FIXME: check response */
+
+ return 0;
+}
+
+static int pegoda_auth_key(struct pegoda_handle *ph,
+ u_int8_t sector, const unsigned char *key6)
+{
+ unsigned char buf[1+4+12+1];
+ unsigned char rbuf[16];
+ unsigned int rlen = sizeof(rbuf);
+
+ buf[0] = 0x60;
+ memcpy(buf+1, ph->snr, 4);
+ mifare_transform_key(key6, buf+5);
+ buf[17] = sector;
+
+ pegoda_transcieve(ph, PEGODA_CMD_PICC_AUTH_KEY, buf, 18, rbuf, &rlen);
+
+ /* FIXME: check response */
+
+ return 0;
+}
+
+static int pegoda_read16(struct pegoda_handle *ph,
+ u_int8_t page, unsigned char *rx)
+{
+ int rc;
+ unsigned int rlen = 16;
+
+ rc = pegoda_transcieve(ph, PEGODA_CMD_PICC_READ,
+ &page, 1, rx, &rlen);
+ if (rlen != 16)
+ return -EIO;
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ unsigned char buf[256];
+ unsigned char rbuf[256];
+ unsigned int rlen = sizeof(rbuf);
+ struct pegoda_handle *ph;
+
+ ph = pegoda_open();
+ if (!ph)
+ exit(1);
+
+ /* LED off */
+ buf[0] = 0x00;
+ rlen = sizeof(rbuf);
+ pegoda_transcieve(ph, PEGODA_CMD_SWITCH_LED, buf, 1, rbuf, &rlen);
+
+ /* anticollision */
+
+ buf[0] = 0x26;
+ rlen = sizeof(rbuf);
+ pegoda_transcieve(ph, PEGODA_CMD_PICC_COMMON_REQUEST,
+ buf, 1, rbuf, &rlen);
+
+ buf[0] = 0x93;
+ memset(buf+1, 0, 5);
+ rlen = sizeof(rbuf);
+ pegoda_transcieve(ph, PEGODA_CMD_PICC_CASC_ANTICOLL,
+ buf, 6, rbuf, &rlen);
+
+ memcpy(ph->snr, rbuf, 4);
+
+ buf[0] = 0x93;
+ memcpy(buf+1, ph->snr, 4);
+ rlen = sizeof(rbuf);
+ pegoda_transcieve(ph, PEGODA_CMD_PICC_CASC_SELECT,
+ buf, 5, rbuf, &rlen);
+
+ pegoda_auth_key(ph, 0, "\xff\xff\xff\xff\xff\xff");
+ pegoda_read16(ph, 0, rbuf);
+ printf("read16 = %s\n", hexdump(rbuf, 16));
+
+ exit(0);
+}
--- /dev/null
+#ifndef _PEGODA_H
+#define _PEGODA_H
+/*
+ * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define USB_VENDOR_PHILIPS 0x0742
+#define USB_DEVICE_PEGODA 0xff01
+
+/* header of a pegoda usb command packet */
+struct pegoda_cmd_hdr {
+ u_int8_t seq;
+ u_int8_t cmd;
+ u_int16_t len;
+};
+
+enum {
+ PEGODA_CMD_WRITE_RC = 0x01,
+ PEGODA_CMD_READ_RC = 0x02,
+ PEGODA_CMD_EXCHANGE_BYTESTREAM = 0x03,
+ PEGODA_CMD_WRITE_MULTIPLE = 0x04,
+ PEGODA_CMD_READ_MULTIPLE = 0x05,
+ PEGODA_CMD_READ_WORD = 0x06,
+
+
+ PEGODA_CMD_PCD_CONFIG = 0x10,
+ PEGODA_CMD_PICC_REQUEST = 0x11,
+ PEGODA_CMD_PICC_ANTICOLL = 0x12,
+ PEGODA_CMD_PICC_SELECT = 0x13,
+ PEGODA_CMD_PICC_AUTH = 0x14,
+ PEGODA_CMD_PICC_AUTH_E2 = 0x15,
+ PEGODA_CMD_LOAD_KEY_E2 = 0x17,
+ PEGODA_CMD_PICC_AUTH_KEY = 0x18,
+ PEGODA_CMD_PICC_READ = 0x19,
+ PEGODA_CMD_PICC_WRITE = 0x1a,
+ PEGODA_CMD_PICC_VALUE = 0x1b,
+ PEGODA_CMD_PICC_VALUE_DEBIT = 0x1c,
+ PEGODA_CMD_PICC_HALT = 0x1d,
+ PEGODA_CMD_PICC_WRITE4 = 0x1e,
+ PEGODA_CMD_PICC_COMMON_WRITE = 0x1f,
+
+ PEGODA_CMD_PCD_RF_RESET = 0x20,
+ PEGODA_CMD_PCD_RESET = 0x21,
+ PEGODA_CMD_PCD_GET_SNR = 0x22,
+ PEGODA_CMD_PCD_READ_E2 = 0x23,
+ PEGODA_CMD_PCD_SET_TMO = 0x27,
+ PEGODA_CMD_PICC_COMMON_READ = 0x28,
+ PEGODA_CMD_PCD_INITIALIZE_E2 = 0x29,
+ PEGODA_CMD_ACTIVE_ANTENNA_MASTER = 0x2a,
+ PEGODA_CMD_ACTIVE_ANTENNA_SLAVE = 0x2b,
+
+ PEGODA_CMD_HOST_TRANS_TMR_START = 0x30,
+ PEGODA_CMD_HOST_TRANS_TMR_STOP = 0x31,
+ PEGODA_CMD_HOST_GET_EXEC_TIME = 0x32,
+
+ PEGODA_CMD_PICC_COMMON_REQUEST = 0x40,
+ PEGODA_CMD_PICC_CASC_ANTICOLL = 0x41,
+ PEGODA_CMD_PICC_CASC_SELECT = 0x42,
+ PEGODA_CMD_PICC_ACTIVATE_IDLE = 0x43,
+ PEGODA_CMD_PICC_ACTIVATE_WAKEUP = 0x44,
+ PEGODA_CMD_PCD_SET_DEFAULT_ATTRIB = 0x45,
+ PEGODA_CMD_PCD_SET_ATTRIB = 0x46,
+ PEGODA_CMD_PCD_GET_ATTRIB = 0x47,
+ PEGODA_CMD_PICC_EXCHANGE_BLOCK = 0x48,
+ PEGODA_CMD_PICC_ACTIVATE_IDLE_LOOP = 0x49,
+ PEGODA_CMD_PICC_ACTTIVATION = 0x4a,
+ PEGODA_CMD_PCD_ENABLE_HIGH_BAUD_RATES = 0x4b,
+
+ PEGODA_CMD_SWITCH_LED = 0x60,
+ PEGODA_CMD_TEST_FLASH_NR = 0x61,
+ PEGODA_CMD_START_DOWNLOAD = 0x62,
+ PEGODA_CMD_GET_FW_VERSION = 0x63,
+ PEGODA_CMD_GET_RIC_VERSION = 0x64,
+ PEGODA_CMD_ENABLE_DEBUG_PINS = 0x65,
+ PEGODA_CMD_MIRROR_DATA = 0x66,
+ PEGODA_CMD_TEST_CMDS = 0x67,
+
+ PEGODA_CMD_TEST_PCD = 0x70,
+ PEGODA_CMD_TEST_PICC = 0x71,
+ PEGODA_CMD_GET_ONLINE_STATUS = 0x72,
+
+ PEGODA_CMD_I1_PCD_CONFIG = 0x80,
+ PEGODA_CMD_I1_INIT_STD_MODE = 0x81,
+ PEGODA_CMD_I1_CALC_TSE_HASH = 0x82,
+ PEGODA_CMD_I1_INIT_FAST_MODE = 0x83,
+ PEGODA_CMD_I1_OUTPUT_READ = 0x85,
+ PEGODA_CMD_I1_OUTPUT_ANTICOL_SELECT = 0x86,
+ PEGODA_CMD_I1_OUTPUT_WRITE = 0x87,
+ PEGODA_CMD_I1_OUTPUT_HALT = 0x88,
+ PEGODA_CMD_I1_OUTPUT_EAS = 0x89,
+ PEGODA_CMD_I1_RESET_QUIET = 0x8a,
+ PEGODA_CMD_I1_PCD_RF_RESET = 0x8b,
+ PEGODA_CMD_I1_SET_BIT_PHASE = 0x8c,
+
+ PEGODA_CMD_I2_INIT_STD_MODE = 0x90,
+ PEGODA_CMD_I2_INIT_FAST_MODE = 0x91,
+ PEGODA_CMD_15693_READ_SM = 0x92,
+ PEGODA_CMD_15693_INVENTORY = 0x93,
+ PEGODA_CMD_15693_WRITE_SM = 0x94,
+ PEGODA_CMD_15693_STAY_QUIET = 0x95,
+ PEGODA_CMD_15693_LOCK_BLOCK = 0x96,
+ PEGODA_CMD_15693_SELECT = 0x97,
+ PEGODA_CMD_15693_RESET_TO_READY = 0x98,
+ PEGODA_CMD_15693_WRITE_AFI = 0x99,
+ PEGODA_CMD_15693_LOCK_AFI = 0x9a,
+ PEGODA_CMD_15693_WRITE_DSFID = 0x9b,
+ PEGODA_CMD_15693_LOCK_DSFID = 0x9c,
+ PEGODA_CMD_15693_GET_SYSTEM_INFO = 0x9d,
+ PEGODA_CMD_15693_GET_MULTI_BLOCK_SEC = 0x9e,
+ PEGODA_CMD_15693_INVENTORY_READ = 0x9f,
+ PEGODA_CMD_15693_FAST_INVENTORY_READ = 0xa0,
+ PEGODA_CMD_15693_SET_EAS = 0xa1,
+ PEGODA_CMD_15693_RESET_EAS = 0xa2,
+ PEGODA_CMD_15693_LOCK_EAS = 0xa3,
+ PEGODA_CMD_15693_EAS_ALARM = 0xa4,
+
+ PEGODA_CMD_PC_PCD_CONFIG = 0xb0,
+ PEGODA_CMD_PC_BEGIN_ROUND = 0xb1,
+ PEGODA_CMD_PC_WRITE = 0xb3,
+
+ PEGODA_CMD_UID_PCD_CONFIG = 0xb8,
+ PEGODA_CMD_UID_BEGIN_ROUND = 0xb9,
+ PEGODA_CMD_UID_WRITE = 0xba,
+ PEGODA_CMD_UID_DESTROY = 0xbb,
+};
+
+#endif
--- /dev/null
+LIBVERSION= 0:0:0
+INCLUDES = $(all_includes) -I$(top_srcdir)/include -D__LIBRFID__
+
+lib_LTLIBRARIES = librfid.la
+
+CORE=rfid.c rfid_layer2.c rfid_protocol.c rfid_reader.c
+L2=rfid_layer2_iso14443a.c rfid_layer2_iso14443b.c rfid_layer2_iso15693.c rfid_iso14443_common.c
+PROTO=rfid_proto_tcl.c rfid_proto_mifare_ul.c rfid_proto_mifare_classic.c
+READER=rfid_reader_cm5121.c rfid_reader_cm5121_openct.c rfid_asic_rc632.c
+
+librfid_la_LDFLAGS = -Wc,-nostartfiles -version-info $(LIBVERSION) -lopenct
+librfid_la_SOURCES = $(CORE) $(L2) $(PROTO) $(READER)
+
--- /dev/null
+/* 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,
+
+#define RC632_CDRCTRL_RATE_MASK 0x38
+ RC632_CDRCTRL_RATE_848K = 0x00,
+ RC632_CDRCTRL_RATE_424K = 0x08,
+ 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,
+
+#define RC632_RXCTRL1_SUBCP_MASK 0xe0
+ 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,
+};
+
+
--- /dev/null
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <stdio.h>
+#include <string.h>
+
+#include <librfid/rfid_reader_cm5121.h>
+#include <librfid/rfid_protocol.h>
+#include <librfid/rfid_protocol_tcl.h>
+#include <librfid/rfid_protocol_mifare_ul.h>
+#include <librfid/rfid_protocol_mifare_classic.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);
+ rfid_protocol_register(&rfid_protocol_mful);
+ rfid_protocol_register(&rfid_protocol_mfcl);
+
+ return 0;
+}
+
+void rfid_fini()
+{
+ /* FIXME: implementation */
+}
--- /dev/null
+/* Generic Philips CL RC632 Routines
+ *
+ * (C) Harald Welte <laforge@gnumonks.org>
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include <librfid/rfid.h>
+#include <librfid/rfid_asic.h>
+#include <librfid/rfid_asic_rc632.h>
+#include <librfid/rfid_reader_cm5121.h>
+#include <librfid/rfid_layer2_iso14443a.h>
+#include <librfid/rfid_protocol_mifare_classic.h>
+
+#include "rfid_iso14443_common.h"
+#include "rc632.h"
+//#include "rc632_14443a.h"
+
+
+#define RC632_TMO_AUTH1 14000
+
+#define ENTER() DEBUGP("entering\n")
+struct rfid_asic rc632;
+
+/* Register and FIFO Access functions */
+static int
+rc632_reg_write(struct rfid_asic_handle *handle,
+ u_int8_t reg,
+ u_int8_t val)
+{
+ return handle->rath->rat->priv.rc632.fn.reg_write(handle->rath, reg, val);
+}
+
+static int
+rc632_reg_read(struct rfid_asic_handle *handle,
+ u_int8_t reg,
+ u_int8_t *val)
+{
+ return handle->rath->rat->priv.rc632.fn.reg_read(handle->rath, reg, val);
+}
+
+static int
+rc632_fifo_write(struct rfid_asic_handle *handle,
+ u_int8_t len,
+ const u_int8_t *buf,
+ u_int8_t flags)
+{
+ return handle->rath->rat->priv.rc632.fn.fifo_write(handle->rath,
+ len, buf, flags);
+}
+
+static int
+rc632_fifo_read(struct rfid_asic_handle *handle,
+ u_int8_t len,
+ u_int8_t *buf)
+{
+ return handle->rath->rat->priv.rc632.fn.fifo_read(handle->rath, len, buf);
+}
+
+
+static int
+rc632_set_bits(struct rfid_asic_handle *handle,
+ u_int8_t reg,
+ u_int8_t val)
+{
+ int ret;
+ u_int8_t tmp;
+
+ ret = rc632_reg_read(handle, reg, &tmp);
+ if (ret < 0)
+ return -1;
+
+ /* if bits are already set, no need to set them again */
+ if ((tmp & val) == val)
+ return 0;
+
+ return rc632_reg_write(handle, reg, (tmp|val)&0xff);
+}
+static int
+rc632_set_bit_mask(struct rfid_asic_handle *handle,
+ u_int8_t reg, u_int8_t mask, u_int8_t val)
+{
+ int ret;
+ u_int8_t tmp;
+
+ ret = rc632_reg_read(handle, reg, &tmp);
+ if (ret < 0)
+ return ret;
+
+ /* if bits are already like we want them, abort */
+ if ((tmp & mask) == val)
+ return 0;
+
+ return rc632_reg_write(handle, reg, (tmp & ~mask)|(val & mask));
+}
+
+static int
+rc632_clear_bits(struct rfid_asic_handle *handle,
+ u_int8_t reg,
+ u_int8_t val)
+{
+ int ret;
+ u_int8_t tmp;
+
+ ret = rc632_reg_read(handle, reg, &tmp);
+ if (ret < 0) {
+ DEBUGP("error during reg_read(%p, %d):%d\n",
+ handle, reg, ret);
+ return -1;
+ }
+ /* if bits are already cleared, no need to clear them again */
+ if ((tmp & val) == 0)
+ return 0;
+
+ return rc632_reg_write(handle, reg, (tmp & ~val)&0xff);
+}
+
+static int
+rc632_turn_on_rf(struct rfid_asic_handle *handle)
+{
+ ENTER();
+ return rc632_set_bits(handle, RC632_REG_TX_CONTROL, 0x03);
+}
+
+static int
+rc632_turn_off_rf(struct rfid_asic_handle *handle)
+{
+ ENTER();
+ return rc632_clear_bits(handle, RC632_REG_TX_CONTROL, 0x03);
+}
+
+static int
+rc632_power_up(struct rfid_asic_handle *handle)
+{
+ ENTER();
+ return rc632_clear_bits(handle, RC632_REG_CONTROL,
+ RC632_CONTROL_POWERDOWN);
+}
+
+static int
+rc632_power_down(struct rfid_asic_handle *handle)
+{
+ return rc632_set_bits(handle, RC632_REG_CONTROL,
+ RC632_CONTROL_POWERDOWN);
+}
+
+/* Stupid RC623 implementations don't evaluate interrupts but poll the
+ * command register for "status idle" */
+static int
+rc632_wait_idle(struct rfid_asic_handle *handle, u_int64_t timeout)
+{
+ u_int8_t cmd = 0xff;
+ int ret;
+
+ while (cmd != 0) {
+ ret = rc632_reg_read(handle, RC632_REG_COMMAND, &cmd);
+ if (ret < 0)
+ return ret;
+
+ if (cmd == 0) {
+ /* FIXME: read second time ?? */
+ return 0;
+ }
+
+ {
+ u_int8_t foo;
+ rc632_reg_read(handle, RC632_REG_PRIMARY_STATUS, &foo);
+ if (foo & 0x04)
+ rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &foo);
+ }
+
+ usleep(100);
+
+ /* Fixme: Abort after some timeout */
+ }
+
+ return 0;
+}
+
+static int
+rc632_transmit(struct rfid_asic_handle *handle,
+ const u_int8_t *buf,
+ u_int8_t len,
+ u_int64_t timeout)
+{
+ int ret;
+
+ ret = rc632_fifo_write(handle, len, buf, 0x03);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(handle, RC632_REG_COMMAND, RC632_CMD_TRANSMIT);
+ if (ret < 0)
+ return ret;
+
+ return rc632_wait_idle(handle, timeout);
+}
+
+static int
+tcl_toggle_pcb(struct rfid_asic_handle *handle)
+{
+ // FIXME: toggle something between 0x0a and 0x0b
+ return 0;
+}
+
+static int
+rc632_transcieve(struct rfid_asic_handle *handle,
+ const u_int8_t *tx_buf,
+ u_int8_t tx_len,
+ u_int8_t *rx_buf,
+ u_int8_t *rx_len,
+ unsigned int timer,
+ unsigned int toggle)
+{
+ int ret;
+
+ ret = rc632_fifo_write(handle, tx_len, tx_buf, 0x03);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(handle, RC632_REG_COMMAND, RC632_CMD_TRANSCIEVE);
+ if (ret < 0)
+ return ret;
+
+ if (toggle == 1)
+ tcl_toggle_pcb(handle);
+
+ ret = rc632_wait_idle(handle, timer);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_read(handle, RC632_REG_FIFO_LENGTH, rx_len);
+ if (ret < 0)
+ return ret;
+
+ if (*rx_len == 0) {
+ u_int8_t tmp;
+
+ DEBUGP("rx_len == 0\n");
+
+ rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &tmp);
+ rc632_reg_read(handle, RC632_REG_CHANNEL_REDUNDANCY, &tmp);
+
+ return -1;
+ }
+
+ return rc632_fifo_read(handle, *rx_len, rx_buf);
+}
+
+static int
+rc632_read_eeprom(struct rfid_asic_handle *handle)
+{
+ u_int8_t recvbuf[60];
+ u_int8_t sndbuf[3];
+ int ret;
+
+ sndbuf[0] = 0x00;
+ sndbuf[1] = 0x00;
+ sndbuf[2] = 0x3c;
+
+ ret = rc632_fifo_write(handle, 3, sndbuf, 0x03);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(handle, RC632_REG_COMMAND, RC632_CMD_READ_E2);
+ if (ret < 0)
+ return ret;
+
+ usleep(20000);
+
+ ret = rc632_fifo_read(handle, sizeof(recvbuf), recvbuf);
+ if (ret < 0)
+ return ret;
+
+ // FIXME: do something with eeprom contents
+ return ret;
+}
+
+static int
+rc632_calc_crc16_from(struct rfid_asic_handle *handle)
+{
+ u_int8_t sndbuf[2] = { 0x01, 0x02 };
+ u_int8_t crc_lsb = 0x00 , crc_msb = 0x00;
+ int ret;
+
+ ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_LSB, 0x12);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_MSB, 0xe0);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_fifo_write(handle, sizeof(sndbuf), sndbuf, 3);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(handle, RC632_REG_COMMAND, RC632_CMD_CALC_CRC);
+ if (ret < 0)
+ return ret;
+
+ usleep(10000); // FIXME: no checking for cmd completion?
+
+ ret = rc632_reg_read(handle, RC632_REG_CRC_RESULT_LSB, &crc_lsb);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_read(handle, RC632_REG_CRC_RESULT_MSB, &crc_msb);
+ if (ret < 0)
+ return ret;
+
+ // FIXME: what to do with crc result?
+ return ret;
+}
+
+
+int
+rc632_register_dump(struct rfid_asic_handle *handle, u_int8_t *buf)
+{
+ int ret;
+ u_int8_t i;
+
+ for (i = 0; i <= 0x3f; i++) {
+ ret = rc632_reg_read(handle, i, &buf[i]);
+ // do we want error checks?
+ }
+ return 0;
+}
+
+
+
+/* generic FIFO access functions (if no more efficient ones provided by
+ * transport driver) */
+
+static int
+generic_fifo_write()
+{
+ // FIXME: implementation (not needed for CM 5121)
+ return -1;
+}
+
+static int
+generic_fifo_read()
+{
+ // FIXME: implementation (not neded for CM 5121)
+ return -1;
+}
+
+static int
+rc632_init(struct rfid_asic_handle *ah)
+{
+ int ret;
+
+ /* switch off rf (make sure PICCs are reset at init time) */
+ ret = rc632_power_down(ah);
+ if (ret < 0)
+ return ret;
+
+ usleep(10000);
+
+ /* switch on rf */
+ ret = rc632_power_up(ah);
+ if (ret < 0)
+ return ret;
+
+ /* disable register paging */
+ ret = rc632_reg_write(ah, 0x00, 0x00);
+ if (ret < 0)
+ return ret;
+
+ /* set some sane default values */
+ ret = rc632_reg_write(ah, 0x11, 0x5b);
+ if (ret < 0)
+ return ret;
+
+ /* switch on rf */
+ ret = rc632_turn_on_rf(ah);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int
+rc632_fini(struct rfid_asic_handle *ah)
+{
+ int ret;
+
+ /* switch off rf */
+ ret = rc632_turn_off_rf(ah);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_power_down(ah);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+struct rfid_asic_handle *
+rc632_open(struct rfid_asic_transport_handle *th)
+{
+ struct rfid_asic_handle *h;
+
+ h = malloc(sizeof(*h));
+ if (!h)
+ return NULL;
+ memset(h, 0, sizeof(*h));
+
+ h->asic = &rc632;
+ h->rath = th;
+ h->fc = h->asic->fc;
+ h->mtu = h->mru = 40; /* FIXME */
+
+ if (rc632_init(h) < 0) {
+ free(h);
+ return NULL;
+ }
+
+ return h;
+}
+
+void
+rc632_close(struct rfid_asic_handle *h)
+{
+ rc632_fini(h);
+ free(h);
+}
+
+
+/*
+ * Philips CL RC632 primitives for ISO 14443-A compliant PICC's
+ *
+ * (C) 2005 by Harald Welte <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;
+
+ /* Since FORCE_100_ASK is set (cf mc073930.pdf), this line may be left out? */
+ ret = rc632_reg_write(handle, RC632_REG_MOD_CONDUCTANCE,
+ CM5121_MOD_CONDUCTANCE);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(handle, RC632_REG_CODER_CONTROL,
+ (RC632_CDRCTRL_TXCD_14443A |
+ RC632_CDRCTRL_RATE_106K));
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(handle, RC632_REG_MOD_WIDTH, 0x13);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(handle, RC632_REG_MOD_WIDTH_SOF, 0x3f);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(handle, RC632_REG_TYPE_B_FRAMING, 0x00);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(handle, RC632_REG_RX_CONTROL1,
+ (RC632_RXCTRL1_GAIN_35DB |
+ RC632_RXCTRL1_ISO14443 |
+ RC632_RXCTRL1_SUBCP_8));
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(handle, RC632_REG_DECODER_CONTROL,
+ (RC632_DECCTRL_MANCHESTER |
+ RC632_DECCTRL_RXFR_14443A));
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(handle, RC632_REG_BIT_PHASE,
+ CM5121_14443A_BITPHASE);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(handle, RC632_REG_RX_THRESHOLD,
+ CM5121_14443A_THRESHOLD);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(handle, RC632_REG_BPSK_DEM_CONTROL, 0x00);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(handle, RC632_REG_RX_CONTROL2,
+ (RC632_RXCTRL2_DECSRC_INT |
+ RC632_RXCTRL2_CLK_Q));
+ if (ret < 0)
+ return ret;
+
+ /* Omnikey proprietary driver has 0x03, but 0x06 is the default reset value ?!? */
+ ret = rc632_reg_write(handle, RC632_REG_RX_WAIT, 0x06);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY,
+ (RC632_CR_PARITY_ENABLE |
+ RC632_CR_PARITY_ODD));
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_LSB, 0x63);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(handle, RC632_REG_CRC_PRESET_MSB, 0x63);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int
+rc632_iso14443a_fini(struct iso14443a_handle *handle_14443)
+{
+
+#if 0
+ ret = rc632_turn_off_rf(handle);
+ if (ret < 0)
+ return ret;
+#endif
+
+
+ return 0;
+}
+
+
+/* issue a 14443-3 A PCD -> PICC command in a short frame, such as REQA, WUPA */
+static int
+rc632_iso14443a_transcieve_sf(struct rfid_asic_handle *handle,
+ u_int8_t cmd,
+ struct iso14443a_atqa *atqa)
+{
+ int ret;
+ u_int8_t tx_buf[1];
+ u_int8_t rx_len = 2;
+
+ memset(atqa, 0, sizeof(atqa));
+
+ tx_buf[0] = cmd;
+
+ /* transfer only 7 bits of last byte in frame */
+ ret = rc632_reg_write(handle, RC632_REG_BIT_FRAMING, 0x07);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_clear_bits(handle, RC632_REG_CONTROL,
+ RC632_CONTROL_CRYPTO1_ON);
+ if (ret < 0)
+ return ret;
+
+#if 0
+ ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY,
+ (RC632_CR_PARITY_ENABLE |
+ RC632_CR_PARITY_ODD));
+#else
+ ret = rc632_clear_bits(handle, RC632_REG_CHANNEL_REDUNDANCY,
+ RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE);
+
+#endif
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_transcieve(handle, tx_buf, sizeof(tx_buf),
+ (u_int8_t *)atqa, &rx_len, 0x32, 0);
+ if (ret < 0) {
+ DEBUGP("error during rc632_transcieve()\n");
+ return ret;
+ }
+
+ /* switch back to normal 8bit last byte */
+ ret = rc632_reg_write(handle, RC632_REG_BIT_FRAMING, 0x00);
+ if (ret < 0)
+ return ret;
+
+ if (rx_len != 2) {
+ DEBUGP("rx_len(%d) != 2\n", rx_len);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* transcieve regular frame */
+static int
+rc632_iso14443ab_transcieve(struct rfid_asic_handle *handle,
+ unsigned int frametype,
+ const u_int8_t *tx_buf, unsigned int tx_len,
+ u_int8_t *rx_buf, unsigned int *rx_len,
+ u_int64_t timeout, unsigned int flags)
+{
+ int ret;
+ u_int8_t rxl = *rx_len & 0xff;
+ u_int8_t channel_red;
+
+ memset(rx_buf, 0, *rx_len);
+
+ switch (frametype) {
+ case RFID_14443A_FRAME_REGULAR:
+ case RFID_MIFARE_FRAME:
+ channel_red = RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE
+ |RC632_CR_PARITY_ENABLE|RC632_CR_PARITY_ODD;
+ break;
+ case RFID_14443B_FRAME_REGULAR:
+ channel_red = RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE
+ |RC632_CR_CRC3309;
+ break;
+#if 0
+ case RFID_MIFARE_FRAME:
+ channel_red = RC632_CR_PARITY_ENABLE|RC632_CR_PARITY_ODD;
+ break;
+#endif
+ default:
+ return -EINVAL;
+ break;
+ }
+ ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY,
+ channel_red);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_transcieve(handle, tx_buf, tx_len, rx_buf, &rxl, 0x32, 0);
+ *rx_len = rxl;
+ if (ret < 0)
+ return ret;
+
+
+ return 0;
+}
+
+/* transcieve anti collission bitframe */
+static int
+rc632_iso14443a_transcieve_acf(struct rfid_asic_handle *handle,
+ struct iso14443a_anticol_cmd *acf,
+ unsigned int *bit_of_col)
+{
+ int ret;
+ u_int8_t rx_buf[64];
+ u_int8_t rx_len = sizeof(rx_buf);
+ u_int8_t rx_align = 0, tx_last_bits, tx_bytes;
+ u_int8_t boc;
+ u_int8_t error_flag;
+ *bit_of_col = ISO14443A_BITOFCOL_NONE;
+ memset(rx_buf, 0, sizeof(rx_buf));
+
+ /* disable mifare cryto */
+ ret = rc632_clear_bits(handle, RC632_REG_CONTROL,
+ RC632_CONTROL_CRYPTO1_ON);
+ if (ret < 0)
+ return ret;
+
+ /* disable CRC summing */
+#if 0
+ ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY,
+ (RC632_CR_PARITY_ENABLE |
+ RC632_CR_PARITY_ODD));
+#else
+ ret = rc632_clear_bits(handle, RC632_REG_CHANNEL_REDUNDANCY,
+ RC632_CR_TX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE);
+#endif
+ if (ret < 0)
+ return ret;
+
+ tx_last_bits = acf->nvb & 0x0f; /* lower nibble indicates bits */
+ tx_bytes = acf->nvb >> 4;
+ if (tx_last_bits) {
+ tx_bytes++;
+ rx_align = (tx_last_bits+1) % 8;/* rx frame complements tx */
+ }
+
+ //rx_align = 8 - tx_last_bits;/* rx frame complements tx */
+
+ /* set RxAlign and TxLastBits*/
+ ret = rc632_reg_write(handle, RC632_REG_BIT_FRAMING,
+ (rx_align << 4) | (tx_last_bits));
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_transcieve(handle, (u_int8_t *)acf, tx_bytes,
+ rx_buf, &rx_len, 0x32, 0);
+ if (ret < 0)
+ return ret;
+
+ /* bitwise-OR the two halves of the split byte */
+ acf->uid_bits[tx_bytes-2] = (
+ (acf->uid_bits[tx_bytes-2] & (0xff >> (8-tx_last_bits)))
+ | rx_buf[0]);
+ /* copy the rest */
+ memcpy(&acf->uid_bits[tx_bytes+1-2], &rx_buf[1], rx_len-1);
+
+ /* determine whether there was a collission */
+ ret = rc632_reg_read(handle, RC632_REG_ERROR_FLAG, &error_flag);
+ if (ret < 0)
+ return ret;
+
+ if (error_flag & RC632_ERR_FLAG_COL_ERR) {
+ /* retrieve bit of collission */
+ ret = rc632_reg_read(handle, RC632_REG_COLL_POS, &boc);
+ if (ret < 0)
+ return ret;
+
+ /* bit of collission relative to start of part 1 of
+ * anticollision frame (!) */
+ *bit_of_col = 2*8 + boc;
+ }
+
+ return 0;
+}
+
+enum rc632_rate {
+ RC632_RATE_106 = 0x00,
+ RC632_RATE_212 = 0x01,
+ RC632_RATE_424 = 0x02,
+ RC632_RATE_848 = 0x03,
+};
+
+struct rx_config {
+ u_int8_t subc_pulses;
+ u_int8_t rx_coding;
+ u_int8_t rx_threshold;
+ u_int8_t bpsk_dem_ctrl;
+};
+
+struct tx_config {
+ u_int8_t rate;
+ u_int8_t mod_width;
+};
+
+static struct rx_config rx_configs[] = {
+ {
+ .subc_pulses = RC632_RXCTRL1_SUBCP_8,
+ .rx_coding = RC632_DECCTRL_MANCHESTER,
+ .rx_threshold = 0x88,
+ .bpsk_dem_ctrl = 0x00,
+ },
+ {
+ .subc_pulses = RC632_RXCTRL1_SUBCP_4,
+ .rx_coding = RC632_DECCTRL_BPSK,
+ .rx_threshold = 0x50,
+ .bpsk_dem_ctrl = 0x0c,
+ },
+ {
+ .subc_pulses = RC632_RXCTRL1_SUBCP_2,
+ .rx_coding = RC632_DECCTRL_BPSK,
+ .rx_threshold = 0x50,
+ .bpsk_dem_ctrl = 0x0c,
+ },
+ {
+ .subc_pulses = RC632_RXCTRL1_SUBCP_1,
+ .rx_coding = RC632_DECCTRL_BPSK,
+ .rx_threshold = 0x50,
+ .bpsk_dem_ctrl = 0x0c,
+ },
+};
+
+static struct tx_config tx_configs[] = {
+ {
+ .rate = RC632_CDRCTRL_RATE_106K,
+ .mod_width = 0x13,
+ },
+ {
+ .rate = RC632_CDRCTRL_RATE_212K,
+ .mod_width = 0x07,
+ },
+ {
+ .rate = RC632_CDRCTRL_RATE_424K,
+ .mod_width = 0x03,
+ },
+ {
+ .rate = RC632_CDRCTRL_RATE_848K,
+ .mod_width = 0x01,
+ },
+};
+
+static int rc632_iso14443a_set_speed(struct rfid_asic_handle *handle,
+ unsigned int tx,
+ u_int8_t rate)
+{
+ int rc;
+ u_int8_t reg;
+
+
+ if (!tx) {
+ /* Rx */
+ if (rate > ARRAY_SIZE(rx_configs))
+ return -EINVAL;
+
+ rc = rc632_set_bit_mask(handle, RC632_REG_RX_CONTROL1,
+ RC632_RXCTRL1_SUBCP_MASK,
+ rx_configs[rate].subc_pulses);
+ if (rc < 0)
+ return rc;
+
+ rc = rc632_set_bit_mask(handle, RC632_REG_DECODER_CONTROL,
+ RC632_DECCTRL_BPSK,
+ rx_configs[rate].rx_coding);
+ if (rc < 0)
+ return rc;
+
+ rc = rc632_reg_write(handle, RC632_REG_RX_THRESHOLD,
+ rx_configs[rate].rx_threshold);
+ if (rc < 0)
+ return rc;
+
+ if (rx_configs[rate].rx_coding == RC632_DECCTRL_BPSK) {
+ rc = rc632_reg_write(handle,
+ RC632_REG_BPSK_DEM_CONTROL,
+ rx_configs[rate].bpsk_dem_ctrl);
+ if (rc < 0)
+ return rc;
+ }
+ } else {
+ /* Tx */
+ if (rate > ARRAY_SIZE(tx_configs))
+ return -EINVAL;
+
+ rc = rc632_set_bit_mask(handle, RC632_REG_CODER_CONTROL,
+ RC632_CDRCTRL_RATE_MASK,
+ tx_configs[rate].rate);
+ if (rc < 0)
+ return rc;
+
+ rc = rc632_reg_write(handle, RC632_REG_MOD_WIDTH,
+ tx_configs[rate].mod_width);
+ if (rc < 0)
+ return rc;
+ }
+
+ 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;
+}
+
+static int
+rc632_iso15693_init(struct rfid_asic_handle *h)
+{
+ int ret;
+
+ ret = rc632_reg_write(h, RC632_REG_TX_CONTROL,
+ (RC632_TXCTRL_MOD_SRC_INT |
+ RC632_TXCTRL_TX2_INV |
+ RC632_TXCTRL_TX2_RF_EN |
+ RC632_TXCTRL_TX1_RF_EN));
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CW_CONDUCTANCE, 0x3f);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_MOD_CONDUCTANCE, 0x03);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CODER_CONTROL,
+ (RC632_CDRCTRL_RATE_15693 |
+ 0x03)); /* FIXME */
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_MOD_WIDTH, 0x3f);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_MOD_WIDTH_SOF, 0x3f);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_TYPE_B_FRAMING, 0x00);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_RX_CONTROL1,
+ (RC632_RXCTRL1_SUBCP_16 |
+ RC632_RXCTRL1_ISO15693 |
+ RC632_RXCTRL1_GAIN_35DB));
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_DECODER_CONTROL,
+ (RC632_DECCTRL_RXFR_15693 |
+ RC632_DECCTRL_RX_INVERT));
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_BIT_PHASE, 0xe0);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_RX_THRESHOLD, 0xff);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_BPSK_DEM_CONTROL, 0x00);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_RX_CONTROL2,
+ (RC632_RXCTRL2_AUTO_PD |
+ RC632_RXCTRL2_DECSRC_INT));
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CHANNEL_REDUNDANCY,
+ (RC632_CR_CRC3309 |
+ RC632_CR_RX_CRC_ENABLE |
+ RC632_CR_TX_CRC_ENABLE));
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CRC_PRESET_LSB, 0xff);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CRC_PRESET_MSB, 0xff);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int
+rc632_iso15693_icode_init(struct rfid_asic_handle *h)
+{
+ int ret;
+
+ ret = rc632_reg_write(h, RC632_REG_TX_CONTROL,
+ (RC632_TXCTRL_MOD_SRC_INT |
+ RC632_TXCTRL_TX2_INV |
+ RC632_TXCTRL_TX2_RF_EN |
+ RC632_TXCTRL_TX1_RF_EN));
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CW_CONDUCTANCE, 0x3f);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_MOD_CONDUCTANCE, 0x02);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CODER_CONTROL, 0x2c);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_MOD_WIDTH, 0x3f);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_MOD_WIDTH_SOF, 0x3f);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_MOD_WIDTH_SOF, 0x3f);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_TYPE_B_FRAMING, 0x00);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_RX_CONTROL1, 0x8b); /* FIXME */
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_DECODER_CONTROL, 0x00);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_BIT_PHASE, 0x52);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_RX_THRESHOLD, 0x66);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_BPSK_DEM_CONTROL, 0x00);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_RX_CONTROL2,
+ RC632_RXCTRL2_DECSRC_INT);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CHANNEL_REDUNDANCY,
+ (RC632_CR_RX_CRC_ENABLE |
+ RC632_CR_TX_CRC_ENABLE));
+ ret = rc632_reg_write(h, RC632_REG_CRC_PRESET_LSB, 0xfe);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CRC_PRESET_MSB, 0xff);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int
+rc632_iso15693_icl_init(struct rfid_asic_handle *h)
+{
+ int ret;
+
+ /* ICL */
+
+ ret = rc632_reg_write(h, RC632_REG_TX_CONTROL,
+ (RC632_TXCTRL_MOD_SRC_INT |
+ RC632_TXCTRL_TX2_INV |
+ RC632_TXCTRL_TX2_RF_EN |
+ RC632_TXCTRL_TX1_RF_EN));
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CW_CONDUCTANCE, 0x3f);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_MOD_CONDUCTANCE, 0x11);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CODER_CONTROL,
+ (RC632_CDRCTRL_RATE_15693 |
+ RC632_CDRCTRL_TXCD_ICODE_STD |
+ 0x03)); /* FIXME */
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_MOD_WIDTH, 0x3f);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_MOD_WIDTH_SOF, 0x3f);
+ if (ret < 0)
+ return ret;
+ ret = rc632_reg_write(h, RC632_REG_RX_CONTROL1,
+ (RC632_RXCTRL1_SUBCP_16|
+ RC632_RXCTRL1_ISO15693|
+ RC632_RXCTRL1_GAIN_35DB));
+ if (ret < 0)
+ return ret;
+ ret = rc632_reg_write(h, RC632_REG_DECODER_CONTROL,
+ (RC632_DECCTRL_RX_INVERT|
+ RC632_DECCTRL_RXFR_15693));
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_BIT_PHASE, 0xbd);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_RX_THRESHOLD, 0xff);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_BPSK_DEM_CONTROL, 0x00);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_RX_CONTROL2,
+ RC632_RXCTRL2_DECSRC_INT);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CHANNEL_REDUNDANCY, 0x00);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CRC_PRESET_LSB, 0x12);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_CRC_PRESET_MSB, 0xe0);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+struct mifare_authcmd {
+ u_int8_t auth_cmd;
+ u_int8_t block_address;
+ u_int32_t serno; /* lsb 1 2 msb */
+} __attribute__ ((packed));
+
+
+#define RFID_MIFARE_KEY_LEN 6
+#define RFID_MIFARE_KEY_CODED_LEN 12
+
+/* Transform crypto1 key from generic 6byte into rc632 specific 12byte */
+static int
+rc632_mifare_transform_key(const u_int8_t *key6, u_int8_t *key12)
+{
+ int i;
+ u_int8_t ln;
+ u_int8_t hn;
+
+ for (i = 0; i < RFID_MIFARE_KEY_LEN; i++) {
+ ln = key6[i] & 0x0f;
+ hn = key6[i] >> 4;
+ key12[i * 2 + 1] = (~ln << 4) | ln;
+ key12[i * 2] = (~hn << 4) | hn;
+ }
+ return 0;
+}
+
+static int
+rc632_mifare_set_key(struct rfid_asic_handle *h, const u_int8_t *key)
+{
+ u_int8_t coded_key[RFID_MIFARE_KEY_CODED_LEN];
+ u_int8_t reg;
+ int ret;
+
+ ret = rc632_mifare_transform_key(key, coded_key);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_fifo_write(h, RFID_MIFARE_KEY_CODED_LEN, coded_key, 0x03);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_COMMAND, RC632_CMD_LOAD_KEY);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_wait_idle(h, RC632_TMO_AUTH1);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_read(h, RC632_REG_ERROR_FLAG, ®);
+ if (ret < 0)
+ return ret;
+
+ if (reg & RC632_ERR_FLAG_KEY_ERR)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int
+rc632_mifare_auth(struct rfid_asic_handle *h, u_int8_t cmd, u_int32_t serno,
+ u_int8_t block)
+{
+ int ret;
+ struct mifare_authcmd acmd;
+ u_int8_t reg;
+
+ if (cmd != RFID_CMD_MIFARE_AUTH1A && cmd != RFID_CMD_MIFARE_AUTH1B)
+ return -EINVAL;
+
+ /* Initialize acmd */
+ acmd.block_address = block & 0xff;
+ acmd.auth_cmd = cmd;
+ //acmd.serno = htonl(serno);
+ acmd.serno = serno;
+
+ ret = rc632_clear_bits(h, RC632_REG_CONTROL,
+ RC632_CONTROL_CRYPTO1_ON);
+
+ /* Clear Rx CRC */
+ ret = rc632_clear_bits(h, RC632_REG_CHANNEL_REDUNDANCY,
+ RC632_CR_RX_CRC_ENABLE);
+ if (ret < 0)
+ return ret;
+
+ /* Send Authent1 Command */
+ ret = rc632_fifo_write(h, sizeof(acmd), (unsigned char *)&acmd, 0x03);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_write(h, RC632_REG_COMMAND, RC632_CMD_AUTHENT1);
+ if (ret < 0)
+ return ret;
+
+ /* Wait until transmitter is idle */
+ ret = rc632_wait_idle(h, RC632_TMO_AUTH1);
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_reg_read(h, RC632_REG_SECONDARY_STATUS, ®);
+ if (ret < 0)
+ return ret;
+ if (reg & 0x07)
+ return -EIO;
+
+ /* Clear Tx CRC */
+ ret = rc632_clear_bits(h, RC632_REG_CHANNEL_REDUNDANCY,
+ RC632_CR_TX_CRC_ENABLE);
+ if (ret < 0)
+ return ret;
+
+ /* Send Authent2 Command */
+ ret = rc632_reg_write(h, RC632_REG_COMMAND, RC632_CMD_AUTHENT2);
+ if (ret < 0)
+ return ret;
+
+ /* Wait until transmitter is idle */
+ ret = rc632_wait_idle(h, RC632_TMO_AUTH1);
+ if (ret < 0)
+ return ret;
+
+ /* Check whether authentication was successful */
+ ret = rc632_reg_read(h, RC632_REG_CONTROL, ®);
+ if (ret < 0)
+ return ret;
+
+ if (!(reg & RC632_CONTROL_CRYPTO1_ON))
+ return -EACCES;
+
+ return 0;
+
+}
+
+/* transcieve regular frame */
+static int
+rc632_mifare_transcieve(struct rfid_asic_handle *handle,
+ const u_int8_t *tx_buf, unsigned int tx_len,
+ u_int8_t *rx_buf, unsigned int *rx_len,
+ u_int64_t timeout, unsigned int flags)
+{
+ int ret;
+ u_int8_t rxl = *rx_len & 0xff;
+
+ DEBUGP("entered\n");
+ memset(rx_buf, 0, *rx_len);
+
+#if 1
+ ret = rc632_reg_write(handle, RC632_REG_CHANNEL_REDUNDANCY,
+ (RC632_CR_PARITY_ENABLE |
+ RC632_CR_PARITY_ODD |
+ RC632_CR_TX_CRC_ENABLE |
+ RC632_CR_RX_CRC_ENABLE));
+#else
+ ret = rc632_clear_bits(handle, RC632_REG_CHANNEL_REDUNDANCY,
+ RC632_CR_RX_CRC_ENABLE|RC632_CR_TX_CRC_ENABLE);
+#endif
+ if (ret < 0)
+ return ret;
+
+ ret = rc632_transcieve(handle, tx_buf, tx_len, rx_buf, &rxl, 0x32, 0);
+ *rx_len = rxl;
+ if (ret < 0)
+ return ret;
+
+
+ return 0;
+}
+
+struct rfid_asic rc632 = {
+ .name = "Philips CL RC632",
+ .fc = ISO14443_FREQ_CARRIER,
+ .priv.rc632 = {
+ .fn = {
+ .power_up = &rc632_power_up,
+ .power_down = &rc632_power_down,
+ .turn_on_rf = &rc632_turn_on_rf,
+ .turn_off_rf = &rc632_turn_off_rf,
+ .transcieve = &rc632_iso14443ab_transcieve,
+ .iso14443a = {
+ .init = &rc632_iso14443a_init,
+ .transcieve_sf = &rc632_iso14443a_transcieve_sf,
+ .transcieve_acf = &rc632_iso14443a_transcieve_acf,
+ .set_speed = &rc632_iso14443a_set_speed,
+ },
+ .iso14443b = {
+ .init = &rc632_iso14443b_init,
+ },
+ .iso15693 = {
+ .init = &rc632_iso15693_init,
+ },
+ .mifare_classic = {
+ .setkey = &rc632_mifare_set_key,
+ .auth = &rc632_mifare_auth,
+ },
+ },
+ },
+};
--- /dev/null
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+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];
+}
+
--- /dev/null
+#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
--- /dev/null
+/* librfid - layer 2 protocol handler
+ * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <librfid/rfid.h>
+#include <librfid/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)
+{
+ if (!ph->l2->fn.open)
+ return 0;
+
+ return ph->l2->fn.open(ph);
+}
+
+int
+rfid_layer2_transcieve(struct rfid_layer2_handle *ph,
+ enum rfid_frametype frametype,
+ const unsigned char *tx_buf, unsigned int len,
+ unsigned char *rx_buf, unsigned int *rx_len,
+ u_int64_t timeout, unsigned int flags)
+{
+ if (!ph->l2->fn.transcieve)
+ return -EIO;
+
+ return ph->l2->fn.transcieve(ph, frametype, tx_buf, len, rx_buf,
+ rx_len, timeout, flags);
+}
+
+int rfid_layer2_fini(struct rfid_layer2_handle *ph)
+{
+ if (!ph->l2->fn.fini)
+ return 0;
+
+ return ph->l2->fn.fini(ph);
+}
+
+int
+rfid_layer2_close(struct rfid_layer2_handle *ph)
+{
+ if (!ph->l2->fn.close)
+ return 0;
+
+ 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;
+}
+
+int
+rfid_layer2_getopt(struct rfid_layer2_handle *ph, int optname,
+ void *optval, unsigned int *optlen)
+{
+ if (!ph->l2->fn.getopt)
+ return -EINVAL;
+
+ return ph->l2->fn.getopt(ph, optname, optval, optlen);
+}
+
+int
+rfid_layer2_setopt(struct rfid_layer2_handle *ph, int optname,
+ const void *optval, unsigned int optlen)
+{
+ if (!ph->l2->fn.setopt)
+ return -EINVAL;
+
+ return ph->l2->fn.setopt(ph, optname, optval, optlen);
+}
--- /dev/null
+/* ISO 14443-3 A anticollision implementation
+ *
+ * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <librfid/rfid.h>
+#include <librfid/rfid_layer2.h>
+#include <librfid/rfid_reader.h>
+#include <librfid/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,
+ enum rfid_frametype frametype,
+ const unsigned char *tx_buf, unsigned int tx_len,
+ unsigned char *rx_buf, unsigned int *rx_len,
+ u_int64_t timeout, unsigned int flags)
+{
+ return handle->rh->reader->transcieve(handle->rh, frametype, tx_buf,
+ tx_len, rx_buf, rx_len, timeout, flags);
+}
+
+static int
+iso14443a_code_nvb_bits(unsigned char *nvb, unsigned int bits)
+{
+ unsigned int byte_count = bits / 8;
+ unsigned int bit_count = bits % 8;
+
+ if (byte_count < 2 || byte_count > 7)
+ return -1;
+
+ *nvb = ((byte_count & 0xf) << 4) | bit_count;
+
+ return 0;
+}
+
+/* first bit is '1', second bit '2' */
+static void
+set_bit_in_field(unsigned char *bitfield, unsigned int bit)
+{
+ unsigned int byte_count = bit / 8;
+ unsigned int bit_count = bit % 8;
+
+ DEBUGP("bitfield=%p, byte_count=%u, bit_count=%u\n",
+ bitfield, byte_count, bit_count);
+ DEBUGP("%p = 0x%02x\n", (bitfield+byte_count), *(bitfield+byte_count));
+ *(bitfield+byte_count) |= 1 << (bit_count-1);
+ DEBUGP("%p = 0x%02x\n", (bitfield+byte_count), *(bitfield+byte_count));
+}
+
+static int
+iso14443a_anticol(struct rfid_layer2_handle *handle)
+{
+ int ret;
+ unsigned int uid_size;
+ struct iso14443a_handle *h = &handle->priv.iso14443a;
+ struct iso14443a_atqa atqa;
+ struct iso14443a_anticol_cmd acf;
+ unsigned int bit_of_col;
+ unsigned char sak[3];
+ unsigned int rx_len = sizeof(sak);
+ char *aqptr = (char *) &atqa;
+
+ memset(handle->uid, 0, sizeof(handle->uid));
+ memset(sak, 0, sizeof(sak));
+ memset(&atqa, 0, sizeof(atqa));
+ memset(&acf, 0, sizeof(acf));
+
+ ret = iso14443a_transcieve_sf(handle, ISO14443A_SF_CMD_REQA, &atqa);
+ if (ret < 0) {
+ h->state = ISO14443A_STATE_REQA_SENT;
+ DEBUGP("error during transcieve_sf: %d\n", ret);
+ return ret;
+ }
+ h->state = ISO14443A_STATE_ATQA_RCVD;
+
+ DEBUGP("ATQA: 0x%02x 0x%02x\n", *aqptr, *(aqptr+1));
+
+ if (!atqa.bf_anticol) {
+ h->state = ISO14443A_STATE_NO_BITFRAME_ANTICOL;
+ DEBUGP("no bitframe anticollission bits set, aborting\n");
+ return -1;
+ }
+
+ if (atqa.uid_size == 2 || atqa.uid_size == 3)
+ uid_size = 3;
+ else if (atqa.uid_size == 1)
+ uid_size = 2;
+ else
+ uid_size = 1;
+
+ acf.sel_code = ISO14443A_AC_SEL_CODE_CL1;
+
+ h->state = ISO14443A_STATE_ANTICOL_RUNNING;
+ h->level = ISO14443A_LEVEL_CL1;
+
+cascade:
+ iso14443a_code_nvb_bits(&acf.nvb, 16);
+
+ ret = iso14443a_transcieve_acf(handle, &acf, &bit_of_col);
+ if (ret < 0)
+ return ret;
+ DEBUGP("bit_of_col = %u\n", bit_of_col);
+
+ while (bit_of_col != ISO14443A_BITOFCOL_NONE) {
+ set_bit_in_field(&acf.uid_bits[0], bit_of_col-16);
+ iso14443a_code_nvb_bits(&acf.nvb, bit_of_col);
+ ret = iso14443a_transcieve_acf(handle, &acf, &bit_of_col);
+ DEBUGP("bit_of_col = %u\n", bit_of_col);
+ if (ret < 0)
+ return ret;
+ }
+
+ iso14443a_code_nvb_bits(&acf.nvb, 7*8);
+ ret = iso14443a_transcieve(handle, RFID_14443A_FRAME_REGULAR,
+ (unsigned char *)&acf, 7,
+ (unsigned char *) &sak, &rx_len,
+ TIMEOUT, 0);
+ if (ret < 0)
+ return ret;
+
+ if (sak[0] & 0x04) {
+ /* Cascade bit set, UID not complete */
+ switch (acf.sel_code) {
+ case ISO14443A_AC_SEL_CODE_CL1:
+ /* cascading from CL1 to CL2 */
+ if (acf.uid_bits[0] != 0x88) {
+ DEBUGP("Cascade bit set, but UID0 != 0x88\n");
+ return -1;
+ }
+ memcpy(&handle->uid[0], &acf.uid_bits[1], 3);
+ acf.sel_code = ISO14443A_AC_SEL_CODE_CL2;
+ h->level = ISO14443A_LEVEL_CL2;
+ break;
+ case ISO14443A_AC_SEL_CODE_CL2:
+ /* cascading from CL2 to CL3 */
+ memcpy(&handle->uid[3], &acf.uid_bits[1], 3);
+ acf.sel_code = ISO14443A_AC_SEL_CODE_CL3;
+ h->level = ISO14443A_LEVEL_CL3;
+ break;
+ default:
+ DEBUGP("cannot cascade any further than CL3\n");
+ h->state = ISO14443A_STATE_ERROR;
+ return -1;
+ break;
+ }
+ goto cascade;
+
+ } else {
+ switch (acf.sel_code) {
+ case ISO14443A_AC_SEL_CODE_CL1:
+ /* single size UID (4 bytes) */
+ memcpy(&handle->uid[0], &acf.uid_bits[0], 4);
+ break;
+ case ISO14443A_AC_SEL_CODE_CL2:
+ /* double size UID (7 bytes) */
+ memcpy(&handle->uid[3], &acf.uid_bits[0], 4);
+ break;
+ case ISO14443A_AC_SEL_CODE_CL3:
+ /* triple size UID (10 bytes) */
+ memcpy(&handle->uid[6], &acf.uid_bits[0], 4);
+ break;
+ }
+ }
+
+ h->level = ISO14443A_LEVEL_NONE;
+ h->state = ISO14443A_STATE_SELECTED;
+
+ {
+ if (uid_size == 1)
+ handle->uid_len = 4;
+ else if (uid_size == 2)
+ handle->uid_len = 7;
+ else
+ handle->uid_len = 10;
+
+ DEBUGP("UID %s\n", rfid_hexdump(handle->uid, handle->uid_len));
+ }
+
+ if (sak[0] & 0x20) {
+ DEBUGP("we have a T=CL compliant PICC\n");
+ h->tcl_capable = 1;
+ } else {
+ DEBUGP("we have a T!=CL PICC\n");
+ h->tcl_capable = 0;
+ }
+
+ return 0;
+}
+
+static int
+iso14443a_hlta(struct rfid_layer2_handle *handle)
+{
+ int ret;
+ unsigned char tx_buf[2] = { 0x50, 0x00 };
+ unsigned char rx_buf[10];
+ unsigned int rx_len = sizeof(rx_buf);
+
+ ret = iso14443a_transcieve(handle, RFID_14443A_FRAME_REGULAR,
+ tx_buf, sizeof(tx_buf),
+ rx_buf, &rx_len, 1000 /* 1ms */, 0);
+ if (ret < 0) {
+ /* "error" case: we don't get somethng back from the card */
+ return 0;
+ }
+ return -1;
+}
+
+static int
+iso14443a_setopt(struct rfid_layer2_handle *handle, int optname,
+ const void *optval, unsigned int optlen)
+{
+ int ret = -EINVAL;
+ struct rfid_reader *rdr = handle->rh->reader;
+ unsigned int speed;
+
+ switch (optname) {
+ case RFID_OPT_14443A_SPEED_RX:
+ if (!rdr->iso14443a.set_speed)
+ return -ENOTSUP;
+ speed = *(unsigned int *)optval;
+ ret = rdr->iso14443a.set_speed(handle->rh, 0, speed);
+ break;
+ case RFID_OPT_14443A_SPEED_TX:
+ if (!rdr->iso14443a.set_speed)
+ return -ENOTSUP;
+ speed = *(unsigned int *)optval;
+ ret = rdr->iso14443a.set_speed(handle->rh, 1, speed);
+ break;
+ };
+
+ return ret;
+}
+
+
+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,
+ .setopt = &iso14443a_setopt,
+ },
+};
+
--- /dev/null
+/* ISO 14443-3 B anticollision implementation
+ *
+ * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <librfid/rfid.h>
+#include <librfid/rfid_layer2.h>
+#include <librfid/rfid_reader.h>
+#include <librfid/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)
+{
+ unsigned int multiplier, tmp;
+
+ /* 15 is RFU */
+ if (fwi > 14)
+ return -1;
+
+ /* According to ISO 14443-3:200(E), Chapter 7.9.4.3, the forumala is
+ * (256 * 16 / fC) * 2^fwi We avoid floating point computations by
+ * shifting everything into the microsecond range. In integer
+ * calculations 1000000*256*16/13560000 evaluates to 302 (instead of
+ * 302.064897), which provides sufficient precision, IMHO. The max
+ * result is 302 * 16384 (4947968), which fits well within the 31/32
+ * bit range of an integer */
+
+ multiplier = 1 << fwi; /* 2 to the power of fwi */
+
+ tmp = (unsigned int) 1000000 * 256 * 16;
+
+ return (tmp / h->rh->ah->asic->fc) * multiplier;
+}
+
+static int
+parse_atqb(struct rfid_layer2_handle *h, struct iso14443b_atqb *atqb)
+{
+ int ret;
+
+ if (atqb->fifty != 0x50)
+ return -1;
+
+ if (atqb->protocol_info.fo & 0x01)
+ h->priv.iso14443b.flags |= ISO14443B_CID_SUPPORTED;
+ if (atqb->protocol_info.fo & 0x02)
+ h->priv.iso14443b.flags |= ISO14443B_NAD_SUPPORTED;
+
+ ret = fwi_to_fwt(h, &h->priv.iso14443b.fwt, atqb->protocol_info.fwi);
+ if (ret < 0) {
+ DEBUGP("invalid fwi %u\n", atqb->protocol_info.fwi);
+ return ret;
+ }
+
+ if (atqb->protocol_info.protocol_type == 0x1) {
+ DEBUGP("we have a T=CL compliant PICC\n");
+ h->priv.iso14443b.tcl_capable = 1;
+ } else {
+ DEBUGP("we have a T!=CL PICC\n");
+ h->priv.iso14443b.tcl_capable = 0;
+ }
+
+ iso14443_fsdi_to_fsd(&h->priv.iso14443b.fsc,
+ atqb->protocol_info.max_frame_size);
+
+ /* FIXME: speed capability */
+
+ memcpy(h->uid, atqb->pupi, sizeof(atqb->pupi));
+ h->uid_len = sizeof(atqb->pupi);
+
+ return 0;
+}
+
+static int
+send_reqb(struct rfid_layer2_handle *h, unsigned char afi,
+ unsigned int is_wup, unsigned int num_initial_slots)
+{
+ int ret;
+ unsigned char reqb[3];
+ struct iso14443b_atqb atqb;
+ unsigned int atqb_len = sizeof(atqb);
+ unsigned int num_slot_idx = num_initial_slots;
+
+ reqb[0] = 0x05;
+ reqb[1] = afi;
+
+ for (num_slot_idx = num_initial_slots; num_slot_idx <= 4;
+ num_slot_idx++) {
+ reqb[2] = num_slot_idx & 0x07;
+ if (is_wup)
+ reqb[2] |= 0x08;
+
+ ret = h->rh->reader->transcieve(h->rh, RFID_14443B_FRAME_REGULAR,
+ reqb, sizeof(reqb),
+ (unsigned char *)&atqb,
+ &atqb_len, ATQB_TIMEOUT, 0);
+ h->priv.iso14443b.state = ISO14443B_STATE_REQB_SENT;
+ if (ret < 0) {
+ DEBUGP("error during transcieve of REQB/WUBP\n");
+ continue;
+ }
+
+ /* FIXME: send N-1 slot marker frames */
+
+ if (atqb_len != sizeof(atqb)) {
+ DEBUGP("error: atqb_len = %u instead of %Zu\n",
+ atqb_len, sizeof(atqb));
+ continue;
+ }
+
+ /* FIXME: how to detect a collission at 14443B ? I guess we
+ * can only rely on the CRC checking (CRCErr in ErrorFlag
+ * register?) */
+
+ if (parse_atqb(h, &atqb) >= 0) {
+ h->priv.iso14443b.state = ISO14443B_STATE_ATQB_RCVD;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+static inline unsigned int mbli_to_mbl(struct rfid_layer2_handle *h,
+ unsigned int mbli)
+{
+ return (h->priv.iso14443b.fsc * 2 ^ (mbli-1));
+}
+
+static int
+transcieve_attrib(struct rfid_layer2_handle *h, const unsigned char *inf,
+ unsigned int inf_len, unsigned char *rx_data, unsigned int *rx_len)
+{
+ struct iso14443b_attrib_hdr *attrib;
+ unsigned int attrib_size = sizeof(*attrib) + inf_len;
+ unsigned char *rx_buf;
+ unsigned char fsdi;
+ int ret = 0;
+
+ DEBUGP("fsd is %u\n", h->priv.iso14443b.fsd);
+ attrib = malloc(attrib_size);
+ if (!attrib) {
+ perror("attrib_alloc");
+ return -1;
+ }
+
+ DEBUGP("fsd is %u\n", h->priv.iso14443b.fsd);
+ rx_buf = malloc(*rx_len+1);
+ if (!rx_buf) {
+ perror("rx_buf malloc");
+ ret = -1;
+ goto out_attrib;
+ }
+
+ /* initialize attrib frame */
+ memset(attrib, 0, attrib_size);
+ if (inf_len)
+ memcpy((unsigned char *)attrib+sizeof(*attrib), inf, inf_len);
+
+ attrib->one_d = 0x1d;
+ memcpy(attrib->identifier, h->uid, 4);
+
+ /* FIXME: do we want to change TR0/TR1 from its default ? */
+ /* FIXME: do we want to change SOF/EOF from its default ? */
+
+ ret = iso14443_fsd_to_fsdi(&fsdi, h->priv.iso14443b.fsd);
+ if (ret < 0) {
+ DEBUGP("unable to map FSD(%u) to FSDI\n",
+ h->priv.iso14443b.fsd);
+ goto out_rx;
+ }
+ attrib->param2.fsdi = fsdi;
+
+ /* FIXME: spd_in / spd_out */
+ if (h->priv.iso14443b.tcl_capable == 1)
+ attrib->param3.protocol_type = 0x1;
+
+ *rx_len = *rx_len + 1;
+ ret = h->rh->reader->transcieve(h->rh, RFID_14443B_FRAME_REGULAR,
+ (unsigned char *) attrib,
+ sizeof(*attrib)+inf_len,
+ rx_buf, rx_len, h->priv.iso14443b.fwt,
+ 0);
+ h->priv.iso14443b.state = ISO14443B_STATE_ATTRIB_SENT;
+ if (ret < 0) {
+ DEBUGP("transcieve problem\n");
+ goto out_rx;
+ }
+
+ if ((rx_buf[0] & 0x0f) != h->priv.iso14443b.cid) {
+ DEBUGP("ATTRIB response with invalid CID %u\n",
+ rx_buf[0] & 0x0f);
+ ret = -1;
+ goto out_rx;
+ }
+
+ h->priv.iso14443b.state = ISO14443B_STATE_SELECTED;
+
+ h->priv.iso14443b.mbl = mbli_to_mbl(h, (rx_data[0] & 0xf0) >> 4);
+
+ *rx_len = *rx_len - 1;
+ memcpy(rx_data, rx_buf+1, *rx_len);
+
+out_rx:
+ free(rx_buf);
+out_attrib:
+ free(attrib);
+
+ return ret;
+}
+
+static int
+iso14443b_hltb(struct rfid_layer2_handle *h)
+{
+ int ret;
+ unsigned char hltb[5];
+ unsigned char hltb_resp[1];
+ unsigned int hltb_len = 1;
+
+ hltb[0] = 0x50;
+ memcpy(hltb+1, h->uid, 4);
+
+ ret = h->rh->reader->transcieve(h->rh, RFID_14443B_FRAME_REGULAR,
+ hltb, 5,
+ hltb_resp, &hltb_len,
+ h->priv.iso14443b.fwt, 0);
+ h->priv.iso14443b.state = ISO14443B_STATE_HLTB_SENT;
+ if (ret < 0) {
+ DEBUGP("transcieve problem\n");
+ return ret;
+ }
+
+ if (hltb_len != 1 || hltb_resp[0] != 0x00) {
+ DEBUGP("bad HLTB response\n");
+ return -1;
+ }
+ h->priv.iso14443b.state = ISO14443B_STATE_HALTED;
+
+ return 0;
+}
+
+static int
+iso14443b_anticol(struct rfid_layer2_handle *handle)
+{
+ unsigned char afi = 0; /* FIXME */
+ int ret;
+ unsigned char buf[255];
+ unsigned int buf_len = sizeof(buf);
+
+ ret = send_reqb(handle, afi, 0, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = transcieve_attrib(handle, NULL, 0, buf, &buf_len);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct rfid_layer2_handle *
+iso14443b_init(struct rfid_reader_handle *rh)
+{
+ int ret;
+ struct rfid_layer2_handle *h = malloc(sizeof(*h));
+ if (!h)
+ return NULL;
+
+ h->l2 = &rfid_layer2_iso14443b;
+ h->rh = rh;
+ h->priv.iso14443b.state = ISO14443B_STATE_NONE;
+
+ h->priv.iso14443b.fsd = iso14443_fsd_approx(rh->ah->mru);
+ DEBUGP("fsd is %u\n", h->priv.iso14443b.fsd);
+
+ /* 14443-3 Section 7.1.6 */
+ h->priv.iso14443b.tr0 = (256/ISO14443_FREQ_SUBCARRIER)*10e6;
+ h->priv.iso14443b.tr1 = (200/ISO14443_FREQ_SUBCARRIER)*10e6;
+
+ ret = h->rh->reader->iso14443b.init(h->rh);
+ if (ret < 0) {
+ DEBUGP("error during reader 14443b init\n");
+ free(h);
+ return NULL;
+ }
+
+ return h;
+}
+
+static int
+iso14443b_fini(struct rfid_layer2_handle *handle)
+{
+ free(handle);
+ return 0;
+}
+
+static int
+iso14443b_transcieve(struct rfid_layer2_handle *handle,
+ enum rfid_frametype frametype,
+ const unsigned char *tx_buf, unsigned int tx_len,
+ unsigned char *rx_buf, unsigned int *rx_len,
+ u_int64_t timeout, unsigned int flags)
+{
+ DEBUGP("transcieving %u bytes, expecting max %u\n", tx_len, *rx_len);
+ return handle->rh->reader->transcieve(handle->rh, frametype,
+ tx_buf, tx_len,
+ rx_buf, rx_len, timeout, flags);
+}
+
+struct rfid_layer2 rfid_layer2_iso14443b = {
+ .id = RFID_LAYER2_ISO14443B,
+ .name = "ISO 14443-3 B",
+ .fn = {
+ .init = &iso14443b_init,
+ .open = &iso14443b_anticol,
+ .transcieve = &iso14443b_transcieve,
+ .close = &iso14443b_hltb,
+ .fini = &iso14443b_fini,
+ },
+};
--- /dev/null
+/* ISO 15693 anticollision implementation
+ *
+ * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <librfid/rfid.h>
+#include <librfid/rfid_layer2.h>
+#include <librfid/rfid_reader.h>
+#include <librfid/rfid_layer2_iso15693.h>
+
+#if 0
+/* Transcieve a 7-bit short frame */
+static int
+iso14443a_transcieve_sf(struct rfid_layer2_handle *handle,
+ unsigned char cmd,
+ struct iso14443a_atqa *atqa)
+{
+ struct rfid_reader *rdr = handle->rh->reader;
+
+ return rdr->iso14443a.transcieve_sf(handle->rh, cmd, atqa);
+}
+
+/* Transmit an anticollission bit frame */
+static int
+iso14443a_transcieve_acf(struct rfid_layer2_handle *handle,
+ struct iso14443a_anticol_cmd *acf,
+ unsigned int *bit_of_col)
+{
+ struct rfid_reader *rdr = handle->rh->reader;
+
+ return rdr->iso14443a.transcieve_acf(handle->rh, acf, bit_of_col);
+}
+
+/* Transmit a regular frame */
+static int
+iso14443a_transcieve(struct rfid_layer2_handle *handle,
+ const unsigned char *tx_buf, unsigned int tx_len,
+ unsigned char *rx_buf, unsigned int *rx_len,
+ u_int64_t, unsigned int flags)
+{
+ return handle->rh->reader->transcieve(handle->rh, tx_buf, tx_len,
+ rx_buf, rx_len, timeout, flags);
+}
+
+static int
+iso14443a_code_nvb_bits(unsigned char *nvb, unsigned int bits)
+{
+ unsigned int byte_count = bits / 8;
+ unsigned int bit_count = bits % 8;
+
+ if (byte_count < 2 || byte_count > 7)
+ return -1;
+
+ *nvb = ((byte_count & 0xf) << 4) | bit_count;
+
+ return 0;
+}
+
+/* first bit is '1', second bit '2' */
+static void
+set_bit_in_field(unsigned char *bitfield, unsigned int bit)
+{
+ unsigned int byte_count = bit / 8;
+ unsigned int bit_count = bit % 8;
+
+ DEBUGP("bitfield=%p, byte_count=%u, bit_count=%u\n",
+ bitfield, byte_count, bit_count);
+ DEBUGP("%p = 0x%02x\n", (bitfield+byte_count), *(bitfield+byte_count));
+ *(bitfield+byte_count) |= 1 << (bit_count-1);
+ DEBUGP("%p = 0x%02x\n", (bitfield+byte_count), *(bitfield+byte_count));
+}
+
+static int
+iso14443a_anticol(struct rfid_layer2_handle *handle)
+{
+ int ret;
+ unsigned int uid_size;
+ struct iso14443a_atqa atqa;
+ struct iso14443a_anticol_cmd acf;
+ unsigned int bit_of_col;
+ unsigned char sak[3];
+ unsigned char uid[10]; // triple size equals 10 bytes;
+ unsigned int rx_len = sizeof(sak);
+ char *aqptr = (char *) &atqa;
+ static int first = 0;
+
+ memset(uid, 0, sizeof(uid));
+ memset(sak, 0, sizeof(sak));
+ memset(&atqa, 0, sizeof(atqa));
+ memset(&acf, 0, sizeof(acf));
+
+ if (first == 0) {
+ DEBUGP("Sending REQA\n");
+ ret = iso14443a_transcieve_sf(handle, ISO14443A_SF_CMD_REQA, &atqa);
+ first = 1;
+ } else {
+ DEBUGP("Sending WUPA\n");
+ ret = iso14443a_transcieve_sf(handle, ISO14443A_SF_CMD_WUPA, &atqa);
+ }
+
+ if (ret < 0) {
+ handle->priv.iso14443a.state = ISO14443A_STATE_REQA_SENT;
+ DEBUGP("error during transcieve_sf: %d\n", ret);
+ return ret;
+ }
+ handle->priv.iso14443a.state = ISO14443A_STATE_ATQA_RCVD;
+
+ DEBUGP("ATQA: 0x%02x 0x%02x\n", *aqptr, *(aqptr+1));
+
+ if (!atqa.bf_anticol) {
+ handle->priv.iso14443a.state =ISO14443A_STATE_NO_BITFRAME_ANTICOL;
+ DEBUGP("no bitframe anticollission bits set, aborting\n");
+ return -1;
+ }
+
+ if (atqa.uid_size == 2 || atqa.uid_size == 3)
+ uid_size = 3;
+ else if (atqa.uid_size == 1)
+ uid_size = 2;
+ else
+ uid_size = 1;
+
+ acf.sel_code = ISO14443A_AC_SEL_CODE_CL1;
+
+ handle->priv.iso14443a.state = ISO14443A_STATE_ANTICOL_RUNNING;
+ handle->priv.iso14443a.level = ISO14443A_LEVEL_CL1;
+
+cascade:
+ iso14443a_code_nvb_bits(&acf.nvb, 16);
+
+ ret = iso14443a_transcieve_acf(handle, &acf, &bit_of_col);
+ if (ret < 0)
+ return ret;
+ DEBUGP("bit_of_col = %u\n", bit_of_col);
+
+ while (bit_of_col != ISO14443A_BITOFCOL_NONE) {
+ set_bit_in_field(&acf.uid_bits[0], bit_of_col-16);
+ iso14443a_code_nvb_bits(&acf.nvb, bit_of_col);
+ ret = iso14443a_transcieve_acf(handle, &acf, &bit_of_col);
+ DEBUGP("bit_of_col = %u\n", bit_of_col);
+ if (ret < 0)
+ return ret;
+ }
+
+ iso14443a_code_nvb_bits(&acf.nvb, 7*8);
+ ret = iso14443a_transcieve(handle, (unsigned char *)&acf, 7,
+ (unsigned char *) &sak, &rx_len,
+ TIMEOUT, 0);
+ if (ret < 0)
+ return ret;
+
+ if (sak[0] & 0x04) {
+ /* Cascade bit set, UID not complete */
+ switch (acf.sel_code) {
+ case ISO14443A_AC_SEL_CODE_CL1:
+ /* cascading from CL1 to CL2 */
+ if (acf.uid_bits[0] != 0x88) {
+ DEBUGP("Cascade bit set, but UID0 != 0x88\n");
+ return -1;
+ }
+ memcpy(&uid[0], &acf.uid_bits[1], 3);
+ acf.sel_code = ISO14443A_AC_SEL_CODE_CL2;
+ handle->priv.iso14443a.level = ISO14443A_LEVEL_CL2;
+ break;
+ case ISO14443A_AC_SEL_CODE_CL2:
+ /* cascading from CL2 to CL3 */
+ memcpy(&uid[3], &acf.uid_bits[1], 3);
+ acf.sel_code = ISO14443A_AC_SEL_CODE_CL3;
+ handle->priv.iso14443a.level = ISO14443A_LEVEL_CL3;
+ break;
+ default:
+ DEBUGP("cannot cascade any further than CL3\n");
+ handle->priv.iso14443a.state = ISO14443A_STATE_ERROR;
+ return -1;
+ break;
+ }
+ goto cascade;
+
+ } else {
+ switch (acf.sel_code) {
+ case ISO14443A_AC_SEL_CODE_CL1:
+ /* single size UID (4 bytes) */
+ memcpy(&uid[0], &acf.uid_bits[0], 4);
+ break;
+ case ISO14443A_AC_SEL_CODE_CL2:
+ /* double size UID (7 bytes) */
+ memcpy(&uid[3], &acf.uid_bits[0], 4);
+ break;
+ case ISO14443A_AC_SEL_CODE_CL3:
+ /* triple size UID (10 bytes) */
+ memcpy(&uid[6], &acf.uid_bits[0], 4);
+ break;
+ }
+ }
+
+ handle->priv.iso14443a.level = ISO14443A_LEVEL_NONE;
+ handle->priv.iso14443a.state = ISO14443A_STATE_SELECTED;
+
+ {
+ int uid_len;
+ if (uid_size == 1)
+ uid_len = 4;
+ else if (uid_size == 2)
+ uid_len = 7;
+ else
+ uid_len = 10;
+
+ DEBUGP("UID %s\n", rfid_hexdump(uid, uid_len));
+ }
+
+ if (sak[0] & 0x20) {
+ DEBUGP("we have a T=CL compliant PICC\n");
+ handle->priv.iso14443a.tcl_capable = 1;
+ } else {
+ DEBUGP("we have a T!=CL PICC\n");
+ handle->priv.iso14443a.tcl_capable = 0;
+ }
+
+ return 0;
+}
+
+static int
+iso14443a_hlta(struct rfid_layer2_handle *handle)
+{
+ int ret;
+ unsigned char tx_buf[2] = { 0x50, 0x00 };
+ unsigned char rx_buf[10];
+ unsigned int rx_len = sizeof(rx_buf);
+
+ return 0;
+
+ ret = iso14443a_transcieve(handle, tx_buf, sizeof(tx_buf),
+ rx_buf, &rx_len, 1000 /* 1ms */, 0);
+ if (ret < 0) {
+ /* "error" case: we don't get somethng back from the card */
+ return 0;
+ }
+ return -1;
+}
+#endif
+
+static struct rfid_layer2_handle *
+iso15693_init(struct rfid_reader_handle *rh)
+{
+ int ret;
+ struct rfid_layer2_handle *h = malloc(sizeof(*h));
+ if (!h)
+ return NULL;
+
+ h->l2 = &rfid_layer2_iso15693;
+ h->rh = rh;
+ h->priv.iso15693.state = ISO15693_STATE_NONE;
+
+ ret = h->rh->reader->iso15693.init(h->rh);
+ if (ret < 0) {
+ free(h);
+ return NULL;
+ }
+
+ return h;
+}
+
+static int
+iso15693_fini(struct rfid_layer2_handle *handle)
+{
+ free(handle);
+ return 0;
+}
+
+
+struct rfid_layer2 rfid_layer2_iso15693 = {
+ .id = RFID_LAYER2_ISO15693,
+ .name = "ISO 15693",
+ .fn = {
+ .init = &iso15693_init,
+ //.open = &iso15693_anticol,
+ //.transcieve = &iso15693_transcieve,
+ //.close = &iso14443a_hlta,
+ .fini = &iso15693_fini,
+ },
+};
+
--- /dev/null
+
+/* Mifare Classic implementation, PCD side.
+ *
+ * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <librfid/rfid.h>
+#include <librfid/rfid_protocol.h>
+#include <librfid/rfid_layer2.h>
+#include <librfid/rfid_protocol_mifare_classic.h>
+
+#include <librfid/rfid_reader.h>
+
+#include "rfid_iso14443_common.h"
+
+
+#define MIFARE_UL_CMD_WRITE 0xA2
+#define MIFARE_UL_CMD_READ 0x30
+
+/* FIXME */
+#define MIFARE_CL_READ_FWT 100
+#define MIFARE_CL_WRITE_FWT 100
+
+static int
+mfcl_read(struct rfid_protocol_handle *ph, unsigned int page,
+ unsigned char *rx_data, unsigned int *rx_len)
+{
+ unsigned char rx_buf[16];
+ unsigned int real_rx_len = sizeof(rx_buf);
+ unsigned char tx[2];
+ int ret;
+
+ if (page > MIFARE_CL_PAGE_MAX)
+ return -EINVAL;
+
+ tx[0] = MIFARE_CL_CMD_READ;
+ tx[1] = page & 0xff;
+
+ ret = rfid_layer2_transcieve(ph->l2h, RFID_MIFARE_FRAME, tx,
+ sizeof(tx), rx_buf, &real_rx_len,
+ MIFARE_CL_READ_FWT, 0);
+
+ if (ret < 0)
+ return ret;
+
+ if (real_rx_len == 1 && *rx_buf == 0x04)
+ return -EPERM;
+
+ if (real_rx_len < *rx_len)
+ *rx_len = real_rx_len;
+
+ memcpy(rx_data, rx_buf, *rx_len);
+
+ return ret;
+}
+
+static int
+mfcl_write(struct rfid_protocol_handle *ph, unsigned int page,
+ unsigned char *tx_data, unsigned int tx_len)
+{
+ unsigned int i;
+ unsigned char tx[18];
+ unsigned char rx[1];
+ unsigned int rx_len;
+ int ret;
+
+ if (tx_len != 16 || page > MIFARE_CL_PAGE_MAX)
+ return -EINVAL;
+
+ tx[0] = MIFARE_CL_CMD_WRITE16;
+ tx[1] = page & 0xff;
+
+ memcpy(tx+2, tx_data, 16);
+
+ ret = rfid_layer2_transcieve(ph->l2h, RFID_MIFARE_FRAME, tx,
+ sizeof(tx), rx, &rx_len,
+ MIFARE_CL_WRITE_FWT, 0);
+
+ if (ret < 0)
+ return ret;
+
+ if (rx[0] != MIFARE_UL_RESP_ACK)
+ return -EIO;
+
+ return ret;
+}
+
+static struct rfid_protocol_handle *
+mfcl_init(struct rfid_layer2_handle *l2h)
+{
+ struct rfid_protocol_handle *ph;
+ ph = malloc(sizeof(struct rfid_protocol_handle));
+ return ph;
+}
+
+static int mfcl_fini(struct rfid_protocol_handle *ph)
+{
+ free(ph);
+ return 0;
+}
+
+struct rfid_protocol rfid_protocol_mfcl = {
+ .id = RFID_PROTOCOL_MIFARE_CLASSIC,
+ .name = "Mifare Classic",
+ .fn = {
+ .init = &mfcl_init,
+ .read = &mfcl_read,
+ .write = &mfcl_write,
+ .fini = &mfcl_fini,
+ },
+};
+
+int mfcl_set_key(struct rfid_protocol_handle *ph, unsigned char *key)
+{
+ if (!ph->l2h->rh->reader->mifare_classic.setkey)
+ return -ENODEV;
+
+ return ph->l2h->rh->reader->mifare_classic.setkey(ph->l2h->rh, key);
+}
+
+int mfcl_auth(struct rfid_protocol_handle *ph, u_int8_t cmd, u_int8_t block)
+{
+ u_int32_t serno = *((u_int32_t *)ph->l2h->uid);
+
+ if (!ph->l2h->rh->reader->mifare_classic.auth)
+ return -ENODEV;
+
+ return ph->l2h->rh->reader->mifare_classic.auth(ph->l2h->rh, cmd,
+ serno, block);
+}
--- /dev/null
+
+/* Mifare Ultralight implementation, PCD side.
+ *
+ * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <librfid/rfid.h>
+#include <librfid/rfid_protocol.h>
+#include <librfid/rfid_layer2.h>
+#include <librfid/rfid_protocol_mifare_ul.h>
+
+#include "rfid_iso14443_common.h"
+
+
+/* FIXME */
+#define MIFARE_UL_READ_FWT 100
+#define MIFARE_UL_WRITE_FWT 100
+
+static int
+mful_read(struct rfid_protocol_handle *ph, unsigned int page,
+ unsigned char *rx_data, unsigned int *rx_len)
+{
+ unsigned char rx_buf[16];
+ unsigned int real_rx_len = sizeof(rx_buf);
+ unsigned char tx[2];
+ int ret;
+
+ if (page > MIFARE_UL_PAGE_MAX)
+ return -EINVAL;
+
+ tx[0] = MIFARE_UL_CMD_READ;
+ tx[1] = page & 0xff;
+
+ ret = rfid_layer2_transcieve(ph->l2h, RFID_14443A_FRAME_REGULAR,
+ tx, sizeof(tx), rx_buf,
+ &real_rx_len, MIFARE_UL_READ_FWT, 0);
+
+ if (ret < 0)
+ return ret;
+
+ if (real_rx_len < *rx_len)
+ *rx_len = real_rx_len;
+
+ memcpy(rx_data, rx_buf, *rx_len);
+
+ return ret;
+}
+
+static int
+mful_write(struct rfid_protocol_handle *ph, unsigned int page,
+ unsigned char *tx_data, unsigned int tx_len)
+{
+ unsigned int i;
+ unsigned char tx[6];
+ unsigned char rx[10];
+ unsigned int rx_len = sizeof(rx);
+ int ret;
+
+ if (tx_len != 4 || page > MIFARE_UL_PAGE_MAX)
+ return -EINVAL;
+
+ tx[0] = MIFARE_UL_CMD_WRITE;
+ tx[1] = page & 0xff;
+
+ for (i = 0; i < 4; i++)
+ tx[2+i] = tx_data[i];
+
+ ret = rfid_layer2_transcieve(ph->l2h, RFID_14443A_FRAME_REGULAR,
+ tx, sizeof(tx), rx, &rx_len,
+ MIFARE_UL_WRITE_FWT, 0);
+
+ if (ret < 0)
+ return ret;
+
+ if (rx[0] != MIFARE_UL_RESP_ACK)
+ return -EIO;
+
+ return ret;
+}
+
+static int
+mful_transcieve(struct rfid_protocol_handle *ph,
+ const unsigned char *tx_data, unsigned int tx_len,
+ unsigned char *rx_data, unsigned int *rx_len,
+ unsigned int timeout, unsigned int flags)
+{
+ return -EINVAL;
+}
+
+static struct rfid_protocol_handle *
+mful_init(struct rfid_layer2_handle *l2h)
+{
+ struct rfid_protocol_handle *ph;
+ ph = malloc(sizeof(struct rfid_protocol_handle));
+ return ph;
+}
+
+static int mful_fini(struct rfid_protocol_handle *ph)
+{
+ free(ph);
+ return 0;
+}
+
+struct rfid_protocol rfid_protocol_mful = {
+ .id = RFID_PROTOCOL_MIFARE_UL,
+ .name = "Mifare Ultralight",
+ .fn = {
+ .init = &mful_init,
+ .read = &mful_read,
+ .write = &mful_write,
+ .fini = &mful_fini,
+ },
+};
+
+/* Functions below are not (yet? covered in the generic librfid api */
+
+
+/* lock a certain page */
+int rfid_mful_lock_page(struct rfid_protocol_handle *ph, unsigned int page)
+{
+ unsigned char buf[4] = { 0x00, 0x00, 0x00, 0x00 };
+
+ if (ph->proto != &rfid_protocol_mful)
+ return -EINVAL;
+
+ if (page < 3 || page > 15)
+ return -EINVAL;
+
+ if (page > 8)
+ buf[2] = (1 << page);
+ else
+ buf[3] = (1 << (page - 8));
+
+ return mful_write(ph, MIFARE_UL_PAGE_LOCK, buf, sizeof(buf));
+}
+
+/* convenience wrapper to lock the otp page */
+int rfid_mful_lock_otp(struct rfid_protocol_handle *ph)
+{
+ return rfid_mful_lock_page(ph, MIFARE_UL_PAGE_OTP);
+}
--- /dev/null
+/* ISO 14443-4 (T=CL) implementation, PCD side.
+ *
+ * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <librfid/rfid.h>
+#include <librfid/rfid_protocol_tcl.h>
+#include <librfid/rfid_protocol.h>
+#include <librfid/rfid_layer2.h>
+#include <librfid/rfid_layer2_iso14443b.h>
+
+#include <librfid/rfid_asic.h>
+#include <librfid/rfid_reader.h>
+
+#include "rfid_iso14443_common.h"
+
+static enum rfid_frametype l2_to_frame(unsigned int layer2)
+{
+ switch (layer2) {
+ case RFID_LAYER2_ISO14443A:
+ return RFID_14443A_FRAME_REGULAR;
+ break;
+ case RFID_LAYER2_ISO14443B:
+ return RFID_14443B_FRAME_REGULAR;
+ break;
+ }
+ return 0;
+}
+
+static unsigned int sfgi_to_sfgt(struct rfid_protocol_handle *h,
+ unsigned char sfgi)
+{
+ unsigned int multiplier;
+ unsigned int tmp;
+
+ if (sfgi > 14)
+ sfgi = 14;
+
+ multiplier = 1 << sfgi; /* 2 to the power of sfgi */
+
+ /* ISO 14443-4:2000(E) Section 5.2.5:
+ * (256 * 16 / h->l2h->rh->ah->fc) * (2 ^ sfgi) */
+ tmp = (unsigned int) 1000000 * 256 * 16;
+
+ return (tmp / h->l2h->rh->ah->fc) * multiplier;
+}
+
+static unsigned int fwi_to_fwt(struct rfid_protocol_handle *h,
+ unsigned char fwi)
+{
+ unsigned int multiplier, tmp;
+
+ if (fwi > 14)
+ fwi = 14;
+
+ multiplier = 1 << fwi; /* 2 to the power of fwi */
+
+ /* ISO 14443-4:2000(E) Section 7.2.:
+ * (256*16 / h->l2h->rh->ah->fc) * (2 ^ fwi) */
+
+ tmp = (unsigned int) 1000000 * 256 * 16;
+
+ return (tmp / h->l2h->rh->ah->fc) * multiplier;
+}
+
+/* 4.9seconds as microseconds (4.9 billion seconds) exceeds 2^32 */
+#define activation_fwt(x) (((u_int64_t)1000000 * 65536 / x->l2h->rh->ah->fc))
+#define deactivation_fwt(x) activation_fwt(x)
+
+static int
+tcl_parse_ats(struct rfid_protocol_handle *h,
+ unsigned char *ats, unsigned int size)
+{
+ unsigned char len = ats[0];
+ unsigned char t0;
+ unsigned char *cur;
+
+ if (len == 0 || size == 0)
+ return -1;
+
+ if (size < len)
+ len = size;
+
+ h->priv.tcl.ta = 0;
+
+ if (len == 1) {
+ /* FIXME: assume some default values */
+ h->priv.tcl.fsc = 32;
+ h->priv.tcl.ta = 0x80; /* 0x80 (same d for both dirs) */
+ h->priv.tcl.sfgt = sfgi_to_sfgt(h, 0);
+ if (h->l2h->l2->id == RFID_LAYER2_ISO14443A) {
+ /* Section 7.2: fwi default for type A is 4 */
+ h->priv.tcl.fwt = fwi_to_fwt(h, 4);
+ } else {
+ /* Section 7.2: fwi for type B is always in ATQB */
+ /* Value is assigned in tcl_connect() */
+ /* This function is never called for Type B, since it has no (R)ATS */
+ }
+ return 0;
+ }
+
+ /* guarateed to be at least 2 bytes in size */
+
+ t0 = ats[1];
+ cur = &ats[2];
+
+ iso14443_fsdi_to_fsd(&h->priv.tcl.fsc, t0 & 0x0f);
+
+ if (t0 & (1 << 4)) {
+ /* TA is transmitted */
+ h->priv.tcl.ta = *cur++;
+ }
+
+ if (t0 & (1 << 5)) {
+ /* TB is transmitted */
+ h->priv.tcl.sfgt = sfgi_to_sfgt(h, *cur & 0x0f);
+ h->priv.tcl.fwt = fwi_to_fwt(h, (*cur & 0xf0) >> 4);
+ cur++;
+ }
+
+ if (t0 & (1 << 6)) {
+ /* TC is transmitted */
+ if (*cur & 0x01)
+ h->priv.tcl.flags |= TCL_HANDLE_F_NAD_SUPPORTED;
+ if (*cur & 0x02)
+ h->priv.tcl.flags |= TCL_HANDLE_F_CID_SUPPORTED;
+ cur++;
+ }
+
+ h->priv.tcl.historical_len = (ats+len) - cur;
+ h->priv.tcl.historical_bytes = cur;
+
+ return 0;
+}
+
+
+/* request an ATS from the PICC */
+static int
+tcl_request_ats(struct rfid_protocol_handle *h)
+{
+ int ret;
+ unsigned char rats[2];
+ unsigned char fsdi;
+
+ if (h->priv.tcl.state != TCL_STATE_INITIAL)
+ return -1;
+
+ ret = iso14443_fsd_to_fsdi(&fsdi, h->priv.tcl.fsd);
+ if (ret < 0) {
+ DEBUGP("unable to encode FSD of %u as FSDI\n", h->priv.tcl.fsd);
+ return ret;
+ }
+
+ rats[0] = 0xe0;
+ rats[1] = (h->priv.tcl.cid & 0x0f) | ((fsdi << 4) & 0xf0);
+
+ /* transcieve (with CRC) */
+ ret = rfid_layer2_transcieve(h->l2h, RFID_14443A_FRAME_REGULAR,
+ rats, 2, h->priv.tcl.ats,
+ &h->priv.tcl.ats_len, activation_fwt(h),
+ TCL_TRANSP_F_TX_CRC);
+ if (ret < 0) {
+ DEBUGP("transcieve of rats failed\n");
+ h->priv.tcl.state = TCL_STATE_RATS_SENT;
+ /* FIXME: retransmit */
+ return ret;
+ }
+ h->priv.tcl.state = TCL_STATE_ATS_RCVD;
+
+ ret = tcl_parse_ats(h, h->priv.tcl.ats, h->priv.tcl.ats_len);
+ if (ret < 0) {
+ DEBUGP("parsing of ats failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+#define ATS_TA_DIV_2 1
+#define ATS_TA_DIV_4 2
+#define ATS_TA_DIV_8 4
+
+#define PPS_DIV_8 3
+#define PPS_DIV_4 2
+#define PPS_DIV_2 1
+#define PPS_DIV_1 0
+static unsigned char d_to_di(struct rfid_protocol_handle *h, unsigned char D)
+{
+ static char DI;
+ unsigned int speed = h->l2h->rh->reader->iso14443a.speed;
+
+ if ((D & ATS_TA_DIV_8) && (speed & RFID_14443A_SPEED_848K))
+ DI = PPS_DIV_8;
+ else if ((D & ATS_TA_DIV_4) && (speed & RFID_14443A_SPEED_424K))
+ DI = PPS_DIV_4;
+ else if ((D & ATS_TA_DIV_2) && (speed & RFID_14443A_SPEED_212K))
+ DI = PPS_DIV_2;
+ else
+ DI = PPS_DIV_1;
+
+ return DI;
+}
+
+static unsigned int di_to_speed(unsigned char DI)
+{
+ switch (DI) {
+ case PPS_DIV_8:
+ return RFID_14443A_SPEED_848K;
+ break;
+ case PPS_DIV_4:
+ return RFID_14443A_SPEED_424K;
+ break;
+ case PPS_DIV_2:
+ return RFID_14443A_SPEED_212K;
+ break;
+ case PPS_DIV_1:
+ return RFID_14443A_SPEED_106K;
+ break;
+ }
+}
+
+/* start a PPS run (autimatically configure highest possible speed */
+static int
+tcl_do_pps(struct rfid_protocol_handle *h)
+{
+ int ret;
+ unsigned char ppss[3];
+ unsigned char pps_response[1];
+ unsigned int rx_len = 1;
+ unsigned char Dr, Ds, DrI, DsI;
+ unsigned int speed;
+
+ if (h->priv.tcl.state != TCL_STATE_ATS_RCVD)
+ return -1;
+
+ Dr = h->priv.tcl.ta & 0x07;
+ Ds = h->priv.tcl.ta & 0x70 >> 4;
+ DEBUGP("Dr = 0x%x, Ds = 0x%x\n", Dr, Ds);
+
+ if (Dr != Ds && !(h->priv.tcl.ta & 0x80)) {
+ /* device supports different divisors for rx and tx, but not
+ * really ?!? */
+ DEBUGP("PICC has contradictory TA, aborting PPS\n");
+ return -1;
+ };
+
+ /* ISO 14443-4:2000(E) Section 5.3. */
+
+ ppss[0] = 0xd0 | (h->priv.tcl.cid & 0x0f);
+ ppss[1] = 0x11;
+ ppss[2] = 0x00;
+
+ /* FIXME: deal with different speed for each direction */
+ DrI = d_to_di(h, Dr);
+ DsI = d_to_di(h, Ds);
+ DEBUGP("DrI = 0x%x, DsI = 0x%x\n", DrI, DsI);
+
+ ppss[2] = (ppss[2] & 0xf0) | (DrI | DsI << 2);
+
+ ret = rfid_layer2_transcieve(h->l2h, RFID_14443A_FRAME_REGULAR,
+ ppss, 3, pps_response, &rx_len,
+ h->priv.tcl.fwt, TCL_TRANSP_F_TX_CRC);
+ if (ret < 0)
+ return ret;
+
+ if (pps_response[0] != ppss[0]) {
+ DEBUGP("PPS Response != PPSS\n");
+ return -1;
+ }
+
+ speed = di_to_speed(DrI);
+
+ ret = rfid_layer2_setopt(h->l2h, RFID_OPT_14443A_SPEED_RX,
+ &speed, sizeof(speed));
+ if (ret < 0)
+ return ret;
+
+ ret = rfid_layer2_setopt(h->l2h, RFID_OPT_14443A_SPEED_TX,
+ &speed, sizeof(speed));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+
+static int
+tcl_build_prologue2(struct tcl_handle *th,
+ unsigned char *prlg, unsigned int *prlg_len,
+ unsigned char pcb)
+{
+ *prlg_len = 1;
+
+ *prlg = pcb;
+
+ if (th->toggle) {
+ /* we've sent a toggle bit last time */
+ th->toggle = 0;
+ } else {
+ /* we've not sent a toggle last time: send one */
+ th->toggle = 1;
+ *prlg |= 0x01;
+ }
+
+ if (th->flags & TCL_HANDLE_F_CID_USED) {
+ /* ISO 14443-4:2000(E) Section 7.1.1.2 */
+ *prlg |= TCL_PCB_CID_FOLLOWING;
+ (*prlg_len)++;
+ prlg[*prlg_len] = th->cid & 0x0f;
+ }
+
+ /* nad only for I-block (0xc0 == 00) */
+ if ((th->flags & TCL_HANDLE_F_NAD_USED) &&
+ ((pcb & 0xc0) == 0x00)) {
+ /* ISO 14443-4:2000(E) Section 7.1.1.3 */
+ /* FIXME: in case of chaining only for first frame */
+ *prlg |= TCL_PCB_NAD_FOLLOWING;
+ prlg[*prlg_len] = th->nad;
+ (*prlg_len)++;
+ }
+
+ return 0;
+}
+
+static int
+tcl_build_prologue_i(struct tcl_handle *th,
+ unsigned char *prlg, unsigned int *prlg_len)
+{
+ /* ISO 14443-4:2000(E) Section 7.1.1.1 */
+ return tcl_build_prologue2(th, prlg, prlg_len, 0x02);
+}
+
+static int
+tcl_build_prologue_r(struct tcl_handle *th,
+ unsigned char *prlg, unsigned int *prlg_len,
+ unsigned int nak)
+{
+ unsigned char pcb = 0xa2;
+ /* ISO 14443-4:2000(E) Section 7.1.1.1 */
+
+ if (nak)
+ pcb |= 0x10;
+
+ return tcl_build_prologue2(th, prlg, prlg_len, pcb);
+}
+
+static int
+tcl_build_prologue_s(struct tcl_handle *th,
+ unsigned char *prlg, unsigned int *prlg_len)
+{
+ /* ISO 14443-4:2000(E) Section 7.1.1.1 */
+
+ /* the only S-block from PCD->PICC is DESELECT,
+ * well, actually there is the S(WTX) response. */
+ return tcl_build_prologue2(th, prlg, prlg_len, 0xc2);
+}
+
+/* FIXME: WTXM implementation */
+
+static int tcl_prlg_len(struct tcl_handle *th)
+{
+ int prlg_len = 1;
+
+ if (th->flags & TCL_HANDLE_F_CID_USED)
+ prlg_len++;
+
+ if (th->flags & TCL_HANDLE_F_NAD_USED)
+ prlg_len++;
+
+ return prlg_len;
+}
+
+#define max_net_tx_framesize(x) (x->fsc - tcl_prlg_len(x))
+
+static int
+tcl_connect(struct rfid_protocol_handle *h)
+{
+ int ret;
+
+ if (h->priv.tcl.state != TCL_STATE_DESELECTED &&
+ h->priv.tcl.state != TCL_STATE_INITIAL)
+ return -1;
+
+ switch (h->l2h->l2->id) {
+ case RFID_LAYER2_ISO14443A:
+ /* Start Type A T=CL Activation Sequence */
+ ret = tcl_request_ats(h);
+ if (ret < 0)
+ return ret;
+
+ /* Only do PPS if any non-default divisors supported */
+ if (h->priv.tcl.ta & 0x77) {
+ ret = tcl_do_pps(h);
+ if (ret < 0)
+ return ret;
+ }
+ break;
+ case RFID_LAYER2_ISO14443B:
+ /* initialized T=CL state from Type B Activation Data */
+ h->priv.tcl.cid = h->l2h->priv.iso14443b.cid;
+ h->priv.tcl.fsc = h->l2h->priv.iso14443b.fsc;
+ h->priv.tcl.fsd = h->l2h->priv.iso14443b.fsd;
+ h->priv.tcl.fwt = h->l2h->priv.iso14443b.fwt;
+
+ /* what about ta? sfgt? */
+
+ if (h->l2h->priv.iso14443b.flags & ISO14443B_CID_SUPPORTED)
+ h->priv.tcl.flags |= TCL_HANDLE_F_CID_SUPPORTED;
+ if (h->l2h->priv.iso14443b.flags & ISO14443B_NAD_SUPPORTED)
+ h->priv.tcl.flags |= TCL_HANDLE_F_NAD_SUPPORTED;
+
+ switch (h->l2h->priv.iso14443b.state) {
+ case ISO14443B_STATE_SELECTED:
+ h->priv.tcl.state = TCL_STATE_ATS_RCVD;
+ break;
+ case ISO14443B_STATE_ATTRIB_SENT:
+ h->priv.tcl.state = TCL_STATE_RATS_SENT;
+ break;
+ }
+
+ /* PUPI will be presented as ATS/historical bytes */
+ memcpy(h->priv.tcl.ats, h->l2h->uid, 4);
+ h->priv.tcl.ats_len = 4;
+ h->priv.tcl.historical_bytes = h->priv.tcl.ats;
+
+ break;
+ default:
+ DEBUGP("unsupported l2: %u\n", h->l2h->l2->id);
+ return -1;
+ break;
+ }
+
+ h->priv.tcl.state = TCL_STATE_ESTABLISHED;
+
+ 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 = rfid_layer2_transcieve(h->l2h, RFID_14443A_FRAME_REGULAR,
+ frame, prlg_len, rx,
+ &rx_len, deactivation_fwt(h),
+ TCL_TRANSP_F_TX_CRC);
+ if (ret < 0) {
+ /* FIXME: retransmit, HLT(A|B) */
+ return ret;
+ }
+
+ th->state = TCL_STATE_DESELECTED;
+
+ return 0;
+}
+
+#define is_s_block(x) ((x & 0xc0) == 0xc0)
+#define is_r_block(x) ((x & 0xc0) == 0x80)
+#define is_i_block(x) ((x & 0xc0) == 0x00)
+
+static int
+tcl_transcieve(struct rfid_protocol_handle *h,
+ const unsigned char *tx_data, unsigned int tx_len,
+ unsigned char *rx_data, unsigned int *rx_len,
+ unsigned int timeout, unsigned int flags)
+{
+ int ret;
+ unsigned char *tx_buf, *rx_buf;
+ unsigned char *_rx_data = rx_data;
+ unsigned int _rx_len;
+ unsigned int max_rx_len = *rx_len; /* maximum number of payoload that
+ caller has requested */
+ unsigned int prlg_len;
+ struct tcl_handle *th = &h->priv.tcl;
+
+ unsigned char *_tx;
+ unsigned int _tx_len, _timeout;
+ unsigned char wtx_resp[3];
+ unsigned char ack[10];
+ unsigned int ack_len;
+
+ if (tx_len > max_net_tx_framesize(th)) {
+ /* slow path: we need to use chaining */
+ return -1;
+ }
+
+ tx_buf = malloc(tcl_prlg_len(th) + tx_len);
+ if (!tx_buf) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ rx_buf = malloc(tcl_prlg_len(th) + *rx_len);
+ if (!rx_buf) {
+ ret = -ENOMEM;
+ goto out_txb;
+ }
+
+ if (tcl_build_prologue_i(th, tx_buf, &prlg_len) < 0) {
+ ret = -1;
+ goto out_rxb;
+ }
+ memcpy(tx_buf + prlg_len, tx_data, tx_len);
+
+ /* intialize to data-to-be-transferred */
+ _tx = tx_buf;
+ _tx_len = tx_len+prlg_len;
+ _timeout = th->fwt;
+ _rx_len = *rx_len;
+ *rx_len = 0;
+
+do_tx:
+ ret = rfid_layer2_transcieve(h->l2h, l2_to_frame(h->l2h->l2->id),
+ _tx, _tx_len,
+ rx_buf, &_rx_len, _timeout, 0);
+ DEBUGP("l2 transcieve finished\n");
+ if (ret < 0)
+ goto out_rxb;
+
+ if ((*rx_buf & 0x01) != h->priv.tcl.toggle) {
+ DEBUGP("response with wrong toggle bit\n");
+ goto out_rxb;
+ }
+
+ if (is_r_block(*rx_buf)) {
+ unsigned int txed = _tx - tx_buf;
+ DEBUGP("R-Block\n");
+ /* Handle ACK frame in case of chaining */
+ if (*rx_buf & TCL_PCB_CID_FOLLOWING) {
+ if (*(rx_buf+1) != h->priv.tcl.cid) {
+ DEBUGP("CID %u is not valid\n", *(rx_buf)+1);
+ goto out_rxb;
+ }
+ }
+ /* set up parameters for next frame in chain */
+ if (txed < tx_len) {
+ /* move tx pointer by the amount of bytes transferred
+ * in last frame */
+ _tx += _tx_len;
+ _tx_len = (tx_len - txed);
+ if (_tx_len > max_net_tx_framesize(th)) {
+ /* not last frame in chain */
+ _tx_len = max_net_tx_framesize(th);
+ } else {
+ /* last frame in chain */
+ }
+ goto do_tx;
+ } else {
+ DEBUGP("Received ACK in response to last frame in "
+ "chain?!? Expected I-frame.\n");
+ ret = -1;
+ goto out_rxb;
+ }
+ } else if (is_s_block(*rx_buf)) {
+ unsigned char inf;
+ unsigned int prlg_len;
+
+ DEBUGP("S-Block\n");
+ /* Handle Wait Time Extension */
+ if (*rx_buf & TCL_PCB_CID_FOLLOWING) {
+ if (_rx_len < 3) {
+ DEBUGP("S-Block with CID but short len\n");
+ ret = -1;
+ goto out_rxb;
+ }
+ if (*(rx_buf+1) != h->priv.tcl.cid) {
+ DEBUGP("CID %u is not valid\n", *(rx_buf)+1);
+ goto out_rxb;
+ }
+ inf = *(rx_buf+2);
+ } else
+ inf = *(rx_buf+1);
+
+ if ((*rx_buf & 0x30) != 0x30) {
+ DEBUGP("S-Block but not WTX?\n");
+ ret = -1;
+ goto out_rxb;
+ }
+ inf &= 0x3f; /* only lower 6 bits code WTXM */
+ if (inf == 0 || (inf >= 60 && inf <= 63)) {
+ DEBUGP("WTXM %u is RFU!\n", inf);
+ ret = -1;
+ goto out_rxb;
+ }
+
+ /* Acknowledge WTXM */
+ tcl_build_prologue_s(&h->priv.tcl, wtx_resp, &prlg_len);
+ /* set two bits that make this block a wtx */
+ wtx_resp[0] |= 0x30;
+ wtx_resp[prlg_len] = inf;
+ _tx = wtx_resp;
+ _tx_len = prlg_len+1;
+ _timeout = th->fwt * inf;
+
+ /* start over with next transcieve */
+ goto do_tx; /* FIXME: do transcieve locally since we use
+ totally different buffer */
+
+ } else if (is_i_block(*rx_buf)) {
+ unsigned char *inf = rx_buf+1;
+ unsigned int net_payload_len;
+ /* we're actually receiving payload data */
+
+ DEBUGP("I-Block: ");
+ if (*rx_buf & TCL_PCB_CID_FOLLOWING) {
+ if (*(rx_buf+1) != h->priv.tcl.cid) {
+ DEBUGPC("CID %u is not valid\n", *(rx_buf)+1);
+ goto out_rxb;
+ }
+ inf++;
+ }
+ if (*rx_buf & TCL_PCB_NAD_FOLLOWING) {
+ inf++;
+ }
+ net_payload_len = _rx_len - (inf - rx_buf);
+ DEBUGPC("%u bytes\n", net_payload_len);
+ memcpy(_rx_data, inf, net_payload_len);
+ /* increment the number of payload bytes that we actually
+ * received */
+ *rx_len += net_payload_len;
+ _rx_data += net_payload_len;
+
+ if (*rx_buf & 0x10) {
+ /* we're not the last frame in the chain, continue rx */
+ DEBUGP("not the last frame in the chain, continue\n");
+ ack_len = sizeof(ack);
+ tcl_build_prologue_r(&h->priv.tcl, ack, &ack_len, 0);
+ _tx = ack;
+ _tx_len = ack_len;
+ goto do_tx;
+ }
+ }
+
+out_rxb:
+ free(rx_buf);
+out_txb:
+ free(tx_buf);
+out:
+ return ret;
+}
+
+static struct rfid_protocol_handle *
+tcl_init(struct rfid_layer2_handle *l2h)
+{
+ struct rfid_protocol_handle *th;
+ unsigned int mru = l2h->rh->ah->mru;
+
+ th = malloc(sizeof(struct rfid_protocol_handle) + mru);
+ if (!th)
+ return NULL;
+
+ /* FIXME: mru should be attribute of layer2 (in case it adds/removes
+ * some overhead */
+ memset(th, 0, sizeof(struct rfid_protocol_handle) + mru);
+
+ /* maximum received ats length equals mru of asic/reader */
+ th->priv.tcl.state = TCL_STATE_INITIAL;
+ th->priv.tcl.ats_len = mru;
+ th->priv.tcl.toggle = 1;
+
+ th->priv.tcl.fsd = iso14443_fsd_approx(mru);
+
+ return th;
+}
+
+static int
+tcl_fini(struct rfid_protocol_handle *ph)
+{
+ free(ph);
+ return 0;
+}
+
+struct rfid_protocol rfid_protocol_tcl = {
+ .id = RFID_PROTOCOL_TCL,
+ .name = "ISO 14443-4 / T=CL",
+ .fn = {
+ .init = &tcl_init,
+ .open = &tcl_connect,
+ .transcieve = &tcl_transcieve,
+ .close = &tcl_deselect,
+ .fini = &tcl_fini,
+ },
+};
--- /dev/null
+/* librfid - layer 3 protocol handler
+ * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <librfid/rfid_layer2.h>
+#include <librfid/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;
+ struct rfid_protocol_handle *ph = NULL;
+
+ for (p = rfid_protocol_list; p; p = p->next) {
+ if (p->id == id) {
+ ph = p->fn.init(l2h);
+ break;
+ }
+ }
+
+ if (!ph)
+ return NULL;
+
+ ph->proto = p;
+ ph->l2h = l2h;
+
+ return ph;
+}
+
+int
+rfid_protocol_open(struct rfid_protocol_handle *ph)
+{
+ if (ph->proto->fn.open)
+ return ph->proto->fn.open(ph);
+ return 0;
+}
+
+int
+rfid_protocol_transcieve(struct rfid_protocol_handle *ph,
+ const unsigned char *tx_buf, unsigned int len,
+ unsigned char *rx_buf, unsigned int *rx_len,
+ unsigned int timeout, unsigned int flags)
+{
+ return ph->proto->fn.transcieve(ph, tx_buf, len, rx_buf, rx_len,
+ timeout, flags);
+}
+
+int
+rfid_protocol_read(struct rfid_protocol_handle *ph,
+ unsigned int page,
+ unsigned char *rx_data,
+ unsigned int *rx_len)
+{
+ if (ph->proto->fn.read)
+ return ph->proto->fn.read(ph, page, rx_data, rx_len);
+ else
+ return -EINVAL;
+}
+
+int
+rfid_protocol_write(struct rfid_protocol_handle *ph,
+ unsigned int page,
+ unsigned char *tx_data,
+ unsigned int tx_len)
+{
+ if (ph->proto->fn.write)
+ return ph->proto->fn.write(ph, page, tx_data, tx_len);
+ else
+ return -EINVAL;
+}
+
+int rfid_protocol_fini(struct rfid_protocol_handle *ph)
+{
+ return ph->proto->fn.fini(ph);
+}
+
+int
+rfid_protocol_close(struct rfid_protocol_handle *ph)
+{
+ if (ph->proto->fn.close)
+ return ph->proto->fn.close(ph);
+ return 0;
+}
+
+int
+rfid_protocol_register(struct rfid_protocol *p)
+{
+ p->next = rfid_protocol_list;
+ rfid_protocol_list = p;
+
+ return 0;
+}
--- /dev/null
+/* librfid - core reader handling
+ * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <librfid/rfid.h>
+#include <librfid/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,
+ enum rfid_frametype frametype,
+ const unsigned char *tx_buf, unsigned int len,
+ unsigned char *rx_buf, unsigned int *rx_len,
+ u_int64_t timeout, unsigned int flags)
+{
+ return rh->reader->transcieve(rh, frametype, tx_buf, len, rx_buf,
+ rx_len, timeout, flags);
+}
+
+void
+rfid_reader_close(struct rfid_reader_handle *rh)
+{
+ rh->reader->close(rh);
+}
+
+int
+rfid_reader_register(struct rfid_reader *r)
+{
+ r->next = rfid_reader_list;
+ rfid_reader_list = r;
+
+ return 0;
+}
--- /dev/null
+/* Omnikey CardMan 5121 specific RC632 transport layer
+ *
+ * (C) 2005 by Harald Welte <laforge@gnumonks.org>
+ *
+ * The 5121 is an Atmel AT89C5122 based USB CCID reader (probably the same
+ * design like the 3121). It's CL RC632 is connected via address/data bus,
+ * not via SPI.
+ *
+ * The vendor-supplied reader firmware provides some undocumented extensions
+ * to CCID (via PC_to_RDR_Escape) that allow access to registers and FIFO of
+ * the RC632.
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <librfid/rfid.h>
+#include <librfid/rfid_reader.h>
+#include <librfid/rfid_asic.h>
+#include <librfid/rfid_asic_rc632.h>
+#include <librfid/rfid_reader_cm5121.h>
+
+/* FIXME */
+#include "rc632.h"
+
+//#define SENDBUF_LEN 40
+#define SENDBUF_LEN 100
+#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: ", reg, value);
+
+ if (PC_to_RDR_Escape(rath->data, sndbuf, 8, rcvbuf,
+ &retlen) == 0) {
+ DEBUGPC("OK\n");
+ return 0;
+ }
+
+ DEBUGPC("ERROR\n");
+ return -1;
+}
+
+static int Read1ByteFromReg(struct rfid_asic_transport_handle *rath,
+ unsigned char reg,
+ unsigned char *value)
+{
+ unsigned char sndbuf[SENDBUF_LEN];
+ unsigned char recvbuf[RECVBUF_LEN];
+ unsigned int retlen = sizeof(recvbuf);
+
+ sndbuf[0] = 0x20;
+ sndbuf[1] = 0x00;
+ sndbuf[2] = 0x00;
+ sndbuf[3] = 0x00;
+ sndbuf[4] = 0x01;
+ sndbuf[5] = 0x00;
+ sndbuf[6] = reg;
+
+ if (PC_to_RDR_Escape(rath->data, sndbuf, 7, recvbuf,
+ &retlen) == 0) {
+ *value = recvbuf[1];
+ DEBUGP("reg=0x%02x, val=%02x: ", reg, *value);
+ DEBUGPC("OK\n");
+ return 0;
+ }
+
+ DEBUGPC("ERROR\n");
+ return -1;
+}
+
+static int ReadNBytesFromFIFO(struct rfid_asic_transport_handle *rath,
+ unsigned char num_bytes,
+ unsigned char *buf)
+{
+ unsigned char sndbuf[SENDBUF_LEN];
+ unsigned char recvbuf[0x7f];
+ unsigned int retlen = sizeof(recvbuf);
+
+ sndbuf[0] = 0x20;
+ sndbuf[1] = 0x00;
+ sndbuf[2] = 0x00;
+ sndbuf[3] = 0x00;
+ sndbuf[4] = num_bytes;
+ sndbuf[5] = 0x00;
+ sndbuf[6] = 0x02;
+
+ DEBUGP("num_bytes=%u: ", num_bytes);
+ if (PC_to_RDR_Escape(rath->data, sndbuf, 7, recvbuf, &retlen) == 0) {
+ DEBUGPC("%u [%s]\n", retlen,
+ rfid_hexdump(recvbuf+1, num_bytes));
+ memcpy(buf, recvbuf+1, num_bytes); // len == 0x7f
+ return 0;
+ }
+
+ DEBUGPC("ERROR\n");
+ return -1;
+}
+
+static int WriteNBytesToFIFO(struct rfid_asic_transport_handle *rath,
+ unsigned char len,
+ const unsigned char *bytes,
+ unsigned char flags)
+{
+ unsigned char sndbuf[SENDBUF_LEN];
+ unsigned char recvbuf[0x7f];
+ unsigned int retlen = sizeof(recvbuf);
+
+ sndbuf[0] = 0x20;
+ sndbuf[1] = 0x00;
+ sndbuf[2] = len;
+ sndbuf[3] = 0x00;
+ sndbuf[4] = 0x00;
+ sndbuf[5] = flags;
+ sndbuf[6] = 0x02;
+
+ DEBUGP("%u [%s]: ", len, rfid_hexdump(bytes, len));
+
+ memcpy(sndbuf+7, bytes, len);
+
+ if (PC_to_RDR_Escape(rath->data, sndbuf, len+7, recvbuf, &retlen) == 0) {
+ DEBUGPC("OK (%u [%s])\n", retlen, rfid_hexdump(recvbuf, retlen));
+ return 0;
+ }
+
+ DEBUGPC("ERROR\n");
+ return -1;
+}
+
+#if 0
+static int TestFIFO(struct rc632_handle *handle)
+{
+ unsigned char sndbuf[60]; // 0x3c
+
+ // FIXME: repne stosd, call
+
+ memset(sndbuf, 0, sizeof(sndbuf));
+
+ if (WriteNBytesToFIFO(handle, sizeof(sndbuf), sndbuf, 0) < 0)
+ return -1;
+
+ return ReadNBytesFromFIFO(handle, sizeof(sndbuf), sndbuf);
+}
+#endif
+
+static int cm5121_transcieve(struct rfid_reader_handle *rh,
+ enum rfid_frametype frametype,
+ const unsigned char *tx_data, unsigned int tx_len,
+ unsigned char *rx_data, unsigned int *rx_len,
+ u_int64_t timeout, unsigned int flags)
+{
+ return rh->ah->asic->priv.rc632.fn.transcieve(rh->ah, frametype,
+ tx_data, tx_len, rx_data,
+ rx_len, timeout, flags);
+}
+
+static int cm5121_transcieve_sf(struct rfid_reader_handle *rh,
+ unsigned char cmd, struct iso14443a_atqa *atqa)
+{
+ return rh->ah->asic->priv.rc632.fn.iso14443a.transcieve_sf(rh->ah,
+ cmd,
+ atqa);
+}
+
+static int
+cm5121_transcieve_acf(struct rfid_reader_handle *rh,
+ struct iso14443a_anticol_cmd *cmd,
+ unsigned int *bit_of_col)
+{
+ return rh->ah->asic->priv.rc632.fn.iso14443a.transcieve_acf(rh->ah,
+ cmd, bit_of_col);
+}
+
+static int
+cm5121_14443a_init(struct rfid_reader_handle *rh)
+{
+ return rh->ah->asic->priv.rc632.fn.iso14443a.init(rh->ah);
+}
+
+static int
+cm5121_14443a_set_speed(struct rfid_reader_handle *rh,
+ unsigned int tx,
+ unsigned int speed)
+{
+ u_int8_t rate;
+
+ DEBUGP("setting rate: ");
+ switch (speed) {
+ case RFID_14443A_SPEED_106K:
+ rate = 0x00;
+ DEBUGPC("106K\n");
+ break;
+ case RFID_14443A_SPEED_212K:
+ rate = 0x01;
+ DEBUGPC("212K\n");
+ break;
+ case RFID_14443A_SPEED_424K:
+ rate = 0x02;
+ DEBUGPC("424K\n");
+ break;
+ case RFID_14443A_SPEED_848K:
+ rate = 0x03;
+ DEBUGPC("848K\n");
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ return rh->ah->asic->priv.rc632.fn.iso14443a.set_speed(rh->ah,
+ tx, rate);
+}
+
+static int
+cm5121_14443b_init(struct rfid_reader_handle *rh)
+{
+ return rh->ah->asic->priv.rc632.fn.iso14443b.init(rh->ah);
+}
+
+static int
+cm5121_15693_init(struct rfid_reader_handle *rh)
+{
+ return rh->ah->asic->priv.rc632.fn.iso15693.init(rh->ah);
+}
+
+static int
+cm5121_mifare_setkey(struct rfid_reader_handle *rh, const u_int8_t *key)
+{
+ return rh->ah->asic->priv.rc632.fn.mifare_classic.setkey(rh->ah, key);
+}
+
+static int
+cm5121_mifare_auth(struct rfid_reader_handle *rh, u_int8_t cmd,
+ u_int32_t serno, u_int8_t block)
+{
+ return rh->ah->asic->priv.rc632.fn.mifare_classic.auth(rh->ah,
+ cmd, serno, block);
+}
+
+struct rfid_asic_transport cm5121_ccid = {
+ .name = "CM5121 OpenCT",
+ .priv.rc632 = {
+ .fn = {
+ .reg_write = &Write1ByteToReg,
+ .reg_read = &Read1ByteFromReg,
+ .fifo_write = &WriteNBytesToFIFO,
+ .fifo_read = &ReadNBytesFromFIFO,
+ },
+ },
+};
+
+static int cm5121_enable_rc632(struct rfid_asic_transport_handle *rath)
+{
+ unsigned char tx_buf[1] = { 0x01 };
+ unsigned char rx_buf[64];
+ unsigned int rx_len = sizeof(rx_buf);
+
+ PC_to_RDR_Escape(rath->data, tx_buf, 1, rx_buf, &rx_len);
+ printf("received %u bytes from 01 command\n", rx_len);
+
+ return 0;
+}
+
+static struct rfid_reader_handle *
+cm5121_open(void *data)
+{
+ struct rfid_reader_handle *rh;
+ struct rfid_asic_transport_handle *rath;
+
+ rh = malloc(sizeof(*rh));
+ if (!rh)
+ return NULL;
+ memset(rh, 0, sizeof(*rh));
+
+ rath = malloc(sizeof(*rath));
+ if (!rath)
+ goto out_rh;
+ memset(rath, 0, sizeof(*rath));
+
+ rath->rat = &cm5121_ccid;
+ rh->reader = &rfid_reader_cm5121;
+
+ if (cm5121_source_init(rath) < 0)
+ goto out_rath;
+
+ if (cm5121_enable_rc632(rath) < 0)
+ goto out_rath;
+
+ rh->ah = rc632_open(rath);
+ if (!rh->ah)
+ goto out_rath;
+
+ DEBUGP("returning %p\n", rh);
+ return rh;
+
+out_rath:
+ free(rath);
+out_rh:
+ free(rh);
+
+ return NULL;
+}
+
+static void
+cm5121_close(struct rfid_reader_handle *rh)
+{
+ struct rfid_asic_transport_handle *rath = rh->ah->rath;
+ rc632_close(rh->ah);
+ free(rath);
+ free(rh);
+}
+
+struct rfid_reader rfid_reader_cm5121 = {
+ .name = "Omnikey CardMan 5121 RFID",
+ .open = &cm5121_open,
+ .close = &cm5121_close,
+ .transcieve = &cm5121_transcieve,
+ .iso14443a = {
+ .init = &cm5121_14443a_init,
+ .transcieve_sf = &cm5121_transcieve_sf,
+ .transcieve_acf = &cm5121_transcieve_acf,
+ .speed = RFID_14443A_SPEED_106K | RFID_14443A_SPEED_212K |
+ RFID_14443A_SPEED_424K, //| RFID_14443A_SPEED_848K,
+ .set_speed = &cm5121_14443a_set_speed,
+ },
+ .iso14443b = {
+ .init = &cm5121_14443b_init,
+ },
+ .mifare_classic = {
+ .setkey = &cm5121_mifare_setkey,
+ .auth = &cm5121_mifare_auth,
+ },
+};
+
+
--- /dev/null
+/* CM5121 backend for 'internal' CCID driver */
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include <librfid/rfid_asic.h>
+
+#include "ccid/ccid-driver.h"
+
+/* this is the sole function required by rfid_reader_cm5121.c */
+int
+PC_to_RDR_Escape(void *handle,
+ const unsigned char *tx_buf, unsigned int tx_len,
+ unsigned char *rx_buf, unsigned int *rx_len)
+{
+ int rc;
+ ccid_driver_t ch = handle;
+ size_t maxrxlen = *rx_len;
+
+ rc = ccid_transceive_escape (ch, tx_buf, tx_len,
+ rx_buf, maxrxlen, rx_len);
+
+ return rc;
+}
+
+int cm5121_source_init(struct rfid_asic_transport_handle *rath)
+{
+ int rc;
+
+ rc = ccid_open_reader(&rath->data, NULL);
+ if (rc) {
+ fprintf (stderr, "failed to open CCID reader: %#x\n", rc);
+ return -1;
+ }
+ return 0;
+}
--- /dev/null
+/* CM5121 backend for OpenCT virtual slot */
+
+#include <stdio.h>
+
+#include <librfid/rfid_asic.h>
+#include <openct/openct.h>
+
+/* FIXME: get rid of this global crap. In fact this needs to become part of
+ * struct rfid_reader_handle */
+static ct_lock_handle lock;
+static int slot = 1;
+
+/* this is the sole function required by rfid_reader_cm5121.c */
+int
+PC_to_RDR_Escape(void *handle,
+ const unsigned char *tx_buf, unsigned int tx_len,
+ unsigned char *rx_buf, unsigned int *rx_len)
+{
+ int rc;
+ ct_handle *h = (ct_handle *) handle;
+
+ rc = ct_card_transact(h, 1, tx_buf, tx_len, rx_buf, *rx_len);
+ if (rc >= 0) {
+ *rx_len = rc;
+ return 0;
+ }
+
+ return rc;
+}
+
+
+int cm5121_source_init(struct rfid_asic_transport_handle *rath)
+{
+ struct ct_handle *h;
+ int rc;
+ unsigned char atr[64];
+
+ h = ct_reader_connect(0);
+ if (!h)
+ return -1;
+
+ printf("acquiring card lock\n");
+ rc = ct_card_lock(h, slot, IFD_LOCK_EXCLUSIVE, &lock);
+ if (rc < 0) {
+ fprintf(stderr, "error, no card lock\n");
+ return -1;
+ }
+
+ rc = ct_card_reset(h, slot, atr, sizeof(atr));
+ if (rc < 0) {
+ fprintf(stderr, "error, can't reset virtual card\n");
+ return -1;
+ }
+
+ rath->data = h;
+
+ return 0;
+}
+
--- /dev/null
+INCLUDES = $(all_includes) -I$(top_srcdir)/include
+
+bin_PROGRAMS = openct-escape
+
+openct_escape_SOURCES = openct-escape.c
+openct_escape_LDADD = ../src/librfid.la
+openct_escape_LDFLAGS = -dynamic
+
--- /dev/null
+/* -*- linux-c -*-
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <librfid/rfid.h>
+#include <librfid/rfid_reader.h>
+#include <librfid/rfid_layer2.h>
+#include <librfid/rfid_protocol.h>
+
+#include <librfid/rfid_protocol_mifare_classic.h>
+#include <librfid/rfid_protocol_mifare_ul.h>
+
+static const char *
+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;
+}
+
+static struct rfid_reader_handle *rh;
+static struct rfid_layer2_handle *l2h;
+static struct rfid_protocol_handle *ph;
+
+static int init()
+{
+ unsigned char buf[0x3f];
+ int rc;
+
+ printf("initializing librfid\n");
+ rfid_init();
+
+ printf("opening reader handle\n");
+ rh = rfid_reader_open(NULL, 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;
+ }
+
+ return 0;
+}
+
+static int l3(int protocol)
+{
+ printf("running layer3 (ats)\n");
+ ph = rfid_protocol_init(l2h, protocol);
+ 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;
+ }
+
+ printf("we now have layer3 up and running\n");
+
+ return 0;
+}
+
+static int select_mf(void)
+{
+ unsigned char cmd[] = { 0x00, 0xa4, 0x00, 0x00, 0x02, 0x3f, 0x00, 0x00 };
+ unsigned char ret[256];
+ unsigned int rlen = sizeof(ret);
+
+ int rv;
+
+ rv = rfid_protocol_transcieve(ph, cmd, sizeof(cmd), ret, &rlen, 0, 0);
+ if (rv < 0)
+ return rv;
+
+ printf("%d: [%s]\n", rlen, hexdump(ret, rlen));
+
+ return 0;
+}
+
+
+static int iso7816_get_challenge(unsigned char len)
+{
+ unsigned char cmd[] = { 0x00, 0x84, 0x00, 0x00, 0x08 };
+ unsigned char ret[256];
+ unsigned int rlen = sizeof(ret);
+
+ cmd[4] = len;
+
+ int rv;
+
+ rv = rfid_protocol_transcieve(ph, cmd, sizeof(cmd), ret, &rlen, 0, 0);
+ if (rv < 0)
+ return rv;
+
+ printf("%d: [%s]\n", rlen, hexdump(ret, rlen));
+
+ return 0;
+}
+
+int
+iso7816_select_application(void)
+{
+ unsigned char cmd[] = { 0x00, 0xa4, 0x04, 0x0c, 0x07,
+ 0xa0, 0x00, 0x00, 0x02, 0x47, 0x10, 0x01 };
+ unsigned char resp[7];
+ unsigned int rlen = sizeof(resp);
+
+ int rv;
+
+ rv = rfid_protocol_transcieve(ph, cmd, sizeof(cmd), resp, &rlen, 0, 0);
+ if (rv < 0)
+ return rv;
+
+ /* FIXME: parse response */
+ printf("%s\n", hexdump(resp, rlen));
+
+ return 0;
+}
+
+int
+iso7816_select_ef(u_int16_t fid)
+{
+ unsigned char cmd[7] = { 0x00, 0xa4, 0x02, 0x0c, 0x02, 0x00, 0x00 };
+ unsigned char resp[7];
+ unsigned int rlen = sizeof(resp);
+
+ int rv;
+
+ cmd[5] = (fid >> 8) & 0xff;
+ cmd[6] = fid & 0xff;
+
+ rv = rfid_protocol_transcieve(ph, cmd, sizeof(cmd), resp, &rlen, 0, 0);
+ if (rv < 0)
+ return rv;
+
+ /* FIXME: parse response */
+ printf("%s\n", hexdump(resp, rlen));
+
+ return 0;
+}
+
+int
+iso7816_read_binary(unsigned char *buf, unsigned int *len)
+{
+ unsigned char cmd[] = { 0x00, 0xb0, 0x00, 0x00, 0x00 };
+ unsigned char resp[256];
+ unsigned int rlen = sizeof(resp);
+
+ int rv;
+
+ rv = rfid_protocol_transcieve(ph, cmd, sizeof(cmd), resp, &rlen, 0, 0);
+ if (rv < 0)
+ return rv;
+
+ /* FIXME: parse response, determine whether we need additional reads */
+
+ /* FIXME: copy 'len' number of response bytes to 'buf' */
+ return 0;
+}
+
+/* wrapper function around SELECT EF and READ BINARY */
+int
+iso7816_read_ef(u_int16_t fid, unsigned char *buf, unsigned int *len)
+{
+ int rv;
+
+ rv = iso7816_select_ef(fid);
+ if (rv < 0)
+ return rv;
+
+ return iso7816_read_binary(buf, len);
+}
+
+/* mifare ultralight helpers */
+int
+mifare_ulight_write(struct rfid_protocol_handle *ph)
+{
+ unsigned char buf[4] = { 0xa1, 0xa2, 0xa3, 0xa4 };
+
+ return rfid_protocol_write(ph, 10, buf, 4);
+}
+
+int
+mifare_ulight_blank(struct rfid_protocol_handle *ph)
+{
+ unsigned char buf[4] = { 0x00, 0x00, 0x00, 0x00 };
+ int i, ret;
+
+ for (i = 4; i <= MIFARE_UL_PAGE_MAX; i++) {
+ ret = rfid_protocol_write(ph, i, buf, 4);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+static int
+mifare_ulight_read(struct rfid_protocol_handle *ph)
+{
+ unsigned char buf[20];
+ unsigned int len = sizeof(buf);
+ int ret;
+ int i;
+
+ for (i = 0; i <= MIFARE_UL_PAGE_MAX; i++) {
+ ret = rfid_protocol_read(ph, i, buf, &len);
+ if (ret < 0)
+ return ret;
+
+ printf("Page 0x%x: %s\n", i, hexdump(buf, 4));
+ }
+ return 0;
+}
+
+/* mifare classic helpers */
+static int
+mifare_classic_read(struct rfid_protocol_handle *ph)
+{
+ unsigned char buf[20];
+ unsigned int len = sizeof(buf);
+ int ret;
+ int i;
+
+ for (i = 0; i <= MIFARE_CL_PAGE_MAX; i++) {
+ ret = rfid_protocol_read(ph, i, buf, &len);
+ if (ret < 0)
+ return ret;
+
+ printf("Page 0x%x: %s\n", i, hexdump(buf, len));
+ }
+ return 0;
+}
+
+
+int main(int argc, char **argv)
+{
+ int rc;
+ char buf[0x40];
+ int i, protocol;
+
+#if 0
+ if (argc) {
+ argc--;
+ argv++;
+ }
+
+ while (argc) {
+ if ( !strcmp (*argv, "--list")) {
+ char *p;
+ p = ccid_get_reader_list ();
+ if (!p)
+ return 1;
+ fputs (p, stderr);
+ free (p);
+ return 0;
+ }
+ else if ( !strcmp (*argv, "--debug")) {
+ ccid_set_debug_level (ccid_set_debug_level (-1) + 1);
+ argc--; argv++;
+ }
+ else
+ break;
+ }
+#endif
+
+ if (init() < 0)
+ exit(1);
+
+ //protocol = RFID_PROTOCOL_MIFARE_UL;
+ //protocol = RFID_PROTOCOL_MIFARE_CLASSIC;
+ protocol = RFID_PROTOCOL_TCL;
+
+ if (l3(protocol) < 0)
+ exit(1);
+
+ switch (protocol) {
+ case RFID_PROTOCOL_TCL:
+ /* we've established T=CL at this point */
+ select_mf();
+
+ iso7816_select_application();
+ iso7816_select_ef(0x011e);
+ iso7816_select_ef(0x0101);
+#if 1
+ for (i = 0; i < 4; i++)
+ iso7816_get_challenge(0x06);
+#endif
+ break;
+ case RFID_PROTOCOL_MIFARE_UL:
+ mifare_ulight_read(ph);
+#if 0
+ mifare_ulight_blank(ph);
+ mifare_ulight_write(ph);
+ mifare_ulight_read(ph);
+#endif
+ break;
+ case RFID_PROTOCOL_MIFARE_CLASSIC:
+ rc = mfcl_set_key(ph, MIFARE_CL_KEYA_DEFAULT_INFINEON);
+ if (rc < 0) {
+ printf("key format error\n");
+ exit(1);
+ }
+ rc = mfcl_auth(ph, RFID_CMD_MIFARE_AUTH1A, 0);
+ if (rc < 0) {
+ printf("mifare auth error\n");
+ exit(1);
+ } else
+ printf("mifare authe succeeded!\n");
+ mifare_classic_read(ph);
+ break;
+ }
+
+ rfid_reader_close(rh);
+
+ exit(0);
+}