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