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