1 /******************************************************************************
2  *
3  *  Copyright 2019-2023 NXP
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 #include "NxpMfcReader.h"
19 
20 #include <log/log.h>
21 #include <phNfcCompId.h>
22 #include <phNxpLog.h>
23 #include <phNxpNciHal_Adaptation.h>
24 #include <phNxpNciHal_ext.h>
25 
26 #include "phNxpNciHal.h"
27 
28 extern bool sendRspToUpperLayer;
29 extern bool bEnableMfcExtns;
30 
getInstance()31 NxpMfcReader& NxpMfcReader::getInstance() {
32   static NxpMfcReader msNxpMfcReader;
33   return msNxpMfcReader;
34 }
35 
36 /*******************************************************************************
37 **
38 ** Function         Write
39 **
40 ** Description      Wrapper API to handle Mifare Transceive to TAG_CMD interface
41 **                  RAW read write.
42 **
43 ** Returns          It returns number of bytes successfully written to NFCC.
44 **
45 *******************************************************************************/
Write(uint16_t mfcDataLen,const uint8_t * pMfcData)46 int NxpMfcReader::Write(uint16_t mfcDataLen, const uint8_t* pMfcData) {
47   // Eg:- From the App pMfcData- {|PART1-00 00 06 C1 04| PART2-01 00 00 00|}
48   uint16_t mfcTagCmdBuffLen = 0;
49   uint8_t mfcTagCmdBuff[MAX_MFC_BUFF_SIZE] = {0};
50   uint16_t mfcTagCmdRemainingCmdLen = mfcDataLen;
51 
52   if (mfcDataLen > MAX_MFC_BUFF_SIZE) {
53     android_errorWriteLog(0x534e4554, "169259605");
54     mfcDataLen = MAX_MFC_BUFF_SIZE;
55   } else if (mfcDataLen < MIN_MFC_BUFF_SIZE) {
56     android_errorWriteLog(0x534e4554, "287677822");
57     NXPLOG_NCIHAL_E("%s: mfcDataLen is below 4 bytes", __func__);
58     return 0;
59   }
60   memcpy(mfcTagCmdBuff, pMfcData, mfcDataLen);
61   if (mfcDataLen >= 3) mfcTagCmdBuffLen = mfcDataLen - NCI_HEADER_SIZE;
62   BuildMfcCmd(&mfcTagCmdBuff[3], &mfcTagCmdBuffLen);
63 
64   mfcTagCmdBuff[2] = mfcTagCmdBuffLen;
65 
66   if (checkIsMFCIncDecRestore(pMfcData[3])) {
67     if (sem_init(&mNacksem, 0, 0) != 0) {
68       NXPLOG_NCIHAL_E("%s : sem_init failed", __func__);
69       return 0;
70     }
71   }
72   int writtenDataLen = phNxpNciHal_write_internal(
73       mfcTagCmdBuffLen + NCI_HEADER_SIZE, mfcTagCmdBuff);
74 
75   /* send TAG_CMD part 2 for Mifare increment ,decrement and restore commands */
76   if (checkIsMFCIncDecRestore(pMfcData[3])) {
77     MfcWaitForAck();
78     if (isAck) {
79       NXPLOG_NCIHAL_D("part 1 command Acked");
80       SendIncDecRestoreCmdPart2(
81           mfcTagCmdRemainingCmdLen - MFC_TAG_INCR_DECR_CMD_PART1_LEN,
82           &pMfcData[0]);
83     } else {
84       NXPLOG_NCIHAL_E("part 1 command NACK");
85     }
86     sem_destroy(&mNacksem);
87   }
88   return writtenDataLen;
89 }
90 
91 /*******************************************************************************
92 **
93 ** Function         BuildMfcCmd
94 **
95 ** Description      builds the TAG CMD for Mifare Classic Tag.
96 **
97 ** Returns          None
98 **
99 *******************************************************************************/
BuildMfcCmd(uint8_t * pData,uint16_t * pLength)100 void NxpMfcReader::BuildMfcCmd(uint8_t* pData, uint16_t* pLength) {
101   uint16_t cmdBuffLen = *pLength;
102   memcpy(mMfcTagCmdIntfData.sendBuf, pData, cmdBuffLen);
103   mMfcTagCmdIntfData.sendBufLen = cmdBuffLen;
104 
105   switch (pData[0]) {
106     case eMifareAuthentA:
107     case eMifareAuthentB:
108       BuildAuthCmd();
109       break;
110     case eMifareRead16:
111       BuildReadCmd();
112       break;
113     case eMifareWrite16:
114       AuthForWrite();
115       BuildWrite16Cmd();
116       break;
117     case eMifareInc:
118     case eMifareDec:
119       BuildIncDecCmd();
120       break;
121     default:
122       BuildRawCmd();
123       break;
124   }
125 
126   memcpy(pData, mMfcTagCmdIntfData.sendBuf, (mMfcTagCmdIntfData.sendBufLen));
127   *pLength = (mMfcTagCmdIntfData.sendBufLen);
128   return;
129 }
130 
131 /*******************************************************************************
132 **
133 ** Function         BuildAuthCmd
134 **
135 ** Description      builds the TAG CMD for Mifare Auth.
136 **
137 ** Returns          None
138 **
139 *******************************************************************************/
BuildAuthCmd()140 void NxpMfcReader::BuildAuthCmd() {
141   uint8_t byKey = 0x00, noOfKeys = 0x00;
142   bool isPreloadedKey = false;
143 
144   if (mMfcTagCmdIntfData.sendBuf[0] == eMifareAuthentB) {
145     byKey |= MFC_ENABLE_KEY_B;
146   }
147   uint8_t aMfckeys[MFC_NUM_OF_KEYS][MFC_KEY_SIZE] = MFC_KEYS;
148   noOfKeys = sizeof(aMfckeys) / MFC_KEY_SIZE;
149   for (uint8_t byIndex = 0; byIndex < noOfKeys; byIndex++) {
150     if ((memcmp(aMfckeys[byIndex], &mMfcTagCmdIntfData.sendBuf[6],
151                 MFC_AUTHKEYLEN) == 0x00)) {
152       byKey = byKey | byIndex;
153       isPreloadedKey = true;
154       break;
155     }
156   }
157   CalcSectorAddress();
158   mMfcTagCmdIntfData.sendBufLen = 0x03;
159   if (!isPreloadedKey) {
160     byKey |= MFC_EMBEDDED_KEY;
161     memmove(&mMfcTagCmdIntfData.sendBuf[3], &mMfcTagCmdIntfData.sendBuf[6],
162             MFC_AUTHKEYLEN);
163     mMfcTagCmdIntfData.sendBufLen += MFC_AUTHKEYLEN;
164   }
165 
166   mMfcTagCmdIntfData.sendBuf[0] = eMfcAuthReq;
167   mMfcTagCmdIntfData.sendBuf[1] = mMfcTagCmdIntfData.byAddr;
168   mMfcTagCmdIntfData.sendBuf[2] = byKey;
169   return;
170 }
171 
172 /*******************************************************************************
173 **
174 ** Function         CalcSectorAddress
175 **
176 ** Description      This function update the sector address for Mifare classic
177 **
178 ** Returns          None
179 **
180 *******************************************************************************/
CalcSectorAddress()181 void NxpMfcReader::CalcSectorAddress() {
182   uint8_t BlockNumber = mMfcTagCmdIntfData.sendBuf[1];
183   if (BlockNumber >= MFC_4K_BLK128) {
184     mMfcTagCmdIntfData.byAddr =
185         (uint8_t)(MFC_SECTOR_NO32 +
186                   ((BlockNumber - MFC_4K_BLK128) / MFC_BYTES_PER_BLOCK));
187   } else {
188     mMfcTagCmdIntfData.byAddr = BlockNumber / MFC_BLKS_PER_SECTOR;
189   }
190 
191   return;
192 }
193 
194 /*******************************************************************************
195 **
196 ** Function         BuildReadCmd
197 **
198 ** Description      builds the TAG CMD for Mifare Read.
199 **
200 ** Returns          None
201 **
202 *******************************************************************************/
BuildReadCmd()203 void NxpMfcReader::BuildReadCmd() { BuildRawCmd(); }
204 
205 /*******************************************************************************
206 **
207 ** Function         checkIsMFCIncDecRestore
208 **
209 ** Description      Check command is MF Increment/Decrement or Restore.
210 **
211 ** Returns          True/False
212 **
213 *******************************************************************************/
checkIsMFCIncDecRestore(uint8_t cmdInst)214 bool NxpMfcReader::checkIsMFCIncDecRestore(uint8_t cmdInst) {
215   return (cmdInst == eMifareDec || cmdInst == eMifareInc ||
216           cmdInst == eMifareRestore);
217 }
218 
219 /*******************************************************************************
220 **
221 ** Function         BuildWrite16Cmd
222 **
223 ** Description      builds the TAG CMD for Mifare write part 2.
224 **
225 ** Returns          None
226 **
227 *******************************************************************************/
BuildWrite16Cmd()228 void NxpMfcReader::BuildWrite16Cmd() {
229   mMfcTagCmdIntfData.sendBuf[0] = eMfRawDataXchgHdr;
230   mMfcTagCmdIntfData.sendBufLen = mMfcTagCmdIntfData.sendBufLen - 1;
231   uint8_t buff[mMfcTagCmdIntfData.sendBufLen];
232   memset(buff, 0, mMfcTagCmdIntfData.sendBufLen);
233   memcpy(buff, mMfcTagCmdIntfData.sendBuf + 2,
234          (mMfcTagCmdIntfData.sendBufLen - 1));
235   memcpy(mMfcTagCmdIntfData.sendBuf + 1, buff,
236          (mMfcTagCmdIntfData.sendBufLen - 1));
237 }
238 
239 /*******************************************************************************
240 **
241 ** Function         BuildRawCmd
242 **
243 ** Description      builds the TAG CMD for Raw transceive.
244 **
245 ** Returns          None
246 **
247 *******************************************************************************/
BuildRawCmd()248 void NxpMfcReader::BuildRawCmd() {
249   mMfcTagCmdIntfData.sendBufLen = mMfcTagCmdIntfData.sendBufLen + 1;
250   uint8_t buff[mMfcTagCmdIntfData.sendBufLen];
251   memset(buff, 0, mMfcTagCmdIntfData.sendBufLen);
252   memcpy(buff, mMfcTagCmdIntfData.sendBuf, mMfcTagCmdIntfData.sendBufLen);
253   memcpy(mMfcTagCmdIntfData.sendBuf + 1, buff, mMfcTagCmdIntfData.sendBufLen);
254   mMfcTagCmdIntfData.sendBuf[0] = eMfRawDataXchgHdr;
255 }
256 
257 /*******************************************************************************
258 **
259 ** Function         BuildIncDecCmd
260 **
261 ** Description      builds the TAG CMD for Mifare Inc/Dec.
262 **
263 ** Returns          None
264 **
265 *******************************************************************************/
BuildIncDecCmd()266 void NxpMfcReader::BuildIncDecCmd() {
267   mMfcTagCmdIntfData.sendBufLen = 0x03;  // eMfRawDataXchgHdr + cmd +
268                                          // blockaddress
269   uint8_t buff[mMfcTagCmdIntfData.sendBufLen];
270   memset(buff, 0, mMfcTagCmdIntfData.sendBufLen);
271   memcpy(buff, mMfcTagCmdIntfData.sendBuf, mMfcTagCmdIntfData.sendBufLen);
272   memcpy(mMfcTagCmdIntfData.sendBuf + 1, buff, mMfcTagCmdIntfData.sendBufLen);
273   mMfcTagCmdIntfData.sendBuf[0] = eMfRawDataXchgHdr;
274 }
275 
276 /*******************************************************************************
277 **
278 ** Function         AuthForWrite
279 **
280 ** Description      send Mifare write Part 1.
281 **
282 ** Returns          None
283 **
284 *******************************************************************************/
AuthForWrite()285 void NxpMfcReader::AuthForWrite() {
286   sendRspToUpperLayer = false;
287   NFCSTATUS status = NFCSTATUS_FAILED;
288   uint8_t authForWriteBuff[] = {0x00,
289                                 0x00,
290                                 0x03,
291                                 (uint8_t)eMfRawDataXchgHdr,
292                                 (uint8_t)mMfcTagCmdIntfData.sendBuf[0],
293                                 (uint8_t)mMfcTagCmdIntfData.sendBuf[1]};
294 
295   status = phNxpNciHal_send_ext_cmd(
296       sizeof(authForWriteBuff) / sizeof(authForWriteBuff[0]), authForWriteBuff);
297   if (status != NFCSTATUS_SUCCESS) {
298     NXPLOG_NCIHAL_E("Mifare Auth for Transceive failed");
299   }
300   return;
301 }
302 
303 /*******************************************************************************
304 **
305 ** Function         SendIncDecRestoreCmdPart2
306 **
307 ** Description      send Mifare Inc/Dec/Restore Command Part 2.
308 **
309 ** Returns          None
310 **
311 *******************************************************************************/
SendIncDecRestoreCmdPart2(uint16_t mfcDataLen,const uint8_t * mfcData)312 void NxpMfcReader::SendIncDecRestoreCmdPart2(uint16_t mfcDataLen,
313                                              const uint8_t* mfcData) {
314   NFCSTATUS status = NFCSTATUS_SUCCESS;
315   bool isError = false;
316   /* Build TAG_CMD part 2 for Mifare increment ,decrement and restore commands*/
317   uint8_t incDecRestorePart2[] = {0x00, 0x00, 0x05, (uint8_t)eMfRawDataXchgHdr,
318                                   0x00, 0x00, 0x00, 0x00};
319   uint8_t incDecRestorePart2Size =
320       (sizeof(incDecRestorePart2) / sizeof(incDecRestorePart2[0]));
321   if (mfcData[3] == eMifareInc || mfcData[3] == eMifareDec) {
322     if (mfcDataLen > MFC_TAG_INCR_DECR_CMD_PART2_LEN) {
323       isError = true;
324       incDecRestorePart2Size = MFC_TAG_INCR_DECR_CMD_PART2_LEN;
325     } else if (mfcDataLen < MFC_TAG_INCR_DECR_CMD_PART2_LEN) {
326       isError = true;
327       incDecRestorePart2Size = mfcDataLen;
328     }
329   }
330   if (isError) {
331     android_errorWriteLog(0x534e4554, "238177877");
332   }
333   for (int i = 4; i < incDecRestorePart2Size; i++) {
334     incDecRestorePart2[i] = mfcData[i + 1];
335   }
336   sendRspToUpperLayer = false;
337   status = phNxpNciHal_send_ext_cmd(incDecRestorePart2Size, incDecRestorePart2);
338   if (status != NFCSTATUS_SUCCESS) {
339     NXPLOG_NCIHAL_E("Mifare Cmd for inc/dec/Restore part 2 failed");
340   }
341   return;
342 }
343 
344 /*******************************************************************************
345 **
346 ** Function          AnalyzeMfcResp
347 **
348 ** Description      Analyze type of MFC response and build MFC response from
349 **                  Tag cmd Intf response?
350 **
351 ** Returns          NFCSTATUS_SUCCESS - Data Reception is successful
352 **                  NFCSTATUS_FAILED  - Data Reception failed
353 **
354 *******************************************************************************/
AnalyzeMfcResp(uint8_t * pBuff,uint16_t * pBufflen)355 NFCSTATUS NxpMfcReader::AnalyzeMfcResp(uint8_t* pBuff, uint16_t* pBufflen) {
356   NFCSTATUS status = NFCSTATUS_SUCCESS;
357   uint16_t wPldDataSize = 0;
358   MfcRespId_t RecvdExtnRspId = eInvalidRsp;
359 
360   if (0 == (*pBufflen)) {
361     status = NFCSTATUS_FAILED;
362   } else {
363     RecvdExtnRspId = (MfcRespId_t)pBuff[0];
364     NXPLOG_NCIHAL_E("%s: RecvdExtnRspId=%d", __func__, RecvdExtnRspId);
365     switch (RecvdExtnRspId) {
366       case eMfXchgDataRsp: {
367         NFCSTATUS writeRespStatus = NFCSTATUS_SUCCESS;
368         /* check the status byte */
369         if (*pBufflen == 3) {
370           if ((pBuff[0] == 0x10) && (pBuff[1] != 0x0A)) {
371             NXPLOG_NCIHAL_E("Mifare Error in payload response");
372             *pBufflen = 0x1;
373             pBuff[0] = NFCSTATUS_FAILED;
374             return NFCSTATUS_FAILED;
375           } else {
376             pBuff[0] = NFCSTATUS_SUCCESS;
377             return NFCSTATUS_SUCCESS;
378           }
379         }
380         writeRespStatus = pBuff[*pBufflen - 1];
381 
382         if (NFCSTATUS_SUCCESS == writeRespStatus) {
383           status = NFCSTATUS_SUCCESS;
384           uint16_t wRecvDataSz = 0;
385 
386           wPldDataSize =
387               ((*pBufflen) - (MFC_EXTN_ID_SIZE + MFC_EXTN_STATUS_SIZE));
388           wRecvDataSz = MAX_MFC_BUFF_SIZE;
389           if ((wPldDataSize) <= wRecvDataSz) {
390             /* Extract the data part from pBuff[2] & fill it to be sent to
391              * upper layer */
392             memcpy(&(pBuff[0]), &(pBuff[1]), wPldDataSize);
393             /* update the number of bytes received from lower layer,excluding
394              * the status byte */
395             *pBufflen = wPldDataSize;
396           } else {
397             status = NFCSTATUS_FAILED;
398           }
399         } else {
400           status = NFCSTATUS_FAILED;
401         }
402       } break;
403 
404       case eMfcAuthRsp: {
405         if (*pBufflen < 2) {
406           status = NFCSTATUS_FAILED;
407           break;
408         }
409         /* check the status byte */
410         if (NFCSTATUS_SUCCESS == pBuff[1]) {
411           status = NFCSTATUS_SUCCESS;
412           /* DataLen = TotalRecvdLen - (sizeof(RspId) + sizeof(Status)) */
413           wPldDataSize =
414               ((*pBufflen) - (MFC_EXTN_ID_SIZE + MFC_EXTN_STATUS_SIZE));
415           /* Extract the data part from pBuff[2] & fill it to be sent to upper
416            * layer */
417           pBuff[0] = pBuff[1];
418           /* update the number of bytes received from lower layer,excluding
419            * the status byte */
420           *pBufflen = wPldDataSize + 1;
421         } else {
422           pBuff[0] = pBuff[1];
423           *pBufflen = 1;
424           status = NFCSTATUS_FAILED;
425         }
426       } break;
427       default: {
428         status = NFCSTATUS_FAILED;
429       } break;
430     }
431   }
432   return status;
433 }
434 
435 /*******************************************************************************
436 **
437 ** Function         CheckMfcResponse
438 **
439 ** Description      This function is called to check if it's a valid Mfc
440 **                  response data
441 **
442 ** Returns          NFCSTATUS_SUCCESS
443 **                  NFCSTATUS_FAILED
444 **
445 *******************************************************************************/
CheckMfcResponse(uint8_t * pTransceiveData,uint16_t transceiveDataLen)446 NFCSTATUS NxpMfcReader::CheckMfcResponse(uint8_t* pTransceiveData,
447                                          uint16_t transceiveDataLen) {
448   NFCSTATUS status = NFCSTATUS_SUCCESS;
449 
450   if (transceiveDataLen == 3) {
451     if ((pTransceiveData)[0] == 0x10 && (pTransceiveData)[1] != 0x0A) {
452       NXPLOG_NCIHAL_E("Mifare Error in payload response");
453       transceiveDataLen = 0x1;
454       pTransceiveData += 1;
455       return NFCSTATUS_FAILED;
456     }
457   }
458   if ((pTransceiveData)[0] == 0x40) {
459     pTransceiveData += 1;
460     transceiveDataLen = 0x01;
461     if ((pTransceiveData)[0] == 0x03) {
462       transceiveDataLen = 0x00;
463       status = NFCSTATUS_FAILED;
464     }
465   } else if ((pTransceiveData)[0] == 0x10) {
466     pTransceiveData += 1;
467     transceiveDataLen = 0x10;
468   }
469   return status;
470 }
471 
472 /*******************************************************************************
473 **
474 ** Function         MfcAckReceived
475 **
476 ** Description      This function is called to notify that MFC
477 **                  response data is received
478 **
479 ** Returns          NFCSTATUS_SUCCESS
480 **                  NFCSTATUS_FAILED
481 **
482 *******************************************************************************/
MfcNotifyOnAckReceived(uint8_t * buff)483 void NxpMfcReader::MfcNotifyOnAckReceived(uint8_t* buff) {
484   const uint8_t NCI_RF_CONN_ID = 0;
485   /*
486    * If Mifare Activated & received RF data packet
487    */
488   if (bEnableMfcExtns && (buff[0] == NCI_RF_CONN_ID)) {
489     int sem_val;
490     isAck = (buff[3] == NFCSTATUS_SUCCESS);
491     sem_getvalue(&mNacksem, &sem_val);
492     if (sem_val == 0) {
493       if (sem_post(&mNacksem) == -1) {
494         NXPLOG_NCIHAL_E("%s : sem_post failed", __func__);
495       }
496     }
497   }
498 }
499 
500 /*******************************************************************************
501 **
502 ** Function         MfcWaitForAck
503 **
504 ** Description      This function is called to wait for MFC NACK
505 **
506 ** Returns          NFCSTATUS_SUCCESS
507 **                  NFCSTATUS_FAILED
508 **
509 *******************************************************************************/
MfcWaitForAck()510 NFCSTATUS NxpMfcReader::MfcWaitForAck() {
511   NFCSTATUS status = NFCSTATUS_FAILED;
512   int sem_timedout = 2, s;
513   struct timespec ts;
514   isAck = false;
515   clock_gettime(CLOCK_MONOTONIC, &ts);
516   ts.tv_sec += sem_timedout;
517   while ((s = sem_timedwait_monotonic_np(&mNacksem, &ts)) == -1 && errno == EINTR) {
518     continue; /* Restart if interrupted by handler */
519   }
520   if (s != -1) {
521     status = NFCSTATUS_SUCCESS;
522   }
523   return status;
524 }
525