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 
11 struct ifd_protocol_info {
12 	struct ifd_protocol_info *next;
13 	struct ifd_protocol_ops *ops;
14 };
15 
16 static struct ifd_protocol_info *list = NULL;
17 
18 /*
19  * Register a protocol
20  */
ifd_protocol_register(struct ifd_protocol_ops * ops)21 int 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  */
ifd_protocol_by_id(int id)40 static 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  */
ifd_protocol_select(ifd_reader_t * reader,int nslot,int preferred)57 ifd_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  */
ifd_protocol_resynchronize(ifd_protocol_t * p,int nad)119 int 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  */
ifd_protocol_transceive(ifd_protocol_t * p,int dad,const void * sbuf,size_t slen,void * rbuf,size_t rlen)131 int 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  */
ifd_protocol_read_memory(ifd_protocol_t * p,int slot,unsigned short addr,unsigned char * rbuf,size_t rlen)153 int 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 
ifd_protocol_write_memory(ifd_protocol_t * p,int slot,unsigned short addr,const unsigned char * sbuf,size_t slen)171 int 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  */
ifd_protocol_new(int id,ifd_reader_t * reader,unsigned int dad)191 ifd_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  */
ifd_protocol_set_parameter(ifd_protocol_t * p,int type,long value)226 int 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 
ifd_protocol_get_parameter(ifd_protocol_t * p,int type,long * value)233 int 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  */
ifd_protocol_free(ifd_protocol_t * p)243 void 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  */
ifd_protocols_list(const char ** names,unsigned int max)258 unsigned 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 }
268