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