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 
20 #include "Tpdu.h"
21 
22 #include "Iso13239CRC.h"
23 
24 /*******************************************************************************
25 **
26 ** Function        Tpdu_toByteArray
27 **
28 ** Description     Forms a byte array representing the given TPDU.
29 **
30 ** Parameters      structTpdu - TPDU struct to be converted to byte array.
31 **                 baTpdu     - Memory position where to store the formed
32 **                              byte array.
33 **
34 ** Returns        length of the formed array, -1 if there is an error.
35 **
36 *******************************************************************************/
Tpdu_toByteArray(Tpdu * structTpdu,uint8_t * baTpdu)37 uint16_t Tpdu_toByteArray(Tpdu *structTpdu, uint8_t *baTpdu) {
38   // NAD - Copy the nad into the nad array position
39   baTpdu[NAD_OFFSET_IN_TPDU] = structTpdu->nad;
40 
41   // PCB - Copy the pcb into the pcb array position
42   baTpdu[PCB_OFFSET_IN_TPDU] = structTpdu->pcb;
43 
44   // Length - Copy the length into the length array position
45   baTpdu[LEN_OFFSET_IN_TPDU] = structTpdu->len;
46 
47   // Data - Copy the data into the data array position
48   uint8_t i;
49   for (i = 0; i < structTpdu->len; i++) {
50     baTpdu[DATA_OFFSET_IN_TPDU + i] = structTpdu->data[i];
51   }
52 
53   // Compute where the checksum shall be stored.
54   uint16_t checksumOffsetInTpdu = DATA_OFFSET_IN_TPDU + structTpdu->len;
55 
56   uint16_t length;
57   uint8_t checksum[2];
58   switch (ATP.checksumType) {
59     case LRC:
60       Tpdu_getChecksumBytes(structTpdu, checksum);
61       baTpdu[checksumOffsetInTpdu] = checksum[0];
62       length = checksumOffsetInTpdu + 1;
63       break;
64     case CRC:
65     default:
66       Tpdu_getChecksumBytes(structTpdu, checksum);
67       baTpdu[checksumOffsetInTpdu] = checksum[0];
68       baTpdu[checksumOffsetInTpdu + 1] = checksum[1];
69       length = checksumOffsetInTpdu + 2;
70       break;
71   }
72 
73   return length;
74 }
75 
76 /*******************************************************************************
77 **
78 ** Function        Tpdu_isChecksumOk
79 **
80 ** Description     Checks that the checksum in the TPDU is as expected.
81 **
82 ** Parameters      tpdu - TPDU whose checksum needs to be checked.
83 **
84 ** Returns        true if checksum is ok, false otherwise.
85 **
86 *******************************************************************************/
Tpdu_isChecksumOk(Tpdu * tpdu)87 bool Tpdu_isChecksumOk(Tpdu *tpdu) {
88   switch (ATP.checksumType) {
89     case LRC:
90       // TODO: implement
91       return false;
92     case CRC:;
93       uint8_t buffer[TPDU_MAX_LENGTH];
94       Tpdu_toByteArray(tpdu, buffer);
95       if (tpdu->checksum ==
96           computeCrc(buffer, (TPDU_PROLOGUE_LENGTH + tpdu->len))) {
97         return true;
98       } else {
99         return false;
100       }
101   }
102 }
103 
104 /*******************************************************************************
105 **
106 ** Function        Tpdu_formTpdu
107 **
108 ** Description     Forms a TPDU with the specified fields.
109 **
110 ** Parameters      nad   - NAD byte of the TPDU.
111 **                 pcb   - PCB byte of the TPDU.
112 **                 len   - Length of the data
113 **                 data  - data of the TPDU
114 **                 tpdu  - output TPDU struct
115 **
116 ** Returns         0 if everything went ok, -1 otherwise.
117 **
118 *******************************************************************************/
Tpdu_formTpdu(uint8_t nad,uint8_t pcb,uint8_t len,uint8_t * data,Tpdu * tpdu)119 int Tpdu_formTpdu(uint8_t nad, uint8_t pcb, uint8_t len, uint8_t *data,
120                   Tpdu *tpdu) {
121   uint8_t i;
122 
123   if (len > TPDU_MAX_DATA_LENGTH) {
124     return -1;
125   }
126   // NAD - Copy the incoming nad into the tpdu nad
127   tpdu->nad = nad;
128   // PCB - Copy the incoming pcb into the tpdu pcb
129   tpdu->pcb = pcb;
130   // Length - Copy the incoming len into the tpdu len
131   tpdu->len = len;
132 
133   // Data - Copy the incoming data into the tpdu data
134   // TODO: check if it will ever be overwritten
135   for (i = 0; i < len; i++) {
136     tpdu->data[i] = data[i];
137   }
138   // tpdu->data = data;
139   // Checksum - Calculate the checksum according to the prologue + data fields
140   // and copy into the tpdu checksum
141   switch (ATP.checksumType) {
142     case LRC:
143       // TODO: implement
144       return -1;
145     case CRC:
146       // Set temporally checksum to 0 to be able to convert the tpdu struct
147       // to an array
148       tpdu->checksum = 0;
149 
150       // Create a buffer to store the tpdu to compute the CRC.
151       uint8_t buffer[TPDU_MAX_LENGTH];
152       Tpdu_toByteArray(tpdu, buffer);
153 
154       // Calculate the crc
155       tpdu->checksum = computeCrc(buffer, (TPDU_PROLOGUE_LENGTH + tpdu->len));
156       break;
157   }
158 
159   return 0;
160 }
161 
162 /*******************************************************************************
163 **
164 ** Function        Tpdu_getChecksumBytes
165 **
166 ** Description     Get the checksum value in the form of a byte array.
167 **
168 ** Parameters      tpdu          - TPDU from where to get the checksum value.
169 **                 checksumBytes - mem postion whre to store the result.
170 **
171 ** Returns         void
172 **
173 *******************************************************************************/
Tpdu_getChecksumBytes(Tpdu * tpdu,uint8_t * checksumBytes)174 void Tpdu_getChecksumBytes(Tpdu *tpdu, uint8_t *checksumBytes) {
175   switch (ATP.checksumType) {
176     case LRC:
177       checksumBytes[0] = (uint8_t)tpdu->checksum;
178       break;
179     case CRC:
180       checksumBytes[0] = (uint8_t)tpdu->checksum;
181       checksumBytes[1] = (uint8_t)(tpdu->checksum >> 8);
182       break;
183   }
184 }
185 
186 /*******************************************************************************
187 **
188 ** Function        Tpdu_getChecksumValue
189 **
190 ** Description     Gets the value of the checksum stored in the array.
191 **
192 ** Parameters      array          - array that contains the checksum.
193 **                 checksumStartPosition
194 **                 checksumType  -Checksum type (LRC or CRC)
195 **
196 ** Returns         checksum value
197 **
198 *******************************************************************************/
Tpdu_getChecksumValue(uint8_t * array,int checksumStartPosition,ChecksumType checksumType)199 uint16_t Tpdu_getChecksumValue(uint8_t *array, int checksumStartPosition,
200                                ChecksumType checksumType) {
201   switch (checksumType) {
202     case LRC:
203       return (uint16_t)array[checksumStartPosition];
204     case CRC:
205       return (uint16_t)(array[checksumStartPosition + 1] << 8) |
206              array[checksumStartPosition];
207   }
208 }
209 
210 /*******************************************************************************
211 **
212 ** Function        Tpdu_getType
213 **
214 ** Description     Returns the type of the TPDU.
215 **
216 ** Parameters      tpdu   - the  tpdu the type has to be get.
217 **
218 ** Returns         TPDU type (I-Block, R-Block or S-Block)
219 **
220 *******************************************************************************/
Tpdu_getType(Tpdu * tpdu)221 TpduType Tpdu_getType(Tpdu *tpdu) {
222   if ((tpdu->pcb & 0x80) == 0x00) {
223     return IBlock;
224   } else if ((tpdu->pcb & 0xC0) == 0x80) {
225     return RBlock;
226   } else {
227     return SBlock;
228   }
229 }
230 
231 /*******************************************************************************
232 **
233 ** Function        Tpdu_copy
234 **
235 ** Description     Copy a Tpdu Struct to an another one.
236 **
237 ** Parameters      dest   - the destination tpdu
238 **                 src    - the tpdu to be copied
239 **
240 ** Returns         void
241 **
242 *******************************************************************************/
Tpdu_copy(Tpdu * dest,Tpdu * src)243 void Tpdu_copy(Tpdu *dest, Tpdu *src) {
244   dest->checksum = src->checksum;
245   dest->len = src->len;
246   dest->nad = src->nad;
247   dest->pcb = src->pcb;
248   if (dest->data == NULL) {
249     dest->data = (uint8_t *)malloc(ATP.ifsc * sizeof(uint8_t));
250   }
251   if (((src->len) > 0) && ((src->len) < ATP.ifsc)) {
252     memcpy(dest->data, src->data, src->len);
253   }
254 }
255 
256 /*******************************************************************************
257 **
258 ** Function        Tpdu_toHexString
259 **
260 ** Description     Converts the TPDU in hex string buffer.
261 **
262 ** Parameters      tpdu            - input tpdu
263 **                 hexStringBuffer - output hex buffer
264 **
265 **
266 ** Returns         void
267 **
268 *******************************************************************************/
Tpdu_toHexString(Tpdu * tpdu,uint8_t * hexStringBuffer)269 void Tpdu_toHexString(Tpdu *tpdu, uint8_t *hexStringBuffer) {
270   uint8_t buffer[tpdu->len + 5];
271   uint16_t length = Tpdu_toByteArray(tpdu, buffer);
272   char *ptr = (char *)hexStringBuffer;
273   int i;
274   for (i = 0; i < length; i++) {
275     ptr += sprintf(ptr, "%02X ", (char)buffer[i]);
276   }
277 }
278