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 #ifndef _T1PROTOCOL_H_
20 #define _T1PROTOCOL_H_
21 
22 #include <stdbool.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include "SpiLayerInterface.h"
26 #include "StEseApi.h"
27 #include "utils-lib/Tpdu.h"
28 
29 // Recovery states
30 #define RECOVERY_STATUS_OK 0
31 #define RECOVERY_STATUS_RESEND_1 1
32 #define RECOVERY_STATUS_RESEND_2 2
33 #define RECOVERY_STATUS_RESYNC_1 3
34 #define RECOVERY_STATUS_RESYNC_2 4
35 #define RECOVERY_STATUS_RESYNC_3 5
36 #define RECOVERY_STATUS_WARM_RESET 6
37 #define RECOVERY_STATUS_KO 7
38 
39 // Apdu modes
40 #define APDU_PART_IS_LAST true
41 #define APDU_PART_IS_NOT_LAST false
42 
43 // SBlock types
44 #define SBLOCK_WTX_REQUEST_MASK 0b11000011
45 #define SBLOCK_WTX_RESPONSE_MASK 0b11100011
46 #define SBLOCK_IFS_REQUEST_MASK 0b11000001
47 #define SBLOCK_IFS_RESPONSE_MASK 0b11100001
48 #define SBLOCK_ABORT_REQUEST_MASK 0b11000010
49 #define SBLOCK_ABORT_RESPONSE_MASK 0b11100010
50 #define SBLOCK_RESYNCH_REQUEST_MASK 0b11000000
51 #define SBLOCK_RESYNCH_RESPONSE_MASK 0b11100000
52 #define SBLOCK_SWRESET_REQUEST_MASK 0b11001111
53 #define SBLOCK_SWRESET_RESPONSE_MASK 0b11101111
54 
55 // IBlock parameters
56 #define IBLOCK_M_BIT_MASK 0b00100000
57 #define IBLOCK_NS_BIT_MASK 0b01000000
58 
59 #define DEFAULT_NBWT 1
60 
61 // Global variables
62 // uint8_t SEQ_NUM_MASTER;
63 // uint8_t SEQ_NUM_SLAVE;
64 // bool firstTransmission;
65 // uint8_t recoveryStatus;
66 // bool aborted;
67 // uint8_t IFSD;
68 
69 typedef enum {
70   Idle = 0,
71   I_block,
72   R_ACK,
73   R_CRC_Error,
74   R_Other_Error,
75   S_Resync_REQ,
76   S_Resync_RES,
77   S_IFS_REQ,
78   S_IFS_RES,
79   S_WTX_RES,
80   S_SWReset_REQ
81 } T1TProtocol_TransceiveState;
82 /**
83  * Form a valid pcb according to the Tpdu type, subtype, master sequence number,
84  * slave sequence number and isLast.
85  *
86  * @param type The Tpdu type (IBlock, RBlock or SBlock).
87  * @param subtype The different subtype options when using RBlock. Error free,
88  * checksum error or other errors.
89  * @param numSeqMaster Master sequence number.
90  * @param numseqSlave Slave sequence number.
91  * @param isLast Indicate if there are more tpdus to send within the same APDU.
92  *
93  * @return pcb The value of the pcb computed.
94  */
95 uint8_t T1protocol_getValidPcb(TpduType type, RBlockType subtype,
96                                uint8_t numSeqMaster, uint8_t numseqSlave,
97                                bool isLast);
98 
99 /**
100  * Check if the checksum of a given tpdu is well formed.
101  *
102  * @param tpdu Tpdu to check.
103  *
104  * @return 0 If checksum is ok, -1 otherwise.
105  */
106 int T1protocol_checkResponseTpduChecksum(Tpdu *tpdu);
107 
108 /**
109  * Check if the pcb of a given tpdu is valid.
110  *
111  * @param tpdu Tpdu to check.
112  *
113  * @return 0 If checksum is ok, -1 otherwise.
114  */
115 int T1protocol_checkResponsePcbConsistency(Tpdu *tpdu);
116 
117 /**
118  * Check if the length field of a given tpdu is valid.
119  *
120  * @param tpdu Tpdu to check.
121  *
122  * @return 0 If checksum is ok, -1 otherwise.
123  */
124 int T1protocol_checkResponseLenConsistency(Tpdu *tpdu);
125 
126 /**
127  * Check if the sequence number of a given tpdu is valid.
128  *
129  * @param tpdu Tpdu to check.
130  *
131  * @return 0 If checksum is ok, -1 otherwise.
132  */
133 int T1protocol_checkResponseSeqNumberConsistency(Tpdu *tpdu);
134 
135 /**
136  * Check if an SBlock response was received after having transmitted a SBlock
137  * request.
138  *
139  * @param lastCmdTpduSent Last Tpdu sent.
140  * @param lastRespTpduReceived Response received.
141  *
142  * @return 0 If checksum is ok, -1 otherwise.
143  */
144 int T1protocol_checkSBlockResponseConsistency(Tpdu *lastCmdTpduSent,
145                                               Tpdu *lastRespTpduReceived);
146 
147 /**
148  * Check if the response TPDU is consistent (check the checksum, check if the
149  * pcb is valid and the expected one and check the len consistency).
150  *
151  * @param lastCmdTpduSent Last Tpdu sent, could be different than the
152  * originalCmdTpdu if there was retransmissions request or SBlocks.
153  * @param lastRespTpduReceived Last response received from the slave.
154  *
155  * @return 0 If consistency is ok, -1 otherwise.
156  */
157 int T1protocol_checkTpduConsistency(Tpdu *lastCmdTpduSent,
158                                     Tpdu *lastRespTpduReceived);
159 
160 /**
161  * Set the sequence numbers to it's initial values.
162  */
163 void T1protocol_resetSequenceNumbers();
164 
165 /**
166  * Update the master sequence number. Increase the value, taking into account is
167  * module 2 type.
168  */
169 void T1protocol_updateMasterSequenceNumber();
170 
171 /**
172  * Update the slave sequence number. Increase the value, taking into account is
173  * module 2 type.
174  */
175 void T1protocol_updateSlaveSequenceNumber();
176 
177 /**
178  * Process the last IBlock received from the slave.
179  *
180  * @param originalCmdTpdu Original Tpdu sent.
181  * @param lastRespTpduReceived Last response received from the slave.
182  *
183  * @return 0 If all went is ok, -1 otherwise.
184  */
185 int T1protocol_processIBlock(Tpdu* originalCmdTpdu, Tpdu* lastRespTpduReceived);
186 
187 /**
188  * Process the last RBlock received from the slave.
189  *
190  * @param originalCmdTpdu Original Tpdu sent.
191  * @param lastRespTpduReceived Last response received from the slave.
192  *
193  */
194 void T1protocol_processRBlock(Tpdu *originalCmdTpdu,
195                               Tpdu *lastRespTpduReceived);
196 
197 /**
198  * Process the last RBlock received from the slave.
199  *
200  * @param rack if 1, send a ack frame, nack otherwise.
201  * @param lastRespTpduReceived Last response received from the slave.
202  *
203  * @return -1 if the retransmission needed fails, 0 if no more retransmission
204  * were needed and 1 if extra retransmission success.
205  */
206 int T1protocol_sendRBlock(int rack, Tpdu *lastRespTpduReceived);
207 
208 /**
209  * Form a SBlock response according to a given SBlock Request.
210  *
211  * @param responseTpdu A valid SBlock response according to the SBlock request
212  * in the requestTpdu param.
213  * @param requestTpdu The Sblock request received from the eSE to process.
214  *
215  * @return 0 If all went is ok, -1 otherwise.
216  */
217 int T1protocol_formSblockResponse(Tpdu *responseTpdu, Tpdu *requestTpdu);
218 
219 /**
220  * Process the last SBlock received from the slave.
221  *
222  * @param originalCmdTpdu Original Tpdu sent.
223  * @param lastCmdTpduSent Last Tpdu sent, could be different than the
224  * originalCmdTpdu if there was retransmissions request or SBlocks.
225  * @param lastRespTpduReceived Last response received from the slave.
226  *
227  * @return -1 if the extra retransmission needed fails or  1 if extra
228  * retransmission success.
229  */
230 int T1protocol_processSBlock(Tpdu *originalCmdTpdu, Tpdu *lastCmdTpduSent,
231                              Tpdu *lastRespTpduReceived);
232 
233 /**
234  * Check if the sequence number of the response TPDU is the expected one.
235  *
236  * @param originalTpdu The original tpdu sent.
237  * @param respTpdu The last response received from the slave.
238  *
239  * @return true If sequence number is ok, false otherwise.
240  */
241 bool T1protocol_isSequenceNumberOk(Tpdu *originalTpdu, Tpdu *respTpdu);
242 
243 /**
244  * Updates the recovery state to the following step.
245  */
246 void T1protocol_updateRecoveryStatus();
247 
248 /**
249  * Copy the data in the response Tpdu into the respApduBuffer.
250  *
251  * @param respTpdu Response tpdu where the data is stored.
252  * @param respApduBuffer Apdu buffer where to store the data received in the
253  * response Tpdu.
254  *
255  * @return The amount of data bytes saved into the apdu buffer.
256  */
257 uint8_t T1protocol_setRespApduData(Tpdu *respTpdu, uint8_t *respApduBuffer);
258 
259 /**
260  * If the eSE send a S(WTX request), acknowledge it by sending
261  * a S(WTX response)
262  *
263  * @param lastRespTpduReceived Last response received from the slave.
264  *
265  * @return bytesRead if data was read, 0 if timeout expired with
266  *         no response, -1 otherwise
267  */
268 int T1protocol_doWTXResponse(Tpdu *lastRespTpduReceived);
269 
270 /**
271  * The first thing to do in the recovery mechanism is to ask for a
272  * retransmission.
273  *
274  * @param lastCmdTpduSent Last Tpdu sent, could be different than the
275  * originalCmdTpdu if there was retransmissions request or SBlocks.
276  * @param lastRespTpduReceived Last response received from the slave.
277  * @param bytesRead If a retransmission occurs, this field contains the amout of
278  * bytes read from the slave in the new transaction.
279  *
280  * @return 0 if everything went fine, -1 if something failed.
281  */
282 int T1protocol_doResendRequest(Tpdu *lastCmdTpduSent,
283                                Tpdu *lastRespTpduReceived, int *bytesRead);
284 
285 /**
286  * The second thing to do in the recovery mechanism if the resend fails
287  * is to perform a Resync.
288  *
289  * @param lastCmdTpduSent Last Tpdu sent, could be different than the
290  * originalCmdTpdu if there was retransmissions request or SBlocks.
291  * @param lastRespTpduReceived Last response received from the slave.
292  * @param bytesRead If a retransmission occurs, this field contains the amout of
293  * bytes read from the slave in the new transaction.
294  *
295  * @return 0 if everything went fine, -1 if something failed.
296  */
297 int T1protocol_doResyncRequest(Tpdu *lastRespTpduReceived);
298 
299 /**
300  * Implements the recovery mechanism when a non-consistent TPDU has been
301  * received or no response has been received before the timeout.
302  *
303  * @param lastCmdTpduSent Last Tpdu sent, could be different than the
304  * originalCmdTpdu if there was retransmissions request or SBlocks.
305  * @param lastRespTpduReceived Last response received from the slave.
306  * @param bytesRead If a retransmission occurs, this field contains the amout of
307  * bytes read from the slave in the new transaction.
308  *
309  * @return 0 if everything went fine,
310  *        -1 if something failed, or
311  *         RC_WARM_RESET_REQUIERD if a warm reset needs to be performed.
312  *       TODO: If a warm reset needs to be performed, the service will die
313  *       and the user will need do the reset manually, as Power Manager is not
314  *       yet implemented.
315  */
316 int T1protocol_doRecovery();
317 
318 /**
319  * Send a soft reset (S-Block)
320  *
321  * @param lastRespTpduReceived Last response received from the slave.
322  *
323  * @return 0 if everything went fine, -1 if an error occurred.
324  */
325 int T1protocol_doSoftReset(Tpdu *lastRespTpduReceived);
326 
327 /**
328  * Send IFS request(S-Block)
329  *
330  * @param  None.
331  *
332  * @return 0 if everything went fine, -1 if an error occurred.
333  */
334 int T1protocol_doRequestIFS(Tpdu* lastRespTpduReceived);
335 
336 /**
337  * Handles any TPDU response iteratively.
338  *
339  * @param originalCmdTpdu Original Tpdu sent.
340  * @param lastCmdTpduSent Last Tpdu sent, could be different than the
341  * originalCmdTpdu if there was retransmissions request or SBlocks.
342  * @param lastRespTpduReceived Last response received from the slave.
343  * @param bytesRead If a retransmission occurs, this field contains the amout of
344  * bytes read from the slave in the new transaction.
345  *
346  * @return 0 if everything went fine, -1 if an error occurred.
347  */
348 int T1protocol_handleTpduResponse(Tpdu *originalCmdTpdu, Tpdu *lastCmdTpduSent,
349                                   Tpdu *lastRespTpduReceived, int *bytesRead);
350 
351 /**
352  * Form a valid Tpdu to send according to the if we need to send
353  * an IBlock or a RBlock (for chained response from the slave).
354  *
355  * @param cmdApduPart Data to sent within an IBlock.
356  * @param cmdLength Amount of data to sent.
357  * @param isLast Flag indicating if there are more data to send.
358  * @param cmdTpdu Resulting Tpdu.
359  *
360  * @return 0 if everything went fine, -1 if something failed.
361  */
362 int T1protocol_formCommandTpduToSend(uint8_t *cmdApduPart, uint8_t cmdLength,
363                                      bool isLast, Tpdu *cmdTpdu);
364 
365 /**
366  * Initializes the T1 Protocol.
367  *
368  * @return 0 if initialization was ok, -1 otherwise.
369  */
370 int T1protocol_init(SpiDriver_config_t *tSpiDriver);
371 
372 /**
373  * This method is used to send and/or receive an APDU part. There are 3 ways of
374  * calling it:
375  * 1. transcieveApduPart(&cmdApduPart, cmdLength, APDU_PART_IS_NOT_LAST, null,
376  *      null): will send an APDU part and expect no response.
377  * 2. transcieveApduPart(&cmdApduPart, cmdLength, APDU_PART_IS_LAST,
378  *      &respApduPart, &respLength): will send an APDU part and get a response
379  *      part.
380  * 3. transcieveApduPart(null, null, null, &respApduPart, &respLength): sends no
381  *      APDU part and gets a response part.
382  *
383  * It will for and send the required TPDU, receive the response and handle it.
384  *
385  * @param cmdApduPart The cmdApdu part that shall be sent (or null).
386  * @param cmdLength The length of the cmdApduPart to be sent (or null).
387  * @param isLast Either APDU_PART_IS_NOT_LAST or APDU_PART_IS_LAST (or null).
388  * @param pRsp Structure to the response buffer and length.
389  *      (or null).
390  *
391  * @return If no response is expected:
392  *          - 0 if everything was ok
393  *          - -1 if an error occurred
394  *         If response is expected:
395  *          - 0 if it is the last response part
396  *          - 1 if there are more response parts
397  *          - -1 if an error occurred.
398  */
399 int T1protocol_transcieveApduPart(uint8_t* cmdApduPart, uint8_t cmdLength,
400                                   bool isLast, StEse_data* pRsp,
401                                   T1TProtocol_TransceiveState Block_type);
402 
403 #endif /* _T1PROTOCOL_H_ */
404