Added loclass-functionality into the pm3,the functionality provided by loclass can...
[proxmark3-svn] / armsrc / mifarecmd.c
CommitLineData
8556b852 1//-----------------------------------------------------------------------------\r
b62a5a84 2// Merlok - June 2011, 2012\r
8556b852
M
3// Gerhard de Koning Gans - May 2008\r
4// Hagen Fritsch - June 2010\r
5//\r
6// This code is licensed to you under the terms of the GNU GPL, version 2 or,\r
7// at your option, any later version. See the LICENSE.txt file for the text of\r
8// the license.\r
9//-----------------------------------------------------------------------------\r
10// Routines to support ISO 14443 type A.\r
11//-----------------------------------------------------------------------------\r
12\r
13#include "mifarecmd.h"\r
14#include "apps.h"\r
15\r
16//-----------------------------------------------------------------------------\r
baeaf579 17// Select, Authenticate, Read a MIFARE tag. \r
8556b852
M
18// read block\r
19//-----------------------------------------------------------------------------\r
20void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)\r
21{\r
22 // params\r
23 uint8_t blockNo = arg0;\r
24 uint8_t keyType = arg1;\r
25 uint64_t ui64Key = 0;\r
26 ui64Key = bytes_to_num(datain, 6);\r
27 \r
28 // variables\r
29 byte_t isOK = 0;\r
30 byte_t dataoutbuf[16];\r
1c611bbd 31 uint8_t uid[10];\r
8556b852
M
32 uint32_t cuid;\r
33 struct Crypto1State mpcs = {0, 0};\r
34 struct Crypto1State *pcs;\r
35 pcs = &mpcs;\r
36\r
37 // clear trace\r
baeaf579 38 iso14a_clear_trace();\r
8556b852
M
39// iso14a_set_tracing(false);\r
40\r
7bc95e2e 41 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);\r
8556b852
M
42\r
43 LED_A_ON();\r
44 LED_B_OFF();\r
45 LED_C_OFF();\r
46\r
47 while (true) {\r
48 if(!iso14443a_select_card(uid, NULL, &cuid)) {\r
baeaf579 49 if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");\r
8556b852
M
50 break;\r
51 };\r
52\r
53 if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {\r
baeaf579 54 if (MF_DBGLEVEL >= 1) Dbprintf("Auth error");\r
8556b852
M
55 break;\r
56 };\r
57 \r
58 if(mifare_classic_readblock(pcs, cuid, blockNo, dataoutbuf)) {\r
baeaf579 59 if (MF_DBGLEVEL >= 1) Dbprintf("Read block error");\r
8556b852
M
60 break;\r
61 };\r
62\r
63 if(mifare_classic_halt(pcs, cuid)) {\r
baeaf579 64 if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");\r
8556b852
M
65 break;\r
66 };\r
67 \r
68 isOK = 1;\r
69 break;\r
70 }\r
71 \r
72 // ----------------------------- crypto1 destroy\r
73 crypto1_destroy(pcs);\r
74 \r
75 if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED");\r
76\r
8556b852 77 LED_B_ON();\r
baeaf579 78 cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16);\r
8556b852
M
79 LED_B_OFF();\r
80\r
baeaf579 81 // Thats it...\r
8556b852
M
82 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
83 LEDsoff();\r
84// iso14a_set_tracing(TRUE);\r
7cc204bf 85\r
86}\r
87\r
88void MifareUReadBlock(uint8_t arg0,uint8_t *datain)\r
89{\r
90 // params\r
91 uint8_t blockNo = arg0;\r
92 \r
93 // variables\r
94 byte_t isOK = 0;\r
95 byte_t dataoutbuf[16];\r
96 uint8_t uid[10];\r
97 uint32_t cuid;\r
98 \r
99 // clear trace\r
100 iso14a_clear_trace();\r
7bc95e2e 101 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);\r
7cc204bf 102 \r
103 LED_A_ON();\r
104 LED_B_OFF();\r
105 LED_C_OFF();\r
106 \r
107 while (true) {\r
108 if(!iso14443a_select_card(uid, NULL, &cuid)) {\r
109 if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");\r
110 break;\r
111 };\r
112 \r
113 if(mifare_ultra_readblock(cuid, blockNo, dataoutbuf)) {\r
114 if (MF_DBGLEVEL >= 1) Dbprintf("Read block error");\r
115 break;\r
116 };\r
117 \r
118 if(mifare_ultra_halt(cuid)) {\r
119 if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");\r
120 break;\r
121 };\r
122 \r
123 isOK = 1;\r
124 break;\r
125 }\r
126 \r
127 if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED");\r
128 \r
7cc204bf 129 LED_B_ON();\r
6a1f2d82 130 cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16);\r
7cc204bf 131 LED_B_OFF();\r
132 \r
133 \r
134 // Thats it...\r
135 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
136 LEDsoff();\r
137}\r
138\r
baeaf579 139\r
7cc204bf 140//-----------------------------------------------------------------------------\r
baeaf579 141// Select, Authenticate, Read a MIFARE tag. \r
142// read sector (data = 4 x 16 bytes = 64 bytes, or 16 x 16 bytes = 256 bytes)\r
8556b852
M
143//-----------------------------------------------------------------------------\r
144void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)\r
145{\r
146 // params\r
147 uint8_t sectorNo = arg0;\r
148 uint8_t keyType = arg1;\r
149 uint64_t ui64Key = 0;\r
150 ui64Key = bytes_to_num(datain, 6);\r
151 \r
152 // variables\r
baeaf579 153 byte_t isOK;\r
154 byte_t dataoutbuf[16 * 16];\r
1c611bbd 155 uint8_t uid[10];\r
8556b852
M
156 uint32_t cuid;\r
157 struct Crypto1State mpcs = {0, 0};\r
158 struct Crypto1State *pcs;\r
159 pcs = &mpcs;\r
160\r
161 // clear trace\r
baeaf579 162 iso14a_clear_trace();\r
8556b852
M
163// iso14a_set_tracing(false);\r
164\r
7bc95e2e 165 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);\r
8556b852
M
166\r
167 LED_A_ON();\r
168 LED_B_OFF();\r
169 LED_C_OFF();\r
170\r
baeaf579 171 isOK = 1;\r
172 if(!iso14443a_select_card(uid, NULL, &cuid)) {\r
173 isOK = 0;\r
8556b852 174 if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");\r
baeaf579 175 }\r
8556b852 176\r
baeaf579 177 \r
178 if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) {\r
179 isOK = 0;\r
8556b852 180 if (MF_DBGLEVEL >= 1) Dbprintf("Auth error");\r
baeaf579 181 }\r
182 \r
183 for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) {\r
184 if(mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf + 16 * blockNo)) {\r
185 isOK = 0;\r
186 if (MF_DBGLEVEL >= 1) Dbprintf("Read sector %2d block %2d error", sectorNo, blockNo);\r
8556b852 187 break;\r
baeaf579 188 }\r
189 }\r
8556b852 190 \r
baeaf579 191 if(mifare_classic_halt(pcs, cuid)) {\r
8556b852 192 if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");\r
8556b852 193 }\r
baeaf579 194\r
8556b852
M
195 \r
196 // ----------------------------- crypto1 destroy\r
197 crypto1_destroy(pcs);\r
198 \r
199 if (MF_DBGLEVEL >= 2) DbpString("READ SECTOR FINISHED");\r
200\r
8556b852 201 LED_B_ON();\r
baeaf579 202 cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,16*NumBlocksPerSector(sectorNo));\r
6e82300d 203 LED_B_OFF();\r
8556b852
M
204\r
205 // Thats it...\r
206 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
207 LEDsoff();\r
208// iso14a_set_tracing(TRUE);\r
7cc204bf 209}\r
210\r
baeaf579 211\r
7cc204bf 212void MifareUReadCard(uint8_t arg0, uint8_t *datain)\r
213{\r
214 // params\r
215 uint8_t sectorNo = arg0;\r
216 \r
217 // variables\r
218 byte_t isOK = 0;\r
219 byte_t dataoutbuf[16 * 4];\r
220 uint8_t uid[10];\r
221 uint32_t cuid;\r
222\r
223 // clear trace\r
224 iso14a_clear_trace();\r
225// iso14a_set_tracing(false);\r
226\r
7bc95e2e 227 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);\r
7cc204bf 228\r
229 LED_A_ON();\r
230 LED_B_OFF();\r
231 LED_C_OFF();\r
232\r
233 while (true) {\r
234 if(!iso14443a_select_card(uid, NULL, &cuid)) {\r
235 if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");\r
236 break;\r
237 };\r
238 for(int sec=0;sec<16;sec++){\r
239 if(mifare_ultra_readblock(cuid, sectorNo * 4 + sec, dataoutbuf + 4 * sec)) {\r
240 if (MF_DBGLEVEL >= 1) Dbprintf("Read block %d error",sec);\r
241 break;\r
242 };\r
243 }\r
244 if(mifare_ultra_halt(cuid)) {\r
245 if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");\r
246 break;\r
247 };\r
248\r
249 isOK = 1;\r
250 break;\r
251 }\r
252 \r
253 if (MF_DBGLEVEL >= 2) DbpString("READ CARD FINISHED");\r
254\r
7cc204bf 255 LED_B_ON();\r
256 cmd_send(CMD_ACK,isOK,0,0,dataoutbuf,64);\r
7cc204bf 257 LED_B_OFF();\r
258\r
259 // Thats it...\r
260 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
261 LEDsoff();\r
7cc204bf 262\r
263}\r
264\r
265\r
266//-----------------------------------------------------------------------------\r
baeaf579 267// Select, Authenticate, Write a MIFARE tag. \r
7cc204bf 268// read block\r
8556b852
M
269//-----------------------------------------------------------------------------\r
270void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)\r
271{\r
272 // params\r
273 uint8_t blockNo = arg0;\r
274 uint8_t keyType = arg1;\r
275 uint64_t ui64Key = 0;\r
276 byte_t blockdata[16];\r
277\r
278 ui64Key = bytes_to_num(datain, 6);\r
279 memcpy(blockdata, datain + 10, 16);\r
280 \r
281 // variables\r
282 byte_t isOK = 0;\r
1c611bbd 283 uint8_t uid[10];\r
8556b852
M
284 uint32_t cuid;\r
285 struct Crypto1State mpcs = {0, 0};\r
286 struct Crypto1State *pcs;\r
287 pcs = &mpcs;\r
288\r
289 // clear trace\r
d19929cb 290 iso14a_clear_trace();\r
8556b852
M
291// iso14a_set_tracing(false);\r
292\r
7bc95e2e 293 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);\r
8556b852
M
294\r
295 LED_A_ON();\r
296 LED_B_OFF();\r
297 LED_C_OFF();\r
298\r
299 while (true) {\r
300 if(!iso14443a_select_card(uid, NULL, &cuid)) {\r
301 if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");\r
302 break;\r
303 };\r
304\r
305 if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {\r
306 if (MF_DBGLEVEL >= 1) Dbprintf("Auth error");\r
307 break;\r
308 };\r
309 \r
310 if(mifare_classic_writeblock(pcs, cuid, blockNo, blockdata)) {\r
311 if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");\r
312 break;\r
313 };\r
314\r
315 if(mifare_classic_halt(pcs, cuid)) {\r
316 if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");\r
317 break;\r
318 };\r
319 \r
320 isOK = 1;\r
321 break;\r
322 }\r
323 \r
324 // ----------------------------- crypto1 destroy\r
325 crypto1_destroy(pcs);\r
326 \r
327 if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED");\r
328\r
8556b852 329 LED_B_ON();\r
9492e0b0 330 cmd_send(CMD_ACK,isOK,0,0,0,0);\r
6e82300d 331 LED_B_OFF();\r
8556b852
M
332\r
333\r
334 // Thats it...\r
335 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
336 LEDsoff();\r
337// iso14a_set_tracing(TRUE);\r
7cc204bf 338\r
339}\r
340\r
baeaf579 341\r
7cc204bf 342void MifareUWriteBlock(uint8_t arg0, uint8_t *datain)\r
343{\r
344 // params\r
345 uint8_t blockNo = arg0;\r
346 byte_t blockdata[16];\r
347\r
348 memset(blockdata,'\0',16);\r
349 memcpy(blockdata, datain,16);\r
350 \r
351 // variables\r
352 byte_t isOK = 0;\r
353 uint8_t uid[10];\r
354 uint32_t cuid;\r
355\r
356 // clear trace\r
357 iso14a_clear_trace();\r
358 // iso14a_set_tracing(false);\r
359\r
7bc95e2e 360 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);\r
7cc204bf 361\r
362 LED_A_ON();\r
363 LED_B_OFF();\r
364 LED_C_OFF();\r
365\r
366 while (true) {\r
367 if(!iso14443a_select_card(uid, NULL, &cuid)) {\r
368 if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");\r
369 break;\r
370 };\r
371\r
372 if(mifare_ultra_writeblock(cuid, blockNo, blockdata)) {\r
373 if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");\r
374 break;\r
375 };\r
376\r
377 if(mifare_ultra_halt(cuid)) {\r
378 if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");\r
379 break;\r
380 };\r
381 \r
382 isOK = 1;\r
383 break;\r
384 }\r
385 \r
386 if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED");\r
387\r
7cc204bf 388 LED_B_ON();\r
baeaf579 389 cmd_send(CMD_ACK,isOK,0,0,0,0);\r
7cc204bf 390 LED_B_OFF();\r
391\r
392\r
393 // Thats it...\r
394 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
395 LEDsoff();\r
396// iso14a_set_tracing(TRUE);\r
7cc204bf 397}\r
398\r
baeaf579 399\r
7cc204bf 400void MifareUWriteBlock_Special(uint8_t arg0, uint8_t *datain)\r
401{\r
baeaf579 402 // params\r
403 uint8_t blockNo = arg0;\r
404 byte_t blockdata[4];\r
405 \r
7cc204bf 406 memcpy(blockdata, datain,4);\r
407\r
baeaf579 408 // variables\r
409 byte_t isOK = 0;\r
410 uint8_t uid[10];\r
411 uint32_t cuid;\r
7cc204bf 412\r
baeaf579 413 // clear trace\r
414 iso14a_clear_trace();\r
415 // iso14a_set_tracing(false);\r
7cc204bf 416\r
baeaf579 417 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);\r
7cc204bf 418\r
baeaf579 419 LED_A_ON();\r
420 LED_B_OFF();\r
421 LED_C_OFF();\r
7cc204bf 422\r
baeaf579 423 while (true) {\r
424 if(!iso14443a_select_card(uid, NULL, &cuid)) {\r
425 if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");\r
426 break;\r
427 };\r
7cc204bf 428\r
baeaf579 429 if(mifare_ultra_special_writeblock(cuid, blockNo, blockdata)) {\r
430 if (MF_DBGLEVEL >= 1) Dbprintf("Write block error");\r
431 break;\r
432 };\r
7cc204bf 433\r
baeaf579 434 if(mifare_ultra_halt(cuid)) {\r
435 if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");\r
436 break;\r
437 };\r
7cc204bf 438\r
baeaf579 439 isOK = 1;\r
440 break;\r
441 }\r
7cc204bf 442\r
baeaf579 443 if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED");\r
7cc204bf 444\r
baeaf579 445 LED_B_ON();\r
446 cmd_send(CMD_ACK,isOK,0,0,0,0);\r
447 LED_B_OFF();\r
7cc204bf 448\r
449\r
baeaf579 450 // Thats it...\r
451 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
452 LEDsoff();\r
7cc204bf 453// iso14a_set_tracing(TRUE);\r
454\r
455}\r
456\r
baeaf579 457\r
7cc204bf 458// Return 1 if the nonce is invalid else return 0\r
6a1f2d82 459int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity) {\r
7cc204bf 460 return ((oddparity((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity((NtEnc >> 24) & 0xFF) ^ BIT(Ks1,16))) & \\r
8556b852
M
461 (oddparity((Nt >> 16) & 0xFF) == ((parity[1]) ^ oddparity((NtEnc >> 16) & 0xFF) ^ BIT(Ks1,8))) & \\r
462 (oddparity((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity((NtEnc >> 8) & 0xFF) ^ BIT(Ks1,0)))) ? 1 : 0;\r
463}\r
464\r
9492e0b0 465\r
8556b852
M
466//-----------------------------------------------------------------------------\r
467// MIFARE nested authentication. \r
468// \r
469//-----------------------------------------------------------------------------\r
9492e0b0 470void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *datain)\r
8556b852
M
471{\r
472 // params\r
9492e0b0 473 uint8_t blockNo = arg0 & 0xff;\r
474 uint8_t keyType = (arg0 >> 8) & 0xff;\r
475 uint8_t targetBlockNo = arg1 & 0xff;\r
476 uint8_t targetKeyType = (arg1 >> 8) & 0xff;\r
8556b852
M
477 uint64_t ui64Key = 0;\r
478\r
479 ui64Key = bytes_to_num(datain, 6);\r
480 \r
481 // variables\r
9492e0b0 482 uint16_t rtr, i, j, len;\r
483 uint16_t davg;\r
484 static uint16_t dmin, dmax;\r
1c611bbd 485 uint8_t uid[10];\r
6a1f2d82 486 uint32_t cuid, nt1, nt2, nttmp, nttest, ks1;\r
487 uint8_t par[1];\r
9492e0b0 488 uint32_t target_nt[2], target_ks[2];\r
489 \r
8556b852 490 uint8_t par_array[4];\r
9492e0b0 491 uint16_t ncount = 0;\r
8556b852
M
492 struct Crypto1State mpcs = {0, 0};\r
493 struct Crypto1State *pcs;\r
494 pcs = &mpcs;\r
6a1f2d82 495 uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf();\r
8556b852 496\r
9492e0b0 497 uint32_t auth1_time, auth2_time;\r
498 static uint16_t delta_time;\r
499\r
8556b852 500 // clear trace\r
d19929cb 501 iso14a_clear_trace();\r
9492e0b0 502 iso14a_set_tracing(false);\r
8556b852 503 \r
7bc95e2e 504 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);\r
8556b852
M
505\r
506 LED_A_ON();\r
8556b852
M
507 LED_C_OFF();\r
508\r
8556b852 509\r
9492e0b0 510 // statistics on nonce distance\r
511 if (calibrate) { // for first call only. Otherwise reuse previous calibration\r
512 LED_B_ON();\r
8556b852 513\r
9492e0b0 514 davg = dmax = 0;\r
515 dmin = 2000;\r
516 delta_time = 0;\r
8556b852 517 \r
9492e0b0 518 for (rtr = 0; rtr < 17; rtr++) {\r
8556b852 519\r
9492e0b0 520 // prepare next select. No need to power down the card.\r
521 if(mifare_classic_halt(pcs, cuid)) {\r
522 if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error");\r
523 rtr--;\r
524 continue;\r
525 }\r
526\r
527 if(!iso14443a_select_card(uid, NULL, &cuid)) {\r
528 if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card");\r
529 rtr--;\r
530 continue;\r
531 };\r
532\r
533 auth1_time = 0;\r
534 if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time)) {\r
535 if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error");\r
536 rtr--;\r
537 continue;\r
538 };\r
539\r
540 if (delta_time) {\r
541 auth2_time = auth1_time + delta_time;\r
542 } else {\r
543 auth2_time = 0;\r
544 }\r
545 if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_NESTED, &nt2, &auth2_time)) {\r
546 if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error");\r
547 rtr--;\r
548 continue;\r
549 };\r
550\r
b19bd5d6 551 nttmp = prng_successor(nt1, 100); //NXP Mifare is typical around 840,but for some unlicensed/compatible mifare card this can be 160\r
552 for (i = 101; i < 1200; i++) {\r
9492e0b0 553 nttmp = prng_successor(nttmp, 1);\r
554 if (nttmp == nt2) break;\r
555 }\r
556\r
557 if (i != 1200) {\r
558 if (rtr != 0) {\r
559 davg += i;\r
560 dmin = MIN(dmin, i);\r
561 dmax = MAX(dmax, i);\r
562 }\r
563 else {\r
564 delta_time = auth2_time - auth1_time + 32; // allow some slack for proper timing\r
565 }\r
566 if (MF_DBGLEVEL >= 3) Dbprintf("Nested: calibrating... ntdist=%d", i);\r
567 }\r
8556b852
M
568 }\r
569 \r
9492e0b0 570 if (rtr <= 1) return;\r
8556b852 571\r
9492e0b0 572 davg = (davg + (rtr - 1)/2) / (rtr - 1);\r
573 \r
574 if (MF_DBGLEVEL >= 3) Dbprintf("min=%d max=%d avg=%d, delta_time=%d", dmin, dmax, davg, delta_time);\r
8556b852 575\r
9492e0b0 576 dmin = davg - 2;\r
577 dmax = davg + 2;\r
578 \r
579 LED_B_OFF();\r
580 \r
581 }\r
8556b852
M
582// ------------------------------------------------------------------------------------------------- \r
583 \r
584 LED_C_ON();\r
585\r
586 // get crypted nonces for target sector\r
9492e0b0 587 for(i=0; i < 2; i++) { // look for exactly two different nonces\r
8556b852 588\r
9492e0b0 589 target_nt[i] = 0;\r
590 while(target_nt[i] == 0) { // continue until we have an unambiguous nonce\r
8556b852 591 \r
9492e0b0 592 // prepare next select. No need to power down the card.\r
593 if(mifare_classic_halt(pcs, cuid)) {\r
594 if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Halt error");\r
595 continue;\r
596 }\r
8556b852 597\r
9492e0b0 598 if(!iso14443a_select_card(uid, NULL, &cuid)) {\r
599 if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card");\r
600 continue;\r
601 };\r
8556b852 602 \r
9492e0b0 603 auth1_time = 0;\r
604 if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, &auth1_time)) {\r
605 if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth1 error");\r
606 continue;\r
607 };\r
8556b852 608\r
9492e0b0 609 // nested authentication\r
610 auth2_time = auth1_time + delta_time;\r
6a1f2d82 611 len = mifare_sendcmd_shortex(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par, &auth2_time);\r
9492e0b0 612 if (len != 4) {\r
613 if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Auth2 error len=%d", len);\r
614 continue;\r
615 };\r
8556b852 616 \r
9492e0b0 617 nt2 = bytes_to_num(receivedAnswer, 4); \r
6a1f2d82 618 if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: Testing nt1=%08x nt2enc=%08x nt2par=%02x", i+1, nt1, nt2, par[0]);\r
8556b852 619 \r
9492e0b0 620 // Parity validity check\r
621 for (j = 0; j < 4; j++) {\r
6a1f2d82 622 par_array[j] = (oddparity(receivedAnswer[j]) != ((par[0] >> (7-j)) & 0x01));\r
9492e0b0 623 }\r
624 \r
625 ncount = 0;\r
626 nttest = prng_successor(nt1, dmin - 1);\r
627 for (j = dmin; j < dmax + 1; j++) {\r
628 nttest = prng_successor(nttest, 1);\r
629 ks1 = nt2 ^ nttest;\r
630\r
631 if (valid_nonce(nttest, nt2, ks1, par_array)){\r
632 if (ncount > 0) { // we are only interested in disambiguous nonces, try again\r
633 if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: dismissed (ambigous), ntdist=%d", i+1, j);\r
634 target_nt[i] = 0;\r
635 break;\r
636 }\r
637 target_nt[i] = nttest;\r
638 target_ks[i] = ks1;\r
639 ncount++;\r
640 if (i == 1 && target_nt[1] == target_nt[0]) { // we need two different nonces\r
641 target_nt[i] = 0;\r
642 if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#2: dismissed (= nonce#1), ntdist=%d", j);\r
8556b852
M
643 break;\r
644 }\r
9492e0b0 645 if (MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: valid, ntdist=%d", i+1, j);\r
8556b852 646 }\r
8556b852 647 }\r
9492e0b0 648 if (target_nt[i] == 0 && j == dmax+1 && MF_DBGLEVEL >= 3) Dbprintf("Nonce#%d: dismissed (all invalid)", i+1);\r
8556b852
M
649 }\r
650 }\r
651\r
652 LED_C_OFF();\r
653 \r
654 // ----------------------------- crypto1 destroy\r
655 crypto1_destroy(pcs);\r
656 \r
9492e0b0 657 byte_t buf[4 + 4 * 4];\r
658 memcpy(buf, &cuid, 4);\r
659 memcpy(buf+4, &target_nt[0], 4);\r
660 memcpy(buf+8, &target_ks[0], 4);\r
661 memcpy(buf+12, &target_nt[1], 4);\r
662 memcpy(buf+16, &target_ks[1], 4);\r
8556b852
M
663 \r
664 LED_B_ON();\r
9492e0b0 665 cmd_send(CMD_ACK, 0, 2, targetBlockNo + (targetKeyType * 0x100), buf, sizeof(buf));\r
6e82300d 666 LED_B_OFF();\r
8556b852 667\r
9492e0b0 668 if (MF_DBGLEVEL >= 3) DbpString("NESTED FINISHED");\r
8556b852 669\r
8556b852
M
670 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
671 LEDsoff();\r
9492e0b0 672 iso14a_set_tracing(TRUE);\r
8556b852
M
673}\r
674\r
675//-----------------------------------------------------------------------------\r
9492e0b0 676// MIFARE check keys. key count up to 85. \r
8556b852
M
677// \r
678//-----------------------------------------------------------------------------\r
679void MifareChkKeys(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)\r
680{\r
681 // params\r
682 uint8_t blockNo = arg0;\r
683 uint8_t keyType = arg1;\r
684 uint8_t keyCount = arg2;\r
685 uint64_t ui64Key = 0;\r
686 \r
687 // variables\r
688 int i;\r
689 byte_t isOK = 0;\r
1c611bbd 690 uint8_t uid[10];\r
8556b852
M
691 uint32_t cuid;\r
692 struct Crypto1State mpcs = {0, 0};\r
693 struct Crypto1State *pcs;\r
694 pcs = &mpcs;\r
695 \r
696 // clear debug level\r
697 int OLD_MF_DBGLEVEL = MF_DBGLEVEL; \r
698 MF_DBGLEVEL = MF_DBG_NONE;\r
699 \r
700 // clear trace\r
d19929cb 701 iso14a_clear_trace();\r
9492e0b0 702 iso14a_set_tracing(TRUE);\r
8556b852 703\r
7bc95e2e 704 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);\r
8556b852
M
705\r
706 LED_A_ON();\r
707 LED_B_OFF();\r
708 LED_C_OFF();\r
709\r
8556b852 710 for (i = 0; i < keyCount; i++) {\r
9492e0b0 711 if(mifare_classic_halt(pcs, cuid)) {\r
712 if (MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Halt error");\r
713 }\r
8556b852
M
714\r
715 if(!iso14443a_select_card(uid, NULL, &cuid)) {\r
9492e0b0 716 if (OLD_MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Can't select card");\r
8556b852
M
717 break;\r
718 };\r
719\r
720 ui64Key = bytes_to_num(datain + i * 6, 6);\r
721 if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {\r
722 continue;\r
723 };\r
724 \r
725 isOK = 1;\r
726 break;\r
727 }\r
728 \r
729 // ----------------------------- crypto1 destroy\r
730 crypto1_destroy(pcs);\r
731 \r
8556b852 732 LED_B_ON();\r
6e82300d 733 cmd_send(CMD_ACK,isOK,0,0,datain + i * 6,6);\r
8556b852
M
734 LED_B_OFF();\r
735\r
736 // Thats it...\r
737 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
738 LEDsoff();\r
739\r
740 // restore debug level\r
741 MF_DBGLEVEL = OLD_MF_DBGLEVEL; \r
742}\r
743\r
744//-----------------------------------------------------------------------------\r
745// MIFARE commands set debug level\r
746// \r
747//-----------------------------------------------------------------------------\r
748void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){\r
749 MF_DBGLEVEL = arg0;\r
750 Dbprintf("Debug level: %d", MF_DBGLEVEL);\r
751}\r
752\r
baeaf579 753\r
8556b852
M
754//-----------------------------------------------------------------------------\r
755// Work with emulator memory\r
756// \r
757//-----------------------------------------------------------------------------\r
758void MifareEMemClr(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){\r
759 emlClearMem();\r
760}\r
761\r
baeaf579 762\r
8556b852
M
763void MifareEMemSet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){\r
764 emlSetMem(datain, arg0, arg1); // data, block num, blocks count\r
765}\r
766\r
baeaf579 767\r
8556b852 768void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){\r
8556b852 769\r
baeaf579 770 byte_t buf[48];\r
771 emlGetMem(buf, arg0, arg1); // data, block num, blocks count (max 4)\r
8556b852
M
772\r
773 LED_B_ON();\r
baeaf579 774 cmd_send(CMD_ACK,arg0,arg1,0,buf,48);\r
8556b852
M
775 LED_B_OFF();\r
776}\r
777\r
baeaf579 778\r
8556b852
M
779//-----------------------------------------------------------------------------\r
780// Load a card into the emulator memory\r
781// \r
782//-----------------------------------------------------------------------------\r
783void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){\r
baeaf579 784 uint8_t numSectors = arg0;\r
8556b852
M
785 uint8_t keyType = arg1;\r
786 uint64_t ui64Key = 0;\r
787 uint32_t cuid;\r
788 struct Crypto1State mpcs = {0, 0};\r
789 struct Crypto1State *pcs;\r
790 pcs = &mpcs;\r
791\r
792 // variables\r
793 byte_t dataoutbuf[16];\r
ab8b654e 794 byte_t dataoutbuf2[16];\r
1c611bbd 795 uint8_t uid[10];\r
8556b852
M
796\r
797 // clear trace\r
d19929cb 798 iso14a_clear_trace();\r
8556b852
M
799 iso14a_set_tracing(false);\r
800 \r
7bc95e2e 801 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);\r
8556b852
M
802\r
803 LED_A_ON();\r
804 LED_B_OFF();\r
805 LED_C_OFF();\r
806 \r
baeaf579 807 bool isOK = true;\r
808\r
809 if(!iso14443a_select_card(uid, NULL, &cuid)) {\r
810 isOK = false;\r
811 if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");\r
812 }\r
8556b852 813 \r
baeaf579 814 for (uint8_t sectorNo = 0; isOK && sectorNo < numSectors; sectorNo++) {\r
815 ui64Key = emlGetKey(sectorNo, keyType);\r
816 if (sectorNo == 0){\r
817 if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) {\r
818 isOK = false;\r
819 if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth error", sectorNo);\r
8556b852 820 break;\r
baeaf579 821 }\r
822 } else {\r
823 if(isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_NESTED)) {\r
824 isOK = false;\r
825 if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth nested error", sectorNo);\r
8556b852 826 break;\r
baeaf579 827 }\r
828 }\r
829 \r
830 for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) {\r
831 if(isOK && mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf)) {\r
832 isOK = false;\r
833 if (MF_DBGLEVEL >= 1) Dbprintf("Error reading sector %2d block %2d", sectorNo, blockNo);\r
ab8b654e
M
834 break;\r
835 };\r
baeaf579 836 if (isOK) {\r
837 if (blockNo < NumBlocksPerSector(sectorNo) - 1) {\r
838 emlSetMem(dataoutbuf, FirstBlockOfSector(sectorNo) + blockNo, 1);\r
839 } else { // sector trailer, keep the keys, set only the AC\r
840 emlGetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1);\r
841 memcpy(&dataoutbuf2[6], &dataoutbuf[6], 4);\r
842 emlSetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1);\r
843 }\r
844 }\r
8556b852
M
845 }\r
846\r
baeaf579 847 }\r
848\r
849 if(mifare_classic_halt(pcs, cuid)) {\r
850 if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");\r
851 };\r
8556b852
M
852\r
853 // ----------------------------- crypto1 destroy\r
854 crypto1_destroy(pcs);\r
ab8b654e
M
855\r
856 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
857 LEDsoff();\r
8556b852
M
858 \r
859 if (MF_DBGLEVEL >= 2) DbpString("EMUL FILL SECTORS FINISHED");\r
860\r
8556b852
M
861}\r
862\r
0675f200
M
863\r
864//-----------------------------------------------------------------------------\r
865// Work with "magic Chinese" card (email him: ouyangweidaxian@live.cn)\r
866// \r
867//-----------------------------------------------------------------------------\r
868void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){\r
869 \r
870 // params\r
871 uint8_t needWipe = arg0;\r
208a0166
M
872 // bit 0 - need get UID\r
873 // bit 1 - need wupC\r
874 // bit 2 - need HALT after sequence\r
875 // bit 3 - need init FPGA and field before sequence\r
876 // bit 4 - need reset FPGA and LED\r
877 uint8_t workFlags = arg1;\r
0675f200
M
878 uint8_t blockNo = arg2;\r
879 \r
880 // card commands\r
881 uint8_t wupC1[] = { 0x40 }; \r
882 uint8_t wupC2[] = { 0x43 }; \r
883 uint8_t wipeC[] = { 0x41 }; \r
884 \r
885 // variables\r
886 byte_t isOK = 0;\r
1c611bbd 887 uint8_t uid[10];\r
0675f200
M
888 uint8_t d_block[18];\r
889 uint32_t cuid;\r
890 \r
1c611bbd 891 memset(uid, 0x00, 10);\r
6a1f2d82 892 uint8_t *receivedAnswer = get_bigbufptr_recvrespbuf();\r
893 uint8_t *receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE;\r
894\r
208a0166
M
895 if (workFlags & 0x08) {\r
896 // clear trace\r
d19929cb 897 iso14a_clear_trace();\r
208a0166 898 iso14a_set_tracing(TRUE);\r
0675f200 899\r
7bc95e2e 900 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);\r
0675f200 901\r
208a0166
M
902 LED_A_ON();\r
903 LED_B_OFF();\r
904 LED_C_OFF();\r
0675f200 905 \r
208a0166
M
906 SpinDelay(300);\r
907 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
908 SpinDelay(100);\r
909 FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);\r
910 }\r
0675f200
M
911\r
912 while (true) {\r
913 // get UID from chip\r
208a0166 914 if (workFlags & 0x01) {\r
0675f200
M
915 if(!iso14443a_select_card(uid, NULL, &cuid)) {\r
916 if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");\r
917 break;\r
918 };\r
919\r
920 if(mifare_classic_halt(NULL, cuid)) {\r
921 if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");\r
922 break;\r
923 };\r
924 };\r
925 \r
926 // reset chip\r
927 if (needWipe){\r
6a1f2d82 928 ReaderTransmitBitsPar(wupC1,7,0, NULL);\r
929 if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {\r
0675f200
M
930 if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");\r
931 break;\r
932 };\r
933\r
9492e0b0 934 ReaderTransmit(wipeC, sizeof(wipeC), NULL);\r
6a1f2d82 935 if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {\r
0675f200
M
936 if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error");\r
937 break;\r
938 };\r
939\r
940 if(mifare_classic_halt(NULL, cuid)) {\r
941 if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");\r
942 break;\r
943 };\r
944 }; \r
945\r
545a1f38 946 // write block\r
208a0166 947 if (workFlags & 0x02) {\r
6a1f2d82 948 ReaderTransmitBitsPar(wupC1,7,0, NULL);\r
949 if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {\r
208a0166
M
950 if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");\r
951 break;\r
952 };\r
0675f200 953\r
9492e0b0 954 ReaderTransmit(wupC2, sizeof(wupC2), NULL);\r
6a1f2d82 955 if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {\r
208a0166
M
956 if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error");\r
957 break;\r
958 };\r
959 }\r
0675f200 960\r
6a1f2d82 961 if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) {\r
0675f200
M
962 if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error");\r
963 break;\r
964 };\r
965 \r
966 memcpy(d_block, datain, 16);\r
967 AppendCrc14443a(d_block, 16);\r
968 \r
9492e0b0 969 ReaderTransmit(d_block, sizeof(d_block), NULL);\r
6a1f2d82 970 if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != 0x0a)) {\r
0675f200
M
971 if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error");\r
972 break;\r
973 }; \r
974 \r
208a0166
M
975 if (workFlags & 0x04) {\r
976 if (mifare_classic_halt(NULL, cuid)) {\r
977 if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");\r
978 break;\r
979 };\r
980 }\r
0675f200
M
981 \r
982 isOK = 1;\r
983 break;\r
984 }\r
985 \r
0675f200 986 LED_B_ON();\r
baeaf579 987 cmd_send(CMD_ACK,isOK,0,0,uid,4);\r
0675f200
M
988 LED_B_OFF();\r
989\r
545a1f38 990 if ((workFlags & 0x10) || (!isOK)) {\r
208a0166
M
991 // Thats it...\r
992 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
993 LEDsoff();\r
994 }\r
0675f200 995}\r
545a1f38 996\r
baeaf579 997\r
545a1f38
M
998void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){\r
999 \r
1000 // params\r
1001 // bit 1 - need wupC\r
1002 // bit 2 - need HALT after sequence\r
1003 // bit 3 - need init FPGA and field before sequence\r
1004 // bit 4 - need reset FPGA and LED\r
1005 uint8_t workFlags = arg0;\r
1006 uint8_t blockNo = arg2;\r
1007 \r
1008 // card commands\r
1009 uint8_t wupC1[] = { 0x40 }; \r
1010 uint8_t wupC2[] = { 0x43 }; \r
1011 \r
1012 // variables\r
1013 byte_t isOK = 0;\r
1014 uint8_t data[18];\r
1015 uint32_t cuid = 0;\r
1016 \r
1017 memset(data, 0x00, 18);\r
6a1f2d82 1018 uint8_t* receivedAnswer = get_bigbufptr_recvrespbuf();\r
1019 uint8_t *receivedAnswerPar = receivedAnswer + MAX_FRAME_SIZE;\r
545a1f38
M
1020 \r
1021 if (workFlags & 0x08) {\r
1022 // clear trace\r
d19929cb 1023 iso14a_clear_trace();\r
545a1f38
M
1024 iso14a_set_tracing(TRUE);\r
1025\r
7bc95e2e 1026 iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);\r
545a1f38
M
1027\r
1028 LED_A_ON();\r
1029 LED_B_OFF();\r
1030 LED_C_OFF();\r
1031 \r
1032 SpinDelay(300);\r
1033 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
1034 SpinDelay(100);\r
1035 FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);\r
1036 }\r
1037\r
1038 while (true) {\r
1039 if (workFlags & 0x02) {\r
7bc95e2e 1040 ReaderTransmitBitsPar(wupC1,7,0, NULL);\r
6a1f2d82 1041 if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {\r
545a1f38
M
1042 if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");\r
1043 break;\r
1044 };\r
1045\r
9492e0b0 1046 ReaderTransmit(wupC2, sizeof(wupC2), NULL);\r
6a1f2d82 1047 if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {\r
545a1f38
M
1048 if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error");\r
1049 break;\r
1050 };\r
1051 }\r
1052\r
1053 // read block\r
6a1f2d82 1054 if ((mifare_sendcmd_short(NULL, 0, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 18)) {\r
545a1f38
M
1055 if (MF_DBGLEVEL >= 1) Dbprintf("read block send command error");\r
1056 break;\r
1057 };\r
1058 memcpy(data, receivedAnswer, 18);\r
1059 \r
1060 if (workFlags & 0x04) {\r
1061 if (mifare_classic_halt(NULL, cuid)) {\r
1062 if (MF_DBGLEVEL >= 1) Dbprintf("Halt error");\r
1063 break;\r
1064 };\r
1065 }\r
1066 \r
1067 isOK = 1;\r
1068 break;\r
1069 }\r
1070 \r
545a1f38 1071 LED_B_ON();\r
baeaf579 1072 cmd_send(CMD_ACK,isOK,0,0,data,18);\r
545a1f38
M
1073 LED_B_OFF();\r
1074\r
1075 if ((workFlags & 0x10) || (!isOK)) {\r
1076 // Thats it...\r
1077 FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);\r
1078 LEDsoff();\r
1079 }\r
1080}\r
1081\r
Impressum, Datenschutz