initial checkin of harald welte's original librfid project
[rfid/librfid.git] / src / rfid_proto_mifare_ul.c
1
2 /* Mifare Ultralight implementation, PCD side.
3  *
4  * (C) 2005 by Harald Welte <laforge@gnumonks.org>
5  *
6  */
7
8 /*
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License version 2 
11  *  as published by the Free Software Foundation
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <errno.h>
27
28 #include <librfid/rfid.h>
29 #include <librfid/rfid_protocol.h>
30 #include <librfid/rfid_layer2.h>
31 #include <librfid/rfid_protocol_mifare_ul.h>
32
33 #include "rfid_iso14443_common.h"
34
35
36 /* FIXME */
37 #define MIFARE_UL_READ_FWT      100
38 #define MIFARE_UL_WRITE_FWT     100
39
40 static int
41 mful_read(struct rfid_protocol_handle *ph, unsigned int page,
42           unsigned char *rx_data, unsigned int *rx_len)
43 {
44         unsigned char rx_buf[16];
45         unsigned int real_rx_len = sizeof(rx_buf);
46         unsigned char tx[2];
47         int ret;
48
49         if (page > MIFARE_UL_PAGE_MAX)
50                 return -EINVAL;
51
52         tx[0] = MIFARE_UL_CMD_READ;
53         tx[1] = page & 0xff;
54
55         ret = rfid_layer2_transcieve(ph->l2h, RFID_14443A_FRAME_REGULAR,
56                                      tx, sizeof(tx), rx_buf, 
57                                      &real_rx_len, MIFARE_UL_READ_FWT, 0);
58
59         if (ret < 0)
60                 return ret;
61
62         if (real_rx_len < *rx_len)
63                 *rx_len = real_rx_len;
64
65         memcpy(rx_data, rx_buf, *rx_len);
66
67         return ret;
68 }
69
70 static int
71 mful_write(struct rfid_protocol_handle *ph, unsigned int page,
72            unsigned char *tx_data, unsigned int tx_len)
73 {
74         unsigned int i;
75         unsigned char tx[6];
76         unsigned char rx[10];
77         unsigned int rx_len = sizeof(rx);
78         int ret;
79
80         if (tx_len != 4 || page > MIFARE_UL_PAGE_MAX)
81                 return -EINVAL;
82
83         tx[0] = MIFARE_UL_CMD_WRITE;
84         tx[1] = page & 0xff;
85
86         for (i = 0; i < 4; i++)
87                 tx[2+i] = tx_data[i];
88
89         ret = rfid_layer2_transcieve(ph->l2h, RFID_14443A_FRAME_REGULAR,
90                                      tx, sizeof(tx), rx, &rx_len, 
91                                      MIFARE_UL_WRITE_FWT, 0);
92                                         
93         if (ret < 0)
94                 return ret;
95
96         if (rx[0] != MIFARE_UL_RESP_ACK)
97                 return -EIO;
98
99         return ret;
100 }
101
102 static int
103 mful_transcieve(struct rfid_protocol_handle *ph,
104                 const unsigned char *tx_data, unsigned int tx_len,
105                 unsigned char *rx_data, unsigned int *rx_len,
106                 unsigned int timeout, unsigned int flags)
107 {
108         return -EINVAL;
109 }
110
111 static struct rfid_protocol_handle *
112 mful_init(struct rfid_layer2_handle *l2h)
113 {
114         struct rfid_protocol_handle *ph;
115         ph = malloc(sizeof(struct rfid_protocol_handle));
116         return ph;
117 }
118
119 static int mful_fini(struct rfid_protocol_handle *ph)
120 {
121         free(ph);
122         return 0;
123 }
124
125 struct rfid_protocol rfid_protocol_mful = {
126         .id     = RFID_PROTOCOL_MIFARE_UL,
127         .name   = "Mifare Ultralight",
128         .fn     = {
129                 .init           = &mful_init,
130                 .read           = &mful_read,
131                 .write          = &mful_write,
132                 .fini           = &mful_fini,
133         },
134 };
135
136 /* Functions below are not (yet? covered in the generic librfid api */
137
138
139 /* lock a certain page */
140 int rfid_mful_lock_page(struct rfid_protocol_handle *ph, unsigned int page)
141 {
142         unsigned char buf[4] = { 0x00, 0x00, 0x00, 0x00 };
143
144         if (ph->proto != &rfid_protocol_mful)
145                 return -EINVAL;
146
147         if (page < 3 || page > 15)
148                 return -EINVAL;
149
150         if (page > 8)
151                 buf[2] = (1 << page);
152         else
153                 buf[3] = (1 << (page - 8));
154
155         return mful_write(ph, MIFARE_UL_PAGE_LOCK, buf, sizeof(buf));
156 }
157
158 /* convenience wrapper to lock the otp page */
159 int rfid_mful_lock_otp(struct rfid_protocol_handle *ph)
160 {
161         return rfid_mful_lock_page(ph, MIFARE_UL_PAGE_OTP);
162 }