1 /******************************************************************************
2 *
3 * Copyright (C) 2018 ST Microelectronics S.A.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *
18 ******************************************************************************/
19 #define LOG_TAG "StEse-T1protocol"
20 #include "T1protocol.h"
21 #include <errno.h>
22 #include <string.h>
23 #include "SpiLayerComm.h"
24 #include "SpiLayerDriver.h"
25 #include "SpiLayerInterface.h"
26 #include "android_logmsg.h"
27 #include "utils-lib/DataMgmt.h"
28 #include "utils-lib/Iso13239CRC.h"
29 #include "utils-lib/Tpdu.h"
30
31 uint8_t SEQ_NUM_MASTER;
32 uint8_t SEQ_NUM_SLAVE;
33 uint8_t recoveryStatus;
34 T1TProtocol_TransceiveState gNextCmd = Idle;
35
36 /*******************************************************************************
37 **
38 ** Function T1protocol_getValidPcb
39 **
40 ** Description Form a valid pcb according to the Tpdu type, subtype,
41 ** master sequence number,slave sequence number and isLast.
42 **
43 ** Parameters type - The Tpdu type (IBlock, RBlock or SBlock).
44 ** subtype - The different subtype options(for RBlock).
45 ** numSeqMaster - Master sequence number.
46 ** numseqSlave - Slave sequence number.
47 ** isLast - Indicate if there are more tpdus to send
48 ** within the same APDU.
49 **
50 ** Returns pcb - Computed PCB.
51 **
52 *******************************************************************************/
T1protocol_getValidPcb(TpduType type,RBlockType subtype,uint8_t numSeqMaster,uint8_t numseqSlave,bool isLast)53 uint8_t T1protocol_getValidPcb(TpduType type, RBlockType subtype,
54 uint8_t numSeqMaster, uint8_t numseqSlave,
55 bool isLast) {
56 uint8_t pcb = 0xFF;
57
58 switch (type) {
59 case IBlock:
60 pcb = 0x00;
61 // Set the Ns according to the numSeqMaster
62 if (numSeqMaster == 1) {
63 pcb |= (uint8_t)IBLOCK_NS_BIT_MASK;
64 }
65
66 // If the Tpdu is a part of chain, set the M bit inside the pcb.
67 if (isLast == APDU_PART_IS_NOT_LAST) {
68 pcb |= IBLOCK_M_BIT_MASK;
69 }
70 break;
71
72 case RBlock:
73 pcb = 0x80;
74 if (subtype == ErrorFree) {
75 // Set the bit for the N(R)
76 pcb |= ((uint8_t)numseqSlave) << 4;
77 } else if (subtype == ChecksumError) {
78 // Set the bits for the subtype checksum error and the N(R)
79 pcb |= 0b00000001;
80 pcb |= ((uint8_t)numseqSlave) << 4;
81 } else if (subtype == OtherErrors) {
82 // Set the bits for the subtype other errors and the N(R)
83 pcb |= 0b00000010;
84 pcb |= ((uint8_t)numseqSlave) << 4;
85 }
86 break;
87
88 default:
89 break;
90 }
91
92 return pcb;
93 }
94
95 /*******************************************************************************
96 **
97 ** Function T1protocol_checkResponseTpduChecksum
98 **
99 ** Description Check if the checksum of a given tpdu is well formed.
100 **
101 ** Parameters cmdTpdu -The TPDU to check
102 **
103 ** Returns 0 If checksum is ok, -1 otherwise.
104 **
105 *******************************************************************************/
T1protocol_checkResponseTpduChecksum(Tpdu * respTpdu)106 int T1protocol_checkResponseTpduChecksum(Tpdu* respTpdu) {
107 if (ATP.checksumType == CRC) {
108 // Check CRC
109 uint8_t arrayTpdu[TPDU_PROLOGUE_LENGTH + respTpdu->len + TPDU_CRC_LENGTH];
110 Tpdu_toByteArray(respTpdu, arrayTpdu);
111 if (computeCrc(arrayTpdu, TPDU_PROLOGUE_LENGTH + respTpdu->len) !=
112 respTpdu->checksum) {
113 return -1;
114 }
115 } else if (ATP.checksumType == LRC) {
116 // Check LRC
117 // char arrayTpdu[TPDU_PROLOGUE_LENGTH + respTpdu->len + TPDU_LRC_LENGTH];
118 // TODO: implement compute LRC
119 return -1;
120 }
121
122 return 0;
123 }
124
125 /*******************************************************************************
126 **
127 ** Function T1protocol_checkResponsePcbConsistency
128 **
129 ** Description Check if the pcb of a given tpdu is valid.
130 **
131 ** Parameters cmdTpdu -The TPDU to check
132 **
133 ** Returns 0 If checksum is ok, -1 otherwise.
134 **
135 *******************************************************************************/
T1protocol_checkResponsePcbConsistency(Tpdu * tpdu)136 int T1protocol_checkResponsePcbConsistency(Tpdu* tpdu) {
137 // Get the type of the incoming tpdu
138 TpduType type = Tpdu_getType(tpdu);
139
140 switch (type) {
141 case IBlock:
142 // Match the IBlock pcb received with the bits that must be 0. If
143 // the result is higher than 0, means some of these bits was set to 1.
144 if ((tpdu->pcb & 0b00011111)) {
145 return -1;
146 }
147 break;
148
149 case RBlock:
150 // Match the RBlock pcb received with the bits that must be 0. If
151 // the result is higher than 0, means some of these bits was set to 1.
152 if ((tpdu->pcb & 0b01101100)) {
153 return -1;
154 }
155 break;
156
157 case SBlock:
158 // Match the SBlock pcb received with the bits that must be 0. If
159 // the result is higher than 0, means some of these bits was set to 1.
160 if ((tpdu->pcb & 0b00010000)) {
161 return -1;
162 }
163 break;
164
165 default:
166 break;
167 }
168
169 return 0;
170 }
171
172 /*******************************************************************************
173 **
174 ** Function T1protocol_checkResponseLenConsistency
175 **
176 ** Description Check if the length field of a given tpdu is valid.
177 **
178 ** Parameters cmdTpdu -The TPDU to check
179 **
180 ** Returns 0 If checksum is ok, -1 otherwise.
181 **
182 *******************************************************************************/
T1protocol_checkResponseLenConsistency(Tpdu * tpdu)183 int T1protocol_checkResponseLenConsistency(Tpdu* tpdu) {
184 // Check the length consistency according to the block type
185 TpduType type = Tpdu_getType(tpdu);
186
187 switch (type) {
188 case IBlock:
189 // If the last Tpdu received was an IBlock, the len must be lower or
190 // equal than the ATP ifsd field.
191 if (tpdu->len > ATP.ifsc) {
192 return -1;
193 }
194 break;
195
196 case RBlock:
197 // If the last Tpdu received was an RBlock, the len must be 0.
198 if (tpdu->len > 0) {
199 return -1;
200 }
201 break;
202
203 case SBlock:
204 // If the last Tpdu received was an SBlock WTX... or IFS..., the length
205 // must be 1. If the last Tpdu received was an SBlock
206 // ABORT... or RESYNCH... the length must be 0.
207 if ((tpdu->pcb == (uint8_t)SBLOCK_WTX_REQUEST_MASK) ||
208 (tpdu->pcb == (uint8_t)SBLOCK_WTX_RESPONSE_MASK) ||
209 (tpdu->pcb == (uint8_t)SBLOCK_IFS_REQUEST_MASK) ||
210 (tpdu->pcb == (uint8_t)SBLOCK_IFS_RESPONSE_MASK)) {
211 if (tpdu->len != 1) {
212 return -1;
213 }
214 } else if ((tpdu->pcb == (uint8_t)SBLOCK_ABORT_REQUEST_MASK) ||
215 (tpdu->pcb == (uint8_t)SBLOCK_ABORT_RESPONSE_MASK) ||
216 (tpdu->pcb == (uint8_t)SBLOCK_RESYNCH_REQUEST_MASK) ||
217 (tpdu->pcb == (uint8_t)SBLOCK_RESYNCH_RESPONSE_MASK)) {
218 if (tpdu->len != 0) {
219 return -1;
220 }
221 }
222 break;
223 }
224
225 return 0;
226 }
227
228 /*******************************************************************************
229 **
230 ** Function T1protocol_checkResponseSeqNumberConsistency
231 **
232 ** Description Check if the sequence number of a given tpdu is valid.
233 **
234 ** Parameters cmdTpdu -The TPDU to check
235 **
236 ** Returns 0 If checksum is ok, -1 otherwise.
237 **
238 *******************************************************************************/
T1protocol_checkResponseSeqNumberConsistency(Tpdu * tpdu)239 int T1protocol_checkResponseSeqNumberConsistency(Tpdu* tpdu) {
240 // Check the length consistency according to the block type
241 TpduType type = Tpdu_getType(tpdu);
242
243 uint8_t seqNumber;
244
245 switch (type) {
246 case IBlock:
247 // CHeck if the sequence number received in the last IBlock matches the
248 // expected.
249 seqNumber = (tpdu->pcb & 0b01000000) >> 6;
250 if (seqNumber != SEQ_NUM_SLAVE) {
251 return -1;
252 }
253 break;
254
255 case RBlock:
256 // TODO
257 // If the original command Tpdu was Iblock chained, both sequence
258 // numbers are expected. If the original command Tpdu was Iblock
259 // without chaining an Rblock with sequence number different than the
260 // actual master sequence number is considered as invalid.
261 /*if ((cmdTpdu->pcb & IBLOCK_M_BIT_MASK) == 0) {
262 // Original Iblock without chaining
263 if (T1protocol_isSequenceNumberOk(
264 cmdTpdu,
265 respTpdu) == false) {
266 // Sequence number different from actual master sequence number
267 return -1;
268 }
269 }*/
270 break;
271
272 default:
273 break;
274 }
275
276 return 0;
277 }
278
279 /*******************************************************************************
280 **
281 ** Function T1protocol_checkSBlockResponseConsistency
282 **
283 ** Description Check if an SBlock response was received after having
284 ** transmitted a SBlock request.
285 **
286 ** Parameters lastCmdTpduSent - Last Tpdu sent.
287 ** lastRespTpduReceived - Response received.
288 **
289 ** Returns 0 If checksum is ok, -1 otherwise.
290 **
291 *******************************************************************************/
T1protocol_checkSBlockResponseConsistency(Tpdu * lastCmdTpduSent,Tpdu * lastRespTpduReceived)292 int T1protocol_checkSBlockResponseConsistency(Tpdu* lastCmdTpduSent,
293 Tpdu* lastRespTpduReceived) {
294 // Check if last Tpdu received was an SBlock(...response) after having
295 // transmitted a SBlock(...request).
296
297 if ((lastCmdTpduSent->pcb == (uint8_t)SBLOCK_WTX_REQUEST_MASK) ||
298 (lastCmdTpduSent->pcb == (uint8_t)SBLOCK_ABORT_REQUEST_MASK) ||
299 (lastCmdTpduSent->pcb == (uint8_t)SBLOCK_IFS_REQUEST_MASK) ||
300 (lastCmdTpduSent->pcb == (uint8_t)SBLOCK_RESYNCH_REQUEST_MASK) ||
301 (lastCmdTpduSent->pcb == (uint8_t)SBLOCK_SWRESET_REQUEST_MASK)) {
302 uint8_t expectedPcbResponse;
303 // Calculate the expected response according to the SBlock request
304 // previously sent.
305 expectedPcbResponse = lastCmdTpduSent->pcb | 0b00100000;
306
307 if (expectedPcbResponse != lastRespTpduReceived->pcb) {
308 return -1;
309 }
310 }
311
312 return 0;
313 }
314
315 /*******************************************************************************
316 **
317 ** Function T1protocol_checkTpduConsistency
318 **
319 ** Description Check if the response TPDU is consistent
320 ** (check the checksum, check if the pcb is valid and the
321 ** expected one and check the len consistency).
322 **
323 ** Parameters lastCmdTpduSent - Last Tpdu sent.
324 ** lastRespTpduReceived - Last response from the slave.
325 **
326 ** Returns 0 If checksum is ok, -1 otherwise.
327 **
328 *******************************************************************************/
T1protocol_checkTpduConsistency(Tpdu * lastCmdTpduSent,Tpdu * lastRespTpduReceived)329 int T1protocol_checkTpduConsistency(Tpdu* lastCmdTpduSent,
330 Tpdu* lastRespTpduReceived) {
331 // Check checksum
332 if (T1protocol_checkResponseTpduChecksum(lastRespTpduReceived) == -1) {
333 return -1;
334 }
335
336 // Check pcb consistency
337 if (T1protocol_checkResponsePcbConsistency(lastRespTpduReceived) == -1) {
338 return -1;
339 }
340
341 // Check len consistency
342 if (T1protocol_checkResponseLenConsistency(lastRespTpduReceived) == -1) {
343 return -1;
344 }
345
346 // Check sequence number consistency
347 if (T1protocol_checkResponseSeqNumberConsistency(lastRespTpduReceived) ==
348 -1) {
349 return -1;
350 }
351
352 // Check if a valid sBlock response has been received after having
353 // transmitted an sBlock request
354 if (T1protocol_checkSBlockResponseConsistency(lastCmdTpduSent,
355 lastRespTpduReceived) == -1) {
356 return -1;
357 }
358
359 return 0;
360 }
361
362 /*******************************************************************************
363 **
364 ** Function T1protocol_resetSequenceNumbers
365 **
366 ** Description Set the sequence numbers to it's initial values.
367 **
368 ** Parameters none
369 **
370 ** Returns void
371 **
372 *******************************************************************************/
T1protocol_resetSequenceNumbers()373 void T1protocol_resetSequenceNumbers() {
374 // Set the sequence numbers to it's initial values.
375 SEQ_NUM_MASTER = 0;
376 SEQ_NUM_SLAVE = 0;
377 }
378
379 /*******************************************************************************
380 **
381 ** Function T1protocol_updateMasterSequenceNumber
382 **
383 ** Description Update the master sequence number.
384 **
385 ** Parameters none
386 **
387 ** Returns void
388 **
389 *******************************************************************************/
T1protocol_updateMasterSequenceNumber()390 void T1protocol_updateMasterSequenceNumber() {
391 // Sequence numbers are module 2,
392 SEQ_NUM_MASTER++;
393 SEQ_NUM_MASTER %= 2;
394 }
395
396 /*******************************************************************************
397 **
398 ** Function T1protocol_updateSlaveSequenceNumber
399 **
400 ** Description Update the slave sequence number.
401 **
402 ** Parameters none
403 **
404 ** Returns void
405 **
406 *******************************************************************************/
T1protocol_updateSlaveSequenceNumber()407 void T1protocol_updateSlaveSequenceNumber() {
408 // Sequence numbers are module 2,
409 SEQ_NUM_SLAVE++;
410 SEQ_NUM_SLAVE %= 2;
411 }
412
413 /*******************************************************************************
414 **
415 ** Function T1protocol_processIBlock
416 **
417 ** Description Process the last IBlock received from the slave.
418 **
419 ** Parameters originalCmdTpdu - Original Tpdu sent.
420 ** lastRespTpduReceived - Last response from the slave.
421 **
422 ** Returns 0 If all went is ok, -1 otherwise.
423 **
424 *******************************************************************************/
T1protocol_processIBlock(Tpdu * originalCmdTpdu,Tpdu * lastRespTpduReceived)425 int T1protocol_processIBlock(Tpdu* originalCmdTpdu,
426 Tpdu* lastRespTpduReceived) {
427 // The last IBlock received was the good one. Update the sequence
428 // numbers needed.
429 int rc = 0;
430 TpduType type = Tpdu_getType(originalCmdTpdu);
431
432 T1protocol_updateSlaveSequenceNumber();
433 rc = DataMgmt_StoreDataInList(lastRespTpduReceived->len,
434 lastRespTpduReceived->data);
435
436 if ((lastRespTpduReceived->pcb & IBLOCK_M_BIT_MASK) > 0) {
437 gNextCmd = R_ACK;
438 } else {
439 if (type == IBlock) {
440 T1protocol_updateMasterSequenceNumber();
441 }
442 gNextCmd = Idle;
443 }
444 return rc;
445 }
446
447 /*******************************************************************************
448 **
449 ** Function T1protocol_processRBlock
450 **
451 ** Description Process the last RBlock received from the slave.
452 **
453 ** Parameters originalCmdTpdu - Original Tpdu sent.
454 ** lastRespTpduReceived - Last response from the slave.
455 **
456 ** Returns -1 if the retransmission needed fails, 0 if no more
457 ** retransmission were needed and 1 if extra retransmission
458 ** success.
459 **
460 *******************************************************************************/
T1protocol_processRBlock(Tpdu * originalCmdTpdu,Tpdu * lastRespTpduReceived)461 void T1protocol_processRBlock(Tpdu* originalCmdTpdu,
462 Tpdu* lastRespTpduReceived) {
463 if ((originalCmdTpdu->pcb & IBLOCK_M_BIT_MASK) > 0) {
464 // Last IBlock sent was chained. Expected RBlock(NS+1) for error free
465 // operation and RBlock(NS) if something well bad.
466 if (T1protocol_isSequenceNumberOk(originalCmdTpdu, lastRespTpduReceived) ==
467 false) {
468 STLOG_HAL_E("Wrong Seq number. Send again ");
469 gNextCmd = I_block;
470 } else {
471 T1protocol_updateMasterSequenceNumber();
472 gNextCmd = Idle;
473 }
474 } else {
475 // Last IBlock sent wasn't chained. If we receive an RBlock(NS) means
476 // retransmission of the original IBlock, otherwise do resend request.
477 if (T1protocol_isSequenceNumberOk(originalCmdTpdu, lastRespTpduReceived) ==
478 true) {
479 STLOG_HAL_D("%s : Need retransmissiom :", __func__);
480 gNextCmd = I_block;
481 } else {
482 gNextCmd = S_Resync_REQ;
483 }
484 }
485 }
486
487 /*******************************************************************************
488 **
489 ** Function T1protocol_sendRBlock
490 **
491 ** Description Send a R-block to the card.
492 **
493 ** Parameters rack - if 1, send a ack frame, nack otherwise.
494 ** lastRespTpduReceived - Last response from the slave.
495 **
496 ** Returns bytesRead if data was read, 0 if timeout expired with
497 ** no response, -1 otherwise
498 **
499 *******************************************************************************/
T1protocol_sendRBlock(int rack,Tpdu * lastRespTpduReceived)500 int T1protocol_sendRBlock(int rack, Tpdu* lastRespTpduReceived) {
501 int result = 0;
502 Tpdu* TempTpdu = (Tpdu*)malloc(sizeof(Tpdu));
503 TempTpdu->data = (uint8_t*)malloc(ATP.ifsc * sizeof(uint8_t));
504
505 result = Tpdu_formTpdu(
506 NAD_HOST_TO_SLAVE,
507 T1protocol_getValidPcb(RBlock, rack ? ErrorFree : OtherErrors, 0,
508 SEQ_NUM_SLAVE, 0),
509 0, NULL, TempTpdu);
510 if (result == -1) {
511 free(TempTpdu->data);
512 free(TempTpdu);
513 return -1;
514 }
515 result = SpiLayerInterface_transcieveTpdu(TempTpdu, lastRespTpduReceived,
516 DEFAULT_NBWT);
517 if (result < 0) {
518 free(TempTpdu->data);
519 free(TempTpdu);
520 return -1;
521 }
522 free(TempTpdu->data);
523 free(TempTpdu);
524 return result;
525 }
526 /*******************************************************************************
527 **
528 ** Function T1protocol_formSblockResponse
529 **
530 ** Description Form a SBlock response according to a given SBlock Request.
531 **
532 ** Parameters responseTpdu - A valid SBlock response according to the
533 ** SBlock request in the requestTpdu param.
534 ** requestTpdu - Sblock request received from the eSE to
535 ** process.
536 **
537 ** Returns 0 If all went is ok, -1 otherwise.
538 **
539 *******************************************************************************/
T1protocol_formSblockResponse(Tpdu * responseTpdu,Tpdu * requestTpdu)540 int T1protocol_formSblockResponse(Tpdu* responseTpdu, Tpdu* requestTpdu) {
541 uint8_t i;
542
543 responseTpdu->nad = NAD_HOST_TO_SLAVE;
544 responseTpdu->pcb = requestTpdu->pcb | 0b00100000;
545 responseTpdu->len = requestTpdu->len;
546 for (i = 0; i < requestTpdu->len; i++) {
547 responseTpdu->data[i] = requestTpdu->data[i];
548 }
549 responseTpdu->checksum = 0x0000;
550
551 if (ATP.checksumType == CRC) {
552 uint8_t buffer[TPDU_PROLOGUE_LENGTH + responseTpdu->len + TPDU_CRC_LENGTH];
553 Tpdu_toByteArray(responseTpdu, buffer);
554 responseTpdu->checksum =
555 computeCrc(buffer, (TPDU_PROLOGUE_LENGTH + responseTpdu->len));
556 } else if (ATP.checksumType == LRC) {
557 // char buffer[TPDU_PROLOGUE_LENGTH + responseTpdu->len + TPDU_LRC_LENGTH];
558 // TODO
559 STLOG_HAL_E("LRC still not implemented.");
560 return -1;
561 }
562
563 return 0;
564 }
565
566 /*******************************************************************************
567 **
568 ** Function T1protocol_processSBlock
569 **
570 ** Description Process the last SBlock received from the slave.
571 **
572 ** Parameters originalCmdTpdu - Original Tpdu sent.
573 ** lastCmdTpduSent - Last Tpdu sent.
574 ** lastRespTpduReceived - Last response from the slave.
575 **
576 ** Returns 0 If all went is ok, -1 otherwise.
577 **
578 *******************************************************************************/
T1protocol_processSBlock(Tpdu * originalCmdTpdu,Tpdu * lastCmdTpduSent,Tpdu * lastRespTpduReceived)579 int T1protocol_processSBlock(Tpdu* originalCmdTpdu, Tpdu* lastCmdTpduSent,
580 Tpdu* lastRespTpduReceived) {
581 int rc;
582 if (lastRespTpduReceived->pcb == (uint8_t)SBLOCK_WTX_REQUEST_MASK) {
583 gNextCmd = S_WTX_RES;
584 } else if (lastRespTpduReceived->pcb == (uint8_t)SBLOCK_IFS_REQUEST_MASK) {
585 gNextCmd = S_IFS_RES;
586 } else if (lastRespTpduReceived->pcb == (uint8_t)SBLOCK_IFS_RESPONSE_MASK) {
587 ATP.ifsc = (uint8_t)lastRespTpduReceived->data[0];
588 return 0;
589 } else if (lastRespTpduReceived->pcb ==
590 (uint8_t)SBLOCK_RESYNCH_REQUEST_MASK) {
591 T1protocol_resetSequenceNumbers();
592 gNextCmd = S_Resync_RES;
593 } else if (lastRespTpduReceived->pcb ==
594 (uint8_t)SBLOCK_RESYNCH_RESPONSE_MASK) {
595 T1protocol_resetSequenceNumbers();
596 // Reset the sequence number of the original Tpdu if needed
597 if ((originalCmdTpdu->pcb & IBLOCK_NS_BIT_MASK) > 0) {
598 originalCmdTpdu->pcb &= ~IBLOCK_NS_BIT_MASK;
599
600 rc = Tpdu_formTpdu(originalCmdTpdu->nad, originalCmdTpdu->pcb,
601 originalCmdTpdu->len, originalCmdTpdu->data,
602 originalCmdTpdu);
603 if (rc < 0) {
604 return rc;
605 }
606 }
607
608 Tpdu_copy(lastCmdTpduSent, originalCmdTpdu);
609 gNextCmd = I_block;
610
611 } else if (lastRespTpduReceived->pcb == (uint8_t)SBLOCK_ABORT_REQUEST_MASK) {
612 // TODO
613 STLOG_HAL_E("ABORT request received still not supported.");
614 return -1;
615 } else if (lastRespTpduReceived->pcb ==
616 (uint8_t)SBLOCK_SWRESET_RESPONSE_MASK) {
617 if (Atp_setAtp(lastRespTpduReceived->data) != 0) {
618 STLOG_HAL_E("Error setting ATP");
619 return -1;
620 }
621
622 T1protocol_resetSequenceNumbers();
623 // SW Reset done
624 return -1;
625 }
626 return 0;
627 }
628
629 /*******************************************************************************
630 **
631 ** Function T1protocol_isSequenceNumberOk
632 **
633 ** Description Check if the sequence number of the response TPDU is the
634 ** expected one.
635 **
636 ** Parameters originalTpdu - Original tpdu sent.
637 ** respTpdu - The last response received from the slave.
638 **
639 ** Returns true If sequence number is ok, false otherwise.
640 **
641 *******************************************************************************/
T1protocol_isSequenceNumberOk(Tpdu * originalTpdu,Tpdu * respTpdu)642 bool T1protocol_isSequenceNumberOk(Tpdu* originalTpdu, Tpdu* respTpdu) {
643 int seqNumber;
644
645 // Get the type of the TPDU and act consequently
646 TpduType tpduType = Tpdu_getType(respTpdu);
647
648 switch (tpduType) {
649 case IBlock:
650 seqNumber = (respTpdu->pcb & 0b01000000) >> 6;
651 if (seqNumber == SEQ_NUM_SLAVE) {
652 return true;
653 } else {
654 return false;
655 }
656 break;
657
658 case RBlock:
659 // If the original Tpdu sent was chained, the expected sequence number
660 // inside the RBlock i the next master sequence number.
661 // If the original Tpdu sent wans't chained, no RBlock expected. If an
662 // RBlock with sequence number equal to the master sequence number is
663 // received, retransmission is needed, otherwise retransmission request
664 // is needed.
665 // TODO
666 if ((originalTpdu->pcb & IBLOCK_M_BIT_MASK) > 0) {
667 seqNumber = (respTpdu->pcb & 0x10) >> 4;
668 if (seqNumber == ((SEQ_NUM_MASTER + 1) % 2)) {
669 return true;
670 } else {
671 return false;
672 }
673 } else {
674 seqNumber = (respTpdu->pcb & 0x10) >> 4;
675 if (seqNumber == SEQ_NUM_MASTER) {
676 return true;
677 } else {
678 return false;
679 }
680 }
681 break;
682
683 default:
684 break;
685 }
686 return false;
687 }
688
689 /*******************************************************************************
690 **
691 ** Function T1protocol_updateRecoveryStatus
692 **
693 ** Description Updates the recovery state to the following step.
694 **
695 ** Parameters none
696 **
697 ** Returns void
698 **
699 *******************************************************************************/
T1protocol_updateRecoveryStatus()700 void T1protocol_updateRecoveryStatus() {
701 switch (recoveryStatus) {
702 case RECOVERY_STATUS_OK:
703 STLOG_HAL_D("recoveryStatus: OK -> RESEND 1");
704 recoveryStatus = RECOVERY_STATUS_RESEND_1;
705 break;
706
707 case RECOVERY_STATUS_RESEND_1:
708 STLOG_HAL_D("recoveryStatus: RESEND 1 -> RESYNC 1");
709 recoveryStatus = RECOVERY_STATUS_RESYNC_1;
710 break;
711
712 case RECOVERY_STATUS_RESYNC_1:
713 STLOG_HAL_D("recoveryStatus: RESYNC 1 -> WARM RESET");
714 recoveryStatus = RECOVERY_STATUS_WARM_RESET;
715 break;
716
717 case RECOVERY_STATUS_WARM_RESET:
718 STLOG_HAL_D("recoveryStatus: WARM_RESET (recovery completed)");
719 recoveryStatus = RECOVERY_STATUS_KO;
720 break;
721 }
722 }
723
724 /*******************************************************************************
725 **
726 ** Function T1protocol_setRespApduData
727 **
728 ** Description Copy the data in the response Tpdu into the respApduBuffer.
729 **
730 ** Parameters respTpdu - Response tpdu where the data is stored.
731 ** respApduBuffer - Apdu buffer to store the data received
732 ** in the response Tpdu.
733 **
734 ** Returns The amount of data bytes saved into the apdu buffer.
735 **
736 *******************************************************************************/
T1protocol_setRespApduData(Tpdu * respTpdu,uint8_t ** respApduBuffer)737 uint8_t T1protocol_setRespApduData(Tpdu* respTpdu, uint8_t** respApduBuffer) {
738 uint8_t i;
739 STLOG_HAL_D("%s : Enter", __func__);
740
741 for (i = 0; i < respTpdu->len; i++) {
742 (*respApduBuffer)[i] = respTpdu->data[i];
743 }
744
745 return respTpdu->len;
746 }
747
748 /*******************************************************************************
749 **
750 ** Function T1protocol_doWTXResponse
751 **
752 ** Description If the eSE send a S(WTX request), acknowledge it by sending
753 ** a S(WTX response)
754 **
755 ** Parameters lastRespTpduReceived - Last response received.
756 **
757 ** Returns bytesRead if data was read, 0 if timeout expired with
758 ** no response, -1 otherwise
759 **
760 *******************************************************************************/
T1protocol_doWTXResponse(Tpdu * lastRespTpduReceived)761 int T1protocol_doWTXResponse(Tpdu* lastRespTpduReceived) {
762 Tpdu* TempTpdu = (Tpdu*)malloc(sizeof(Tpdu));
763 TempTpdu->data = (uint8_t*)malloc(ATP.ifsc * sizeof(uint8_t));
764 // Form a SBlock Resynch request Tpdu to sent.
765 int result = Tpdu_formTpdu(NAD_HOST_TO_SLAVE, SBLOCK_WTX_RESPONSE_MASK, 0,
766 NULL, TempTpdu);
767 T1protocol_formSblockResponse(TempTpdu, lastRespTpduReceived);
768 if (result == -1) {
769 free(TempTpdu->data);
770 free(TempTpdu);
771 return -1;
772 }
773
774 // Send the SBlock and read the response from the slave.
775 result = SpiLayerInterface_transcieveTpdu(TempTpdu, lastRespTpduReceived,
776 DEFAULT_NBWT);
777 if (result < 0) {
778 free(TempTpdu->data);
779 free(TempTpdu);
780 return -1;
781 }
782 free(TempTpdu->data);
783 free(TempTpdu);
784 return result;
785 }
786
787 /*******************************************************************************
788 **
789 ** Function T1protocol_doResendRequest
790 **
791 ** Description First thing to do in the recovery mechanism is to ask
792 ** for a retransmission.
793 **
794 ** Parameters lastCmdTpduSent - Last Tpdu sent
795 ** lastRespTpduReceived - Last response received.
796 ** bytesRead - If a retransmission occurs, this
797 ** field contains the amount of bytes read from the slave
798 ** in the new transaction.
799 **
800 ** Returns 0 if everything went fine, -1 if something failed.
801 **
802 *******************************************************************************/
T1protocol_doResendRequest(Tpdu * lastCmdTpduSent,Tpdu * lastRespTpduReceived,int * bytesRead)803 int T1protocol_doResendRequest(Tpdu* lastCmdTpduSent,
804 Tpdu* lastRespTpduReceived, int* bytesRead) {
805 // Form a RBlock - other errors tpdu with the expected sequence number to
806 // receive.
807 int result = Tpdu_formTpdu(
808 NAD_HOST_TO_SLAVE,
809 T1protocol_getValidPcb(RBlock, OtherErrors, 0, SEQ_NUM_SLAVE, 0), 0, NULL,
810 lastCmdTpduSent);
811 if (result == -1) {
812 return -1;
813 }
814
815 // Send the RBlock an read the response
816 result = SpiLayerInterface_transcieveTpdu(lastCmdTpduSent,
817 lastRespTpduReceived, DEFAULT_NBWT);
818 if (result < 0) {
819 return -1;
820 }
821 *bytesRead = result;
822 return 1;
823 }
824
825 /*******************************************************************************
826 **
827 ** Function T1protocol_doResyncRequest
828 **
829 ** Description Second thing to do in the recovery mechanism if the resend
830 ** fails is to perform a Resync.
831 **
832 ** Parameters lastCmdTpduSent - Last Tpdu sent
833 ** lastRespTpduReceived - Last response received.
834 ** bytesRead - If a retransmission occurs, this
835 ** field contains the amount of bytes read from the slave
836 ** in the new transaction.
837 **
838 ** Returns 0 if everything went fine, -1 if something failed.
839 **
840 *******************************************************************************/
T1protocol_doResyncRequest(Tpdu * lastRespTpduReceived)841 int T1protocol_doResyncRequest(Tpdu* lastRespTpduReceived) {
842 Tpdu* TempTpdu = (Tpdu*)malloc(sizeof(Tpdu));
843 TempTpdu->data = (uint8_t*)malloc(ATP.ifsc * sizeof(uint8_t));
844 // Form a SBlock Resynch request Tpdu to sent.
845 int result = Tpdu_formTpdu(NAD_HOST_TO_SLAVE, SBLOCK_RESYNCH_REQUEST_MASK, 0,
846 NULL, TempTpdu);
847 if (result == -1) {
848 free(TempTpdu->data);
849 free(TempTpdu);
850 return -1;
851 }
852
853 // Send the SBlock and read the response from the slave.
854 result = SpiLayerInterface_transcieveTpdu(TempTpdu, lastRespTpduReceived,
855 DEFAULT_NBWT);
856 if (result < 0) {
857 free(TempTpdu->data);
858 free(TempTpdu);
859 return -1;
860 }
861 free(TempTpdu->data);
862 free(TempTpdu);
863 return result;
864 }
865
866 /*******************************************************************************
867 **
868 ** Function T1protocol_doSoftReset
869 **
870 ** Description Third thing to do in the recovery mechanism is to send
871 ** a software reset to reset SPI interface.
872 **
873 ** Parameters lastRespTpduReceived - memory position whre to store the
874 ** response.
875 **
876 ** Returns 1 if interface reseted, -1 if something failed.
877 **
878 *******************************************************************************/
T1protocol_doSoftReset(Tpdu * lastRespTpduReceived)879 int T1protocol_doSoftReset(Tpdu* lastRespTpduReceived) {
880 Tpdu* TempTpdu = (Tpdu*)malloc(sizeof(Tpdu));
881 TempTpdu->data = (uint8_t*)malloc(ATP.ifsc * sizeof(uint8_t));
882 // Form a SBlock Resynch request Tpdu to sent.
883 int result = Tpdu_formTpdu(NAD_HOST_TO_SLAVE, SBLOCK_SWRESET_REQUEST_MASK, 0,
884 NULL, TempTpdu);
885 if (result == -1) {
886 free(TempTpdu->data);
887 free(TempTpdu);
888 return -1;
889 }
890
891 // Send the SBlock and read the response from the slave.
892 result = SpiLayerInterface_transcieveTpdu(TempTpdu, lastRespTpduReceived,
893 DEFAULT_NBWT);
894 if (result < 0) {
895 free(TempTpdu->data);
896 free(TempTpdu);
897 return -1;
898 }
899 free(TempTpdu->data);
900 free(TempTpdu);
901 return result;
902 }
903
904 /*******************************************************************************
905 **
906 ** Function T1protocol_doRecovery
907 **
908 ** Description Implements the recovery mechanism when a non-consistent
909 ** TPDU has been received or no response has been received
910 ** before the timeout.
911 **
912 ** Parameters lastCmdTpduSent - Last Tpdu sent
913 ** lastRespTpduReceived - Last response received.
914 ** bytesRead - If a retransmission occurs, this
915 ** field contains the amount of bytes read from the slave
916 ** in the new transaction.
917 **
918 ** Returns 0 if everything went fine, -1 if something failed.
919 **
920 *******************************************************************************/
T1protocol_doRecovery()921 int T1protocol_doRecovery() {
922 STLOG_HAL_W("Entering recovery");
923
924 // Update the recovery status
925 T1protocol_updateRecoveryStatus();
926
927 // Do the resend request or the resynck request according to the recovery
928 // status
929 switch (recoveryStatus) {
930 case RECOVERY_STATUS_RESEND_1:
931 case RECOVERY_STATUS_RESEND_2:
932 gNextCmd = R_Other_Error;
933 break;
934 case RECOVERY_STATUS_RESYNC_1:
935 case RECOVERY_STATUS_RESYNC_2:
936 case RECOVERY_STATUS_RESYNC_3:
937 gNextCmd = S_Resync_REQ;
938 break;
939 case RECOVERY_STATUS_WARM_RESET:
940
941 // At this point, we consider that SE is dead and a reboot is requried
942 gNextCmd = S_SWReset_REQ;
943 break;
944 case RECOVERY_STATUS_KO:
945 default:
946 return -1;
947 break;
948 }
949
950 return 0;
951 }
952
953 /*******************************************************************************
954 **
955 ** Function T1protocol_handleTpduResponse
956 **
957 ** Description Handles any TPDU response iteratively.
958 **
959 ** Parameters originalCmdTpdu - Original Tpdu sent.
960 ** lastCmdTpduSent - Last Tpdu sent
961 ** lastRespTpduReceived - Last response received.
962 ** bytesRead - If a retransmission occurs, this
963 ** field contains the amount of bytes read from the slave
964 ** in the new transaction.
965 **
966 ** Returns 0 if everything went fine, -1 if something failed.
967 **
968 *******************************************************************************/
T1protocol_handleTpduResponse(Tpdu * originalCmdTpdu,Tpdu * lastCmdTpduSent,Tpdu * lastRespTpduReceived,int * bytesRead)969 int T1protocol_handleTpduResponse(Tpdu* originalCmdTpdu, Tpdu* lastCmdTpduSent,
970 Tpdu* lastRespTpduReceived, int* bytesRead) {
971 int rc = 0;
972 STLOG_HAL_D("%s : Enter :", __func__);
973
974 // If the last transmission ends without response from the slave, do
975 // recovery mechanism.
976 if (*bytesRead == 0) {
977 STLOG_HAL_D("bytesRead = 0 -> Going into recovery.");
978 rc = T1protocol_doRecovery();
979 return rc;
980 }
981
982 // Check the consistency of the last received tpdu
983 rc = T1protocol_checkTpduConsistency(lastCmdTpduSent, lastRespTpduReceived);
984 if (rc < 0) {
985 STLOG_HAL_D("%s : TPDU consistency check failed -> Going into recovery.",
986 __func__);
987 rc = T1protocol_doRecovery();
988 return rc;
989 }
990
991 // Reset the recovery if a valid Tpdu has been received from the slave
992 if (recoveryStatus != RECOVERY_STATUS_OK) {
993 recoveryStatus = RECOVERY_STATUS_OK;
994 }
995
996 // If all went OK, process the last tpdu received
997 TpduType type = Tpdu_getType(lastRespTpduReceived);
998 switch (type) {
999 case IBlock:
1000 rc = T1protocol_processIBlock(originalCmdTpdu, lastRespTpduReceived);
1001 break;
1002
1003 case RBlock:
1004 T1protocol_processRBlock(originalCmdTpdu, lastRespTpduReceived);
1005 break;
1006
1007 case SBlock:
1008 rc = T1protocol_processSBlock(originalCmdTpdu, lastCmdTpduSent,
1009 lastRespTpduReceived);
1010 break;
1011 }
1012
1013 return rc;
1014 }
1015
1016 /*******************************************************************************
1017 **
1018 ** Function T1protocol_formCommandTpduToSend
1019 **
1020 ** Description Form a valid Tpdu to send according to the if we need to
1021 ** send an IBlock or a RBlock.
1022 **
1023 ** Parameters cmdApduPart - Data to sent within an IBlock.
1024 ** cmdLength - Amount of data to sent.
1025 ** isLast - Flag if there are more data to send.
1026 ** cmdTpdu - Resulting Tpdu.
1027 **
1028 ** Returns 0 if everything went fine, -1 if something failed.
1029 **
1030 *******************************************************************************/
T1protocol_formCommandTpduToSend(uint8_t * cmdApduPart,uint8_t cmdLength,bool isLast,Tpdu * cmdTpdu)1031 int T1protocol_formCommandTpduToSend(uint8_t* cmdApduPart, uint8_t cmdLength,
1032 bool isLast, Tpdu* cmdTpdu) {
1033 STLOG_HAL_D("%s : Enter ", __func__);
1034 if (cmdLength == 0) {
1035 // Send RBlock to get the pending IBlock responses from the slave
1036 if (Tpdu_formTpdu(
1037 NAD_HOST_TO_SLAVE,
1038 T1protocol_getValidPcb(RBlock, ErrorFree, 0, SEQ_NUM_SLAVE, isLast),
1039 0, cmdApduPart, cmdTpdu) == -1) {
1040 STLOG_HAL_E("Error forming an RBlock to send.");
1041 return -1;
1042 }
1043 } else {
1044 // Send IBlock containing the data in cmdApduPart. Set it as chained if
1045 // isLast is false.
1046 if (Tpdu_formTpdu(NAD_HOST_TO_SLAVE,
1047 T1protocol_getValidPcb(IBlock, ErrorFree, SEQ_NUM_MASTER,
1048 0, isLast),
1049 cmdLength, cmdApduPart, cmdTpdu) == -1) {
1050 STLOG_HAL_E("Error forming an IBlock to send.");
1051 return -1;
1052 }
1053 }
1054 return 0;
1055 }
1056
1057 /*******************************************************************************
1058 **
1059 ** Function T1protocol_doRequestIFS
1060 **
1061 ** Description Send a IFS request to negotiate the IFSD value. Use the same
1062 ** value for IFSD than the IFSC received in the ATP.
1063 **
1064 ** Parameters None
1065 **
1066 ** Returns 0 if everything went fine, -1 if something failed.
1067 **
1068 *******************************************************************************/
T1protocol_doRequestIFS()1069 int T1protocol_doRequestIFS() {
1070 Tpdu originalCmdTpdu, lastCmdTpduSent, lastRespTpduReceived;
1071 originalCmdTpdu.data = (uint8_t*)malloc(ATP.ifsc * sizeof(uint8_t));
1072 lastCmdTpduSent.data = (uint8_t*)malloc(ATP.ifsc * sizeof(uint8_t));
1073 lastRespTpduReceived.data = (uint8_t*)malloc(ATP.ifsc * sizeof(uint8_t));
1074
1075 STLOG_HAL_D("%s : Enter ", __func__);
1076 // Form a SBlock Resynch request Tpdu to sent.
1077 int result = Tpdu_formTpdu(NAD_HOST_TO_SLAVE, SBLOCK_IFS_REQUEST_MASK, 1,
1078 &ATP.ifsc, &originalCmdTpdu);
1079 if (result) {
1080 return result;
1081 }
1082
1083 Tpdu_copy(&lastCmdTpduSent, &originalCmdTpdu);
1084
1085 // Send the SBlock and read the response from the slave.
1086 result = SpiLayerInterface_transcieveTpdu(
1087 &lastCmdTpduSent, &lastRespTpduReceived, DEFAULT_NBWT);
1088 if (result <= 0) {
1089 return -1;
1090 }
1091
1092 result = T1protocol_handleTpduResponse(&originalCmdTpdu, &lastCmdTpduSent,
1093 &lastRespTpduReceived, &result);
1094
1095 free(originalCmdTpdu.data);
1096 originalCmdTpdu.data = NULL;
1097 free(lastCmdTpduSent.data);
1098 lastCmdTpduSent.data = NULL;
1099 free(lastRespTpduReceived.data);
1100 lastRespTpduReceived.data = NULL;
1101 return result;
1102 }
1103
1104 /*******************************************************************************
1105 **
1106 ** Function T1protocol_init
1107 **
1108 ** Description Initializes the T1 Protocol.
1109 **
1110 ** Parameters tSpiDriver - hardware information
1111 **
1112 ** Returns 0 if everything went fine, -1 if something failed.
1113 **
1114 *******************************************************************************/
T1protocol_init(SpiDriver_config_t * tSpiDriver)1115 int T1protocol_init(SpiDriver_config_t* tSpiDriver) {
1116 STLOG_HAL_D("%s : Enter ", __func__);
1117 if (SpiLayerInterface_init(tSpiDriver) != 0) {
1118 return -1;
1119 }
1120
1121 return 0;
1122 }
1123
1124 /*******************************************************************************
1125 **
1126 ** Function T1protocol_transcieveApduPart
1127 **
1128 ** Description Send and/or receive an APDU part.
1129 **
1130 ** Parameters cmdApduPart - cmdApdu part that shall be sent
1131 ** cmdLength - Length of the cmdApduPart to be sent.
1132 ** isLast - APDU_PART_IS_NOT_LAST/APDU_PART_IS_LAST
1133 ** pRsp - Structure to the response buffer and length.
1134 **
1135 ** Returns 0 if everything went fine, -1 if something failed.
1136 **
1137 *******************************************************************************/
T1protocol_transcieveApduPart(uint8_t * cmdApduPart,uint8_t cmdLength,bool isLast,StEse_data * pRsp)1138 int T1protocol_transcieveApduPart(uint8_t* cmdApduPart, uint8_t cmdLength,
1139 bool isLast, StEse_data* pRsp) {
1140 Tpdu originalCmdTpdu, lastCmdTpduSent, lastRespTpduReceived;
1141 originalCmdTpdu.data = (uint8_t*)malloc(ATP.ifsc * sizeof(uint8_t));
1142 lastCmdTpduSent.data = (uint8_t*)malloc(ATP.ifsc * sizeof(uint8_t));
1143 lastRespTpduReceived.data = (uint8_t*)malloc(ATP.ifsc * sizeof(uint8_t));
1144 StEse_data pRes;
1145
1146 memset(&pRes, 0x00, sizeof(StEse_data));
1147 STLOG_HAL_D("%s : Enter", __func__);
1148
1149 // Form the cmdTpdu according to the cmdApduPart, cmdLength and isLast
1150 // fields.
1151 if (T1protocol_formCommandTpduToSend(cmdApduPart, cmdLength, isLast,
1152 &originalCmdTpdu) < 0) {
1153 return -1;
1154 }
1155
1156 // Send the command Tpdu and receive the response.
1157 int rc;
1158 recoveryStatus = RECOVERY_STATUS_OK;
1159 Tpdu_copy(&lastCmdTpduSent, &originalCmdTpdu);
1160
1161 gNextCmd = I_block;
1162 while (gNextCmd != 0) {
1163 switch (gNextCmd) {
1164 case I_block:
1165 rc = SpiLayerInterface_transcieveTpdu(
1166 &originalCmdTpdu, &lastRespTpduReceived, DEFAULT_NBWT);
1167 if (rc < 0) {
1168 return rc;
1169 }
1170 break;
1171
1172 case R_ACK:
1173 rc = T1protocol_sendRBlock(true, &lastRespTpduReceived);
1174 if (rc < 0) {
1175 return rc;
1176 }
1177 break;
1178 case R_Other_Error:
1179 rc = T1protocol_sendRBlock(false, &lastRespTpduReceived);
1180 if (rc < 0) {
1181 return rc;
1182 }
1183 break;
1184
1185 case S_Resync_REQ:
1186 rc = T1protocol_doResyncRequest(&lastRespTpduReceived);
1187 if (rc < 0) {
1188 return rc;
1189 }
1190 break;
1191
1192 case S_SWReset_REQ:
1193 rc = T1protocol_doSoftReset(&lastRespTpduReceived);
1194 if (rc < 0) {
1195 return rc;
1196 }
1197 break;
1198
1199 case S_WTX_RES:
1200 rc = T1protocol_doWTXResponse(&lastRespTpduReceived);
1201 if (rc < 0) {
1202 return rc;
1203 }
1204 break;
1205
1206 default:
1207 return -1;
1208 break;
1209 }
1210
1211 rc = T1protocol_handleTpduResponse(&originalCmdTpdu, &lastCmdTpduSent,
1212 &lastRespTpduReceived, &rc);
1213
1214 if (rc < 0) {
1215 return rc;
1216 }
1217 }
1218 TpduType type = Tpdu_getType(&lastRespTpduReceived);
1219
1220 if ((type == IBlock) && (DataMgmt_GetData(&pRes.len, &pRes.p_data) != 0)) {
1221 return -1;
1222 }
1223
1224 pRsp->len = pRes.len;
1225 pRsp->p_data = pRes.p_data;
1226
1227 free(originalCmdTpdu.data);
1228 originalCmdTpdu.data = NULL;
1229 free(lastCmdTpduSent.data);
1230 lastCmdTpduSent.data = NULL;
1231 free(lastRespTpduReceived.data);
1232 lastRespTpduReceived.data = NULL;
1233
1234 if ((lastRespTpduReceived.pcb & IBLOCK_M_BIT_MASK) > 0) {
1235 return 1;
1236 }
1237
1238 return 0;
1239 }
1240