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