source: trunk/src/ifd/protocol.c @ 677

Revision 677, 5.3 KB checked in by aj, 7 years ago (diff)

add/fix/unify out of memory handling.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * Protocol selection
3 *
4 * Copyright (C) 2003, Olaf Kirch <okir@suse.de>
5 */
6
7#include "internal.h"
8#include <stdlib.h>
9#include <string.h>
10
11struct ifd_protocol_info {
12        struct ifd_protocol_info *next;
13        struct ifd_protocol_ops *ops;
14};
15
16static struct ifd_protocol_info *list = NULL;
17
18/*
19 * Register a protocol
20 */
21int ifd_protocol_register(struct ifd_protocol_ops *ops)
22{
23        struct ifd_protocol_info *info, **ptr;
24
25        info = (struct ifd_protocol_info *)calloc(1, sizeof(*info));
26        if (!info) {
27                ct_error("out of memory");
28                return IFD_ERROR_NO_MEMORY;
29        }
30        info->ops = ops;
31
32        for (ptr = &list; *ptr; ptr = &(*ptr)->next) ;
33        *ptr = info;
34        return 0;
35}
36
37/*
38 * Look up protocol based on its ID
39 */
40static struct ifd_protocol_ops *ifd_protocol_by_id(int id)
41{
42        struct ifd_protocol_info *info;
43
44        for (info = list; info; info = info->next) {
45                if (info->ops->id == id)
46                        return info->ops;
47        }
48
49        /* Autoload protocols defined in external modules? */
50
51        return NULL;
52}
53
54/*
55 * Select a protocol
56 */
57ifd_protocol_t *ifd_protocol_select(ifd_reader_t * reader, int nslot,
58                                    int preferred)
59{
60        const ifd_driver_t *drv;
61        ifd_slot_t *slot = &reader->slot[nslot];
62        unsigned char *atr, TDi;
63        unsigned int supported = 0;
64        int def_proto = -1, n, len;
65
66        ifd_debug(1, "atr=%s", ct_hexdump(slot->atr, slot->atr_len));
67
68        /* FIXME: use ifd_atr_parse() instead */
69        atr = slot->atr;
70        len = slot->atr_len;
71        if (len < 2)
72                return NULL;
73
74        /* Ignore hysterical bytes */
75        len -= atr[1] & 0x0f;
76
77        n = 2;
78        do {
79                int prot;
80
81                TDi = atr[n - 1];
82                if (n != 2) {
83                        prot = TDi & 0x0f;
84                        supported |= (1 << prot);
85                        if (def_proto < 0)
86                                def_proto = prot;
87                }
88
89                n += ifd_count_bits(TDi & 0xF0);
90        } while (n < len && (TDi & 0x80));
91
92        if (supported == 0)
93                supported |= 0x01;
94        if (def_proto < 0)
95                def_proto = IFD_PROTOCOL_T0;
96
97        ifd_debug(1, "default T=%d, supported protocols=0x%x",
98                  def_proto, supported);
99
100        if (preferred >= 0
101            && preferred != def_proto && (supported & (1 << preferred))) {
102                /* XXX perform PTS */
103                ifd_debug(1, "protocol selection not supported");
104        }
105
106        if ((drv = reader->driver) && drv->ops && drv->ops->set_protocol) {
107                if (drv->ops->set_protocol(reader, nslot, def_proto) < 0)
108                        return NULL;
109        } else {
110                slot->proto = ifd_protocol_new(def_proto, reader, slot->dad);
111        }
112
113        return slot->proto;
114}
115
116/*
117 * Force the protocol driver to resynchronize
118 */
119int ifd_protocol_resynchronize(ifd_protocol_t * p, int nad)
120{
121        ifd_debug(1, "called.");
122        if (!p || !p->ops || !p->ops->resynchronize)
123                return IFD_ERROR_NOT_SUPPORTED;
124
125        return p->ops->resynchronize(p, nad);
126}
127
128/*
129 * Protocol transceive
130 */
131int ifd_protocol_transceive(ifd_protocol_t * p, int dad, const void *sbuf,
132                            size_t slen, void *rbuf, size_t rlen)
133{
134        int rc;
135
136        if (!p || !p->ops || !p->ops->transceive)
137                return IFD_ERROR_NOT_SUPPORTED;
138
139        ifd_debug(1, "cmd: %s", ct_hexdump(sbuf, slen));
140        rc = p->ops->transceive(p, dad, sbuf, slen, rbuf, rlen);
141
142        if (rc >= 0)
143                ifd_debug(1, "resp:%s", ct_hexdump(rbuf, rc));
144        else
145                ifd_debug(1, "transceive error: %s", ct_strerror(rc));
146
147        return rc;
148}
149
150/*
151 * Read/write synchronous ICCs
152 */
153int ifd_protocol_read_memory(ifd_protocol_t * p, int slot, unsigned short addr,
154                             unsigned char *rbuf, size_t rlen)
155{
156        int rc;
157
158        if (!p || !p->ops || !p->ops->sync_read)
159                return IFD_ERROR_NOT_SUPPORTED;
160
161        ifd_debug(1, "read %u@%04x (%s)", (unsigned int)rlen, addr,
162                  p->ops->name);
163        rc = p->ops->sync_read(p, slot, addr, rbuf, rlen);
164
165        if (rc >= 0)
166                ifd_debug(1, "resp:%s", ct_hexdump(rbuf, rc));
167
168        return rc;
169}
170
171int ifd_protocol_write_memory(ifd_protocol_t * p, int slot, unsigned short addr,
172                              const unsigned char *sbuf, size_t slen)
173{
174        int rc;
175
176        if (!p || !p->ops || !p->ops->sync_write)
177                return IFD_ERROR_NOT_SUPPORTED;
178
179        ifd_debug(1, "write %u@%04x (%s):%s",
180                  (unsigned int)slen, addr,
181                  p->ops->name, ct_hexdump(sbuf, slen));
182        rc = p->ops->sync_write(p, slot, addr, sbuf, slen);
183
184        ifd_debug(1, "resp = %d", rc);
185        return rc;
186}
187
188/*
189 * Create new protocol object
190 */
191ifd_protocol_t *ifd_protocol_new(int id, ifd_reader_t * reader,
192                                 unsigned int dad)
193{
194        struct ifd_protocol_ops *ops;
195        ifd_protocol_t *p;
196
197        if (reader == NULL)
198                return NULL;
199
200        if (!(ops = ifd_protocol_by_id(id))) {
201                ct_error("unknown protocol id %d", id);
202                return NULL;
203        }
204
205        p = (ifd_protocol_t *) calloc(1, ops->size);
206        if (!p) {
207                ct_error("out of memory");
208                return p;
209        }
210        p->reader = reader;
211        p->ops = ops;
212        p->dad = dad;
213
214        if (ops->init && ops->init(p) < 0) {
215                ct_error("Protocol initialization failed");
216                ifd_protocol_free(p);
217                return NULL;
218        }
219
220        return p;
221}
222
223/*
224 * Set a protocol specific parameter
225 */
226int ifd_protocol_set_parameter(ifd_protocol_t * p, int type, long value)
227{
228        if (!p || !p->ops || !p->ops->set_param)
229                return -1;
230        return p->ops->set_param(p, type, value);
231}
232
233int ifd_protocol_get_parameter(ifd_protocol_t * p, int type, long *value)
234{
235        if (!p || !p->ops || !p->ops->get_param)
236                return -1;
237        return p->ops->get_param(p, type, value);
238}
239
240/*
241 * Free protocol object
242 */
243void ifd_protocol_free(ifd_protocol_t * p)
244{
245        if (p->ops) {
246                if (p->ops->release)
247                        p->ops->release(p);
248                memset(p, 0, p->ops->size);
249        } else {
250                memset(p, 0, sizeof(*p));
251        }
252        free(p);
253}
254
255/*
256 * List available protocols
257 */
258unsigned int ifd_protocols_list(const char **names, unsigned int max)
259{
260        struct ifd_protocol_info *info;
261        unsigned int n;
262
263        for (info = list, n = 0; info && n < max; info = info->next, n++) {
264                names[n] = info->ops->name;
265        }
266        return n;
267}
Note: See TracBrowser for help on using the repository browser.