2011年1月30日日曜日

Android NFC での FeliCa の NDEF 判定

FeliCa standard に直接 byte[] data を書き込んでいたら、NDEF として認識されなくなっちゃったので、ちょっと調べてみました。

■ いきさつ

Android Bazaar and Conference で Sony さんに FeliCa Standard カードをいただいた。

 ・このカードには URL 情報が入っていた

 ・もらったときには Android 2.3 標準の Tag というアプリで
  NDEF として認識できてた

 ・自分用の FeliCa 情報を dump するアプリ (Suica Reader の
  tag info 部分と同じ) でも isNdef は true になっていた

 ・Raw Bytes をごりごり上書きしたら isNdef が false になってしまった


ということで、isNdef はどうやって判定しているのか調べてみた。


■ NFC の処理

polling で NFC タグが見つかると、NFCService の mHandler に message が送られます。

その結果 NfcService.java#2048 に辿りつきます。

判定は NfcService.java#2052 の if (nativeTag.checkNdef()) で行っています。

これが true だと NdefTag クラスのインスタンスが生成されて、Intent intent = buildNdefTagIntent(tag); で生成された Intent が broadcast されます。


2058 msgNdef[0] = new NdefMessage(buff);
2059 NdefTag tag = new NdefTag(nativeTag.getUid(),
2060 TagTarget.internalTypeToRawTargets(nativeTag.getType()),
2061 nativeTag.getPollBytes(), nativeTag.getActivationBytes(),
2062 nativeTag.getHandle(),
2063 TagTarget.internalTypeToNdefTargets(nativeTag.getType()),
2064 new NdefMessage[][] {msgNdef});
2065 Intent intent = buildNdefTagIntent(tag)



2220 private Intent buildNdefTagIntent(NdefTag tag) {
2221 Intent intent = new Intent();
2222 intent.setAction(NfcAdapter.ACTION_TAG_DISCOVERED);
2223 intent.putExtra(NfcAdapter.EXTRA_TAG, tag);
2224 intent.putExtra(NfcAdapter.EXTRA_ID, tag.getId());
2225 intent.putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, tag.getNdefMessages());
2226 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2227 return intent;
2228 }


一方 false だと、 Tag クラスのインスタンスが生成されて、NfcAdapter.EXTRA_TAG キー との組み合わせとして Intent の extra に格納されます。


2102 Intent intent = new Intent();
2103 Tag tag = new Tag(nativeTag.getUid(), false,
2104 TagTarget.internalTypeToRawTargets(nativeTag.getType()),
2105 nativeTag.getPollBytes(), nativeTag.getActivationBytes(),
2106 nativeTag.getHandle());
2107 intent.setAction(NfcAdapter.ACTION_TAG_DISCOVERED);
2108 intent.putExtra(NfcAdapter.EXTRA_TAG, tag);
2109 intent.putExtra(NfcAdapter.EXTRA_ID, tag.getId());
2110 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);


では、 checkNdef() を見てみます

NativeNfcTag.java#checkNdef

doCheckNdef を呼んでいます。


100 private native boolean doCheckNdef();
101 public synchronized boolean checkNdef() {
102 if (mWatchdog != null) {
103 mWatchdog.reset();
104 }
105 return doCheckNdef();
106 }


この doCheckNdef() は native 側の com_android_nfc_NativeNfcTag_doCheckNdef を呼んでいます。

com_android_nfc_NativeNfcTag.cpp#571


571 /*
572 * JNI registration.
573 */
574 static JNINativeMethod gMethods[] =
575 {
    ...
582 {"doCheckNdef", "()Z",
583 (void *)com_android_nfc_NativeNfcTag_doCheckNdef},
    ...
590 };


では、com_android_nfc_NativeNfcTag_doCheckNdef を見てみましょう。

com_android_nfc_NativeNfcTag.cpp#com_android_nfc_NativeNfcTag_doCheckNdef


phLibNfc_Ndef_CheckNdef() メソッドを呼んでいます。2番目の引数はこの処理が終わったときの call back です。


500 static jboolean com_android_nfc_NativeNfcTag_doCheckNdef(JNIEnv *e, jobject o)
501 {
    ...
504 jboolean result = JNI_FALSE;
    ...
512 status = phLibNfc_Ndef_CheckNdef(handle, nfc_jni_checkndef_callback,(void *)e);
    ...
523 if (nfc_jni_is_ndef == FALSE)
524 {
525 goto clean_and_return;
526 }
527
528 result = JNI_TRUE;
529
530 clean_and_return:
531 CONCURRENCY_UNLOCK();
532 return result;
533 }


先に call back を見てみましょう。

com_android_nfc_NativeNfcTag.cpp#nfc_jni_checkndef_callback

引数の status が NFCSTATUS_OK なら nfc_jni_is_ndef に TRUE を、そうでなければ FALSE をセットしています。この nfc_jni_is_ndef は上記のcom_android_nfc_NativeNfcTag_doCheckNdef で参照されています。


60 static void nfc_jni_checkndef_callback(void *pContext,
61 phLibNfc_ChkNdef_Info_t info, NFCSTATUS status)
62 {
63 LOG_CALLBACK("nfc_jni_checkndef_callback", status);
64
65 if(status == NFCSTATUS_OK)
66 {
67 if(nfc_jni_ndef_buf)
68 {
69 free(nfc_jni_ndef_buf);
70 }
71 nfc_jni_ndef_buf_len = info.MaxNdefMsgLength;
72 nfc_jni_ndef_buf = (uint8_t*)malloc(nfc_jni_ndef_buf_len);
73 nfc_jni_is_ndef = TRUE;
74 }
75 else
76 {
77 nfc_jni_is_ndef = FALSE;
78 }
79
80 sem_post(nfc_jni_tag_sem);
81 }


では、phLibNfc_Ndef_CheckNdef のほうを見てみましょう。

phLibNfc_ndef_raw.c#phLibNfc_Ndef_CheckNdef

phFriNfc_NdefMap_ChkNdef を呼んでいます。また、 814 行目で先程の call back をgpphLibContext->CBInfo.pClientCkNdefCb にセットしています。


714 /**
715 * This function allows the user to check whether a particular Remote Device
716 * is NDEF compliant or not
717 */
718 NFCSTATUS phLibNfc_Ndef_CheckNdef(phLibNfc_Handle hRemoteDevice,
719 pphLibNfc_ChkNdefRspCb_t pCheckNdef_RspCb,
720 void* pContext)
721 {
    ...
770 for (cr_index = 0; cr_index < PH_FRINFC_NDEFMAP_CR; cr_index++)
771 {
772 /* Register the callback for the check ndef */
773 RetVal = phFriNfc_NdefMap_SetCompletionRoutine(
774 gpphLibContext->ndef_cntx.psNdefMap,
775 cr_index,
776 phLibNfc_Ndef_CheckNdef_Cb,
777 (void *)gpphLibContext);
778 }
779 /*call below layer check Ndef function*/
780 RetVal = phFriNfc_NdefMap_ChkNdef(gpphLibContext->ndef_cntx.psNdefMap);
    ...
812 if(RetVal== NFCSTATUS_PENDING)
813 {
814 gpphLibContext->CBInfo.pClientCkNdefCb = pCheckNdef_RspCb;
815 gpphLibContext->CBInfo.pClientCkNdefCntx = pContext;
816 gpphLibContext->status.GenCb_pending_status=TRUE;
817 gpphLibContext->LibNfcState.next_state = eLibNfcHalStateTransaction;
818 }
819
820 }
821 return RetVal;
822 }
823


では、phFriNfc_NdefMap_ChkNdef を見てみましょう。

phFriNfc_NdefMap.c#phFriNfc_NdefMap_ChkNdef

FeliCa に関係する部分を抜き出すと、phFriNfc_Felica_ChkNdef を呼んでいます。


632 NFCSTATUS phFriNfc_NdefMap_ChkNdef( phFriNfc_NdefMap_t *NdefMap)
633 {
    ...
737 case phHal_eFelica_PICC:
738
739 /*Set the OpMode Type Flag*/
    ...
745 status = phFriNfc_Felica_ChkNdef(NdefMap);
    ...
751 break;
    ...
841 }


では、phFriNfc_Felica_ChkNdef を見てみましょう。

phFriNfc_FelicaMap.c#phFriNfc_Felica_ChkNdef


phFriNfc_Felica_HUpdateManufIdDetails と phFriNfc_Felica_HRdAttrInfo が呼ばれています。


2118 NFCSTATUS phFriNfc_Felica_ChkNdef( phFriNfc_NdefMap_t *NdefMap)
2119 {
    ...
2128 /* check the ndef compliency with the system code reecived in the RemoteDevInfo*/
2129 status = phFriNfc_Felica_HUpdateManufIdDetails(NdefMap);
2130
2131 if (status == NFCSTATUS_SUCCESS)
2132 {
2133
2134 /* set the operation type to Check ndef type*/
2135 NdefMap->Felica.OpFlag = PH_FRINFC_NDEFMAP_FELI_CHK_NDEF_OP;
2136 status = phFriNfc_Felica_HRdAttrInfo(NdefMap);
2137 }
    ...
2149 }


まず、phFriNfc_Felica_HUpdateManufIdDetails を見てみます。

phFriNfc_FelicaMap.c#phFriNfc_Felica_HUpdateManufIdDetails


システムコードが 0x12 0xFC かどうかチェックしています。
これ以外の場合、status として NFCSTATUS_NO_NDEF_SUPPORT が返されるので、NDEFではないと認識されます。

つまり、FeliCa Lite の場合 0x88 0xb4 が返ってくるので、ここで NDEF ではないと認識されてしまいます。


2205 /*!
2206 * ¥brief Checks validity of system code sent from the lower device, during poll operation.
2207 */
2208
  2209 static NFCSTATUS phFriNfc_Felica_HUpdateManufIdDetails(const phFriNfc_NdefMap_t *NdefMap)
2210 {
    ...
2214 /* copy the IDm and PMm in Manufacture Details Structure*/
2215 (void)memcpy( (uint8_t *)(NdefMap->FelicaManufDetails.ManufID),
2216 (uint8_t *)NdefMap->psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDm,
2217 8);
2218 (void)memcpy( (uint8_t *)(NdefMap->FelicaManufDetails.ManufParameter),
2219 (uint8_t *)NdefMap->psRemoteDevInfo->RemoteDevInfo.Felica_Info.PMm,
2220 8);
2221 if((NdefMap->psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode[0] == 0x12)
2222 && (NdefMap->psRemoteDevInfo->RemoteDevInfo.Felica_Info.SystemCode[1] == 0xFC))
2223 {
2224 status = PHNFCSTVAL(CID_NFC_NONE, NFCSTATUS_SUCCESS);
2225 }
2226 else
2227 {
2228 status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
2229 NFCSTATUS_NO_NDEF_SUPPORT);
2230 }
    ...
2260 return (status);
2261
2262 }


次に、phFriNfc_Felica_HRdAttrInfo を見てみましょう。

phFriNfc_FelicaMap.c#phFriNfc_Felica_HRdAttrInfo


システムコードが 0x12 0xFC だけでは NDEF とは認識されず、ここでさらにチェックされます。

read コマンドを送って、0x000B のサービスコードの1ブロック目を読んでいます。
ここは、 Random Access (Read Only) の領域です。

受信データは NdefMap->SendRecvBuf[] に入ります。

カードのオペレーション終了時に呼ばれる処理は 2772行目で設定されており、
phFriNfc_NdefMap_Process が呼ばれます。


2704 static NFCSTATUS phFriNfc_Felica_HRdAttrInfo(phFriNfc_NdefMap_t *NdefMap)
2705 {
2706
2707 NFCSTATUS status = NFCSTATUS_PENDING;
2708 uint8_t BufIndex = 0;
2709
2710 /* Set the Felica Cmd*/
    ...
2712 NdefMap->Cmd.FelCmd = phHal_eFelica_Raw;
    ...
2720
2721 /* 1st byte represents the length of the cmd packet*/
2722 NdefMap->SendRecvBuf[BufIndex] = 0x00;
2723 BufIndex++;
2724
2725 /* Read/check command code*/
2726 NdefMap->SendRecvBuf[BufIndex] = 0x06;
2727 BufIndex++;
2728
2729 /* IDm - Manufacturer Id : 8bytes*/
    ...
2731 (void)memcpy((&(NdefMap->SendRecvBuf[BufIndex])),
2732 (void * )&NdefMap->psRemoteDevInfo->RemoteDevInfo.Felica_Info.IDm,
2733 8);
    ...
2740
2741 BufIndex+=8;
2742
2743 NdefMap->SendRecvBuf[BufIndex] = 0x01; /* Number of Services (n=1 ==> 0x80)*/
2744 BufIndex++;
2745
2746 NdefMap->SendRecvBuf[BufIndex] = 0x0B; /* Service Code List*/
2747 BufIndex++;
2748
2749 NdefMap->SendRecvBuf[BufIndex] = 0x00; /* Service Code List*/
2750 BufIndex++;
2751
2752 NdefMap->SendRecvBuf[BufIndex] = 0x01; /* Number of Blocks to read)*/
2753 BufIndex++;
2754
2755 NdefMap->SendRecvBuf[BufIndex] = 0x80; /* 1st Block Element : byte 1*/
2756 BufIndex++;
2757
2758 NdefMap->SendRecvBuf[BufIndex] = 0x00; /* 1st Block Element : byte 2, block 1*/
2759 BufIndex++;
2760
2761 NdefMap->SendRecvBuf[PH_NFCFRI_NDEFMAP_FELI_PKT_LEN_INDEX] = BufIndex;
2762
2763 *NdefMap->SendRecvLength = NdefMap->TempReceiveLength;
2764
2765 /* Update the Send Len*/
2766 NdefMap->SendLength = BufIndex;
2767
2768 /* Change the state to PH_NFCFRI_NDEFMAP_FELI_STATE_RD_ATTR */
2769 NdefMap->State = PH_NFCFRI_NDEFMAP_FELI_STATE_RD_ATTR;
2770
2771 /*set the completion routines for the desfire card operations*/
2772 NdefMap->MapCompletionInfo.CompletionRoutine = phFriNfc_NdefMap_Process;
2773 NdefMap->MapCompletionInfo.Context = NdefMap;
2774
2775 /*Call the Overlapped HAL Transceive function */
2776 status = phFriNfc_OvrHal_Transceive( NdefMap->LowerDevice,
2777 &NdefMap->MapCompletionInfo,
2778 NdefMap->psRemoteDevInfo,
2779 NdefMap->Cmd,
2780 &NdefMap->psDepAdditionalInfo,
2781 NdefMap->SendRecvBuf,
2782 NdefMap->SendLength,
2783 NdefMap->SendRecvBuf,
2784 NdefMap->SendRecvLength);
2785 return (status);
2786
2787 }
2788


では、phFriNfc_NdefMap_Process を見てみましょう。

phFriNfc_NdefMap.c#phFriNfc_NdefMap_Process

FeliCa の場合、phFriNfc_Felica_Process が呼ばれています。


854 void phFriNfc_NdefMap_Process( void *Context,
855 NFCSTATUS Status)
856 {
857
858 if ( Context != NULL )
859 {
860 phFriNfc_NdefMap_t *NdefMap = (phFriNfc_NdefMap_t *)Context;
861 /*
862 * 4 Changed
863 * Description: Opmode replace with RevDevTyp.
864 */
865
866 switch ( NdefMap->psRemoteDevInfo->RemDevType )
867 {
    ...
908 case phHal_eFelica_PICC :
    ...
910 /* Remote device is Felica Smart card */
911 phFriNfc_Felica_Process(NdefMap, Status);
    ...
916 break;
917
    ...
960 }
961 }
    ...
969 }
970


では、phFriNfc_Felica_Process を見てみましょう。

phFriNfc_FelicaMap.c#phFriNfc_Felica_Process

2321 if ( NdefMap->SendRecvBuf[10] == 0x00)

で read コマンドが成功したかどうかチェックしています。

2328 Status = phFriNfc_Felica_HUpdateAttrInfo(NdefMap);

ここで、NdefMap の SnedRecvBuf に入っているデータ(タグから読み込んだデータ)を FelicaAttrInfo に入れ、CardState も設定しています。

2360 Status = phFriNfc_MapTool_SetCardState( NdefMap,
2361 NDEFLen);

ここで、phFriNfc_Felica_HUpdateAttrInfo から読み込んだカードの状態を設定しています。


2273 void phFriNfc_Felica_Process(void *Context,
2274 NFCSTATUS Status)
2275 {
2276 uint8_t CRFlag = FALSE;
2277 uint16_t RecvTxLen = 0,
2278 BytesToRecv = 0,
2279 Nbc = 0;
2280 uint32_t TotNoWrittenBytes = 0,
2281 NDEFLen=0;
2282
2283 /*Set the context to Map Module*/
2284 phFriNfc_NdefMap_t *NdefMap = (phFriNfc_NdefMap_t *)Context;
2285
2286 if ( Status == NFCSTATUS_SUCCESS )
2287 {
2288 switch (NdefMap->State)
2289 {
    ...
2319 case PH_NFCFRI_NDEFMAP_FELI_STATE_RD_ATTR:
2320 /* check for the status flag1 and status flag2for the successful read operation*/
2321 if ( NdefMap->SendRecvBuf[10] == 0x00)
2322 {
2323 /* check the Manuf Id in the receive buffer*/
2324 Status = phFriNfc_Felica_HCheckManufId(NdefMap);
2325 if ( Status == NFCSTATUS_SUCCESS)
2326 {
2327 /* Update the Attribute Information in to the context structure*/
2328 Status = phFriNfc_Felica_HUpdateAttrInfo(NdefMap);
2329 if ( Status == NFCSTATUS_SUCCESS )
2330 {
2331 PH_NFCFRI_NDEFMAP_FELI_CAL_LEN_BYTES(NdefMap->FelicaAttrInfo.LenBytes[0],
2332 NdefMap->FelicaAttrInfo.LenBytes[1],
2333 NdefMap->FelicaAttrInfo.LenBytes[2],
2334 NDEFLen);
2335
2336 if ( NdefMap->Felica.OpFlag == PH_FRINFC_NDEFMAP_FELI_WR_ATTR_RD_OP )
2337 {
    ...
2346 }
2347 else if( NdefMap->Felica.OpFlag == PH_FRINFC_NDEFMAP_FELI_RD_ATTR_RD_OP )
2348 {
    ...
2356 }
2357 else if( NdefMap->Felica.OpFlag == PH_FRINFC_NDEFMAP_FELI_CHK_NDEF_OP )
2358 {
2359
2360 Status = phFriNfc_MapTool_SetCardState( NdefMap,
2361 NDEFLen);
2362 /* check status value*/
2363 NdefMap->CardType = PH_FRINFC_NDEFMAP_FELICA_SMART_CARD;
2364 /*reset the buffer index*/
2365 NdefMap->ApduBuffIndex = 0;
2366 /* set the Next operation Flag to indicate need of reading attribute information*/
2367 NdefMap->Felica.OpFlag = PH_FRINFC_NDEFMAP_FELI_OP_NONE;
2368 /* call respective CR */
2369 phFriNfc_Felica_HCrHandler(NdefMap,PH_FRINFC_NDEFMAP_CR_CHK_NDEF,Status);
2370 }
2371 else if ( NdefMap->Felica.OpFlag == PH_FRINFC_NDEFMAP_FELI_WR_EMPTY_MSG_OP )
2372 {
    ...
2381 }
2382 else
2383 {
2384
2385 /* invalid operation occured*/
2386 Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,¥
2387 NFCSTATUS_INVALID_DEVICE_REQUEST);
2388 CRFlag =TRUE ;
2389 }
2390 }
2391 else
2392 {
2393 CRFlag =TRUE ;
2394 }
2395 }
2396 else
2397 {
2398 CRFlag =TRUE ;
2399 }
2400 }
2401 else
2402 {
2403 CRFlag =TRUE;
2404 /*handle the Error case*/
2405 Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,¥
2406 NFCSTATUS_READ_FAILED);
2407 }
2408 if ( CRFlag == TRUE )
2409 {
2410 /* call respective CR */
2411 phFriNfc_Felica_HCrHandler(NdefMap,PH_FRINFC_NDEFMAP_CR_RD_NDEF,Status);
2412 }
2413 break;
2414
    ...
2667 }
2668 }
2669 else
2670 {
    ...
2697 }
2698
2699 }



では、受信したデータが NDEF 形式かどうかチェックするところを見てみましょう。

phFriNfc_FelicaMap.c#phFriNfc_Felica_HUpdateAttrInfo

受信データ NdefMap->SendRecvBuf[] はこんな形式になっています。


  LEN Bytes
0 1 2 3 4 5 6 7 8 9 10 11 12
1d 07 -------- IDm ---------- 00 00 01
↑ ↑ ↑
LEN COMMAND RD SUCCESS

13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
---------------- data 部分 --------------------
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
ver | Nbw | Nmaxb2 WriteFlag RdWrFlag CheckSum
Nbr Nmaxb1


data部分がサービス部分に書かれているデータです。ここのフォーマットを NDEF にするポイントは


74 #define PH_NFCFRI_NDEFMAP_FELI_VERSION_INDEX 13 /* Specifies Index of the version in Attribute Resp Buffer*/

61 #define PH_NFCFRI_NDEFMAP_NFCDEV_MAJOR_VER_NUM 0x01
62 #define PH_NFCFRI_NDEFMAP_NFCDEV_MINOR_VER_NUM 0x00
63
64 /* Macros to find major and minor TAG : Ex:Type1/Type2/Type3/Type4 version numbers*/
65 #define PH_NFCFRI_NDEFMAP_GET_MAJOR_TAG_VERNO(a) (((a) & (0xf0))>>(4))
66 #define PH_NFCFRI_NDEFMAP_GET_MINOR_TAG_VERNO(a) ((a) & (0x0f))


SendRecvBuf[13] = data[0] : Version : 0x1*
Felica の場合、上位 4bit が 0001 でなければならない、下位 4bit は 0000 以上でなければならない

SendRecvBuf[14] = data[1] : Nbr
Nmaxb より小さくなければならない
SendRecvBuf[15] = data[2] : Nbw
Nmaxb より小さくなければならない
SendRecvBuf[16] = data[3] : Nmaxb1
SendRecvBuf[17] = data[4] : Nmabb2
Nmaxb : 2 byte (上位 1byte が SendRecvBuf[16], 下位 1byte が SendRecvBuf[17])
 0 以外でなければならない
SendRecvBuf[18] = data[5] : RFU 0x00 でなければならない
SendRecvBuf[19] = data[6] : RFU 0x00 でなければならない
SendRecvBuf[20] = data[7] : RFU 0x00 でなければならない
SendRecvBuf[21] = data[8] : RFU 0x00 でなければならない
SendRecvBuf[22] = data[9] : WriteFlag 0x00 か 0x0f でなければならない
SendRecvBuf[23] = data[10] : RdWrFlag 0x00(READ_ONLY) か 0x01(READ_WRITE) でなければならない
SendRecvBuf[24] = data[11] : LEN Bytes
SendRecvBuf[25] = data[12] : LEN Bytes
SendRecvBuf[26] = data[13] : LEN Bytes
DataLen : 3 byte (最上位 1byte が SendRecvBuf[24], 真ん中 1byte が SendRecvBuf[25], 最下位 1byte が SendRecvBuf[26])
Nbc : (uint16_t )((( DataLen % 16) == 0 ) ? (DataLen >> 4) : ((DataLen >> 4) +1));
Nmaxb より小さくなければならない
0 の場合 READ_ONLY ではいけない
SendRecvBuf[27] = data[14] : ChkSum1 : Check Sum
SendRecvBuf[28] = data[15] : ChkSum2 : Check Sum
RecvChkSum : 2 byte (上位 1byte が ChkSum1, 下位 1byte が ChkSum2)
   SendRecvBuf[13] から SendRecvBuf[26] までの値の加算

チェックサムを行っているところ

2817 static NFCSTATUS phFriNfc_Felica_HCalCheckSum(const uint8_t *TempBuffer,
2818 uint8_t StartIndex,
2819 uint8_t EndIndex,
2820 uint16_t RecvChkSum)
2821 {
2822 NFCSTATUS Result = NFCSTATUS_SUCCESS;
2823 uint16_t CheckSum=0,
2824 BufIndex=0;
2825
2826 for(BufIndex = StartIndex;BufIndex <=EndIndex;BufIndex++)
2827 {
2828 CheckSum += TempBuffer[BufIndex];
2829 }
2830 if( RecvChkSum != CheckSum )
2831 {
2832 Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
2833 NFCSTATUS_INVALID_FORMAT);
2834 }
2835 return (Result);
2836 }


ということで、まとめるとこんな感じ


13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
1* ----------- 00 00 00 00 00/0f 00/01 --------------
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
ver | Nbw | Nmaxb2 WriteFlag RdWrFlag CheckSum
Nbr Nmaxb1


例えば、こんなの


13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
10 00 00 01 00 00 00 00 00 00 01 00 00 00 00 12
↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
ver | Nbw | Nmaxb2 WriteFlag RdWrFlag CheckSum
Nbr Nmaxb1


ここで読んだ内容は phFriNfc_Felica_AttrInfo
に突っ込まれます。

2866 status = phFriNfc_MapTool_ChkSpcVer(NdefMap,
2867 PH_NFCFRI_NDEFMAP_FELI_VERSION_INDEX);

で、バージョンの値をチェックし、

2939 status = phFriNfc_Felica_HCalCheckSum(NdefMap->SendRecvBuf,

で、チェックサムを検証しています。


2848 /*!
2849 * \brief On successful read attribute blk information, this function validates and stores the
2850 * Attribute informations in to the context.
2851 */
2852 static NFCSTATUS phFriNfc_Felica_HUpdateAttrInfo(phFriNfc_NdefMap_t *NdefMap)
2853 {
2854 NFCSTATUS status = NFCSTATUS_PENDING;
2855 uint8_t CRFlag = FALSE,
2856 Nmaxb1, Nmaxb2 = 0,
2857 ChkSum1 = 0, ChkSum2=0;
2858
2859 uint16_t Nmaxblk = 0,
2860 RecvChkSum=0,
2861 NdefBlk = 0;
2862 uint32_t DataLen =0;
2863
2864
2865 /* Validate T3VNo and NFCDevVNo */
2866 status = phFriNfc_MapTool_ChkSpcVer(NdefMap,
2867 PH_NFCFRI_NDEFMAP_FELI_VERSION_INDEX);
2868 if ( status != NFCSTATUS_SUCCESS )
2869 {
2870 CRFlag = TRUE;
2871 }
2872 else
2873 {
2874 /* get the Nmaxb from the receive buffer*/
2875 Nmaxb1 = NdefMap->SendRecvBuf[16];
2876 Nmaxb2 = NdefMap->SendRecvBuf[17];
2877
2878 Nmaxblk = (((uint16_t)Nmaxb1 << 8) | (Nmaxb2 & 0x00ff));
2879
2880 if ( Nmaxblk != 0 )
2881 {
2882 /* check the Nbr against the Nmaxb*/
2883 if ( NdefMap->SendRecvBuf[14] > Nmaxblk )
2884 {
2885 CRFlag = TRUE;
2886 }
2887 else
2888 {
2889 /*check Nbw > Nmaxb*/
2890 /*check the write flag validity*/
2891 /*check for the RFU bytes validity*/
2892 if ( (NdefMap->SendRecvBuf[15] > Nmaxblk) ||
2893 ((NdefMap->SendRecvBuf[22] != 0x00) && (NdefMap->SendRecvBuf[22] !=0x0f ))||
2894 ( (NdefMap->SendRecvBuf[23] != 0x00) && (NdefMap->SendRecvBuf[23] !=0x01 ))||
2895 ( NdefMap->SendRecvBuf[18] != 0x00) ||
2896 ( NdefMap->SendRecvBuf[19] != 0x00) ||
2897 ( NdefMap->SendRecvBuf[20] != 0x00) ||
2898 ( NdefMap->SendRecvBuf[21] != 0x00))
2899
2900 {
2901 CRFlag = TRUE;
2902 }
2903 else
2904 {
2905 /* check the validity of the actual ndef data len*/
2906 PH_NFCFRI_NDEFMAP_FELI_CAL_LEN_BYTES( NdefMap->SendRecvBuf[24],
2907 NdefMap->SendRecvBuf[25],
2908 NdefMap->SendRecvBuf[26],
2909 DataLen);
2910
2911
2912 /* Calculate Nbc*/
2913 NdefBlk = (uint16_t )((( DataLen % 16) == 0 ) ? (DataLen >> 4) : ((DataLen >> 4) +1));
2914
2915 /* check Nbc against Nmaxb*/
2916 if ((NdefBlk > Nmaxblk))
2917 {
2918 CRFlag = TRUE;
2919 }
2920 else
2921 {
2922 /*Store the attribute information in phFriNfc_Felica_AttrInfo*/
2923 NdefMap->FelicaAttrInfo.Version = NdefMap->SendRecvBuf[PH_NFCFRI_NDEFMAP_FELI_VERSION_INDEX];
2924 NdefMap->FelicaAttrInfo.Nbr = NdefMap->SendRecvBuf[14];
2925 NdefMap->FelicaAttrInfo.Nbw = NdefMap->SendRecvBuf[15];
2926
2927 NdefMap->FelicaAttrInfo.Nmaxb = Nmaxblk;
2928
2929 NdefMap->FelicaAttrInfo.WriteFlag = NdefMap->SendRecvBuf[22];
2930 NdefMap->FelicaAttrInfo.RdWrFlag = NdefMap->SendRecvBuf[23];
2931
2932 /* Get CheckSum*/
2933 ChkSum1 = NdefMap->SendRecvBuf[27];
2934 ChkSum2 = NdefMap->SendRecvBuf[28];
2935
2936 RecvChkSum = (((uint16_t)ChkSum1 << 8) | (ChkSum2 & 0x00ff));
2937
2938 /* Check the check sum validity?*/
2939 status = phFriNfc_Felica_HCalCheckSum(NdefMap->SendRecvBuf,
2940 PH_NFCFRI_NDEFMAP_FELI_VERSION_INDEX,
2941 26,
2942 RecvChkSum);
2943 if ( status != NFCSTATUS_SUCCESS )
2944 {
2945 CRFlag = TRUE;
2946 }
2947 else
2948 {
2949 /*check RW Flag Access Rights*/
2950 /* set to read only cannot write*/
2951 if ( NdefMap->FelicaAttrInfo.RdWrFlag == 0x00 )
2952 {
2953 NdefMap->CardState = PH_NDEFMAP_CARD_STATE_READ_ONLY;
2954 }
2955 else
2956 {
2957 NdefMap->CardState = PH_NDEFMAP_CARD_STATE_READ_WRITE;
2958 }
2959
2960 NdefMap->FelicaAttrInfo.LenBytes[0] = NdefMap->SendRecvBuf[24];
2961 NdefMap->FelicaAttrInfo.LenBytes[1] = NdefMap->SendRecvBuf[25];
2962 NdefMap->FelicaAttrInfo.LenBytes[2] = NdefMap->SendRecvBuf[26];
2963 status = PHNFCSTVAL(CID_NFC_NONE,NFCSTATUS_SUCCESS);
2964 }
2965 }
2966 }
2967 }
2968 }
2969 else
2970 {
2971 CRFlag = TRUE;
2972 }
2973 }
2974 if ( (status == NFCSTATUS_INVALID_FORMAT ) && (CRFlag == TRUE ))
2975 {
2976 NdefMap->CardState = PH_NDEFMAP_CARD_STATE_INVALID;
2977 }
2978 if ( CRFlag == TRUE )
2979 {
2980 /*Return Status Error Invalid Format*/
2981 status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,NFCSTATUS_INVALID_FORMAT);
2982 }
2983
2984 return (status);
2985 }



phFriNfc_MapTool_SetCardState も見ておきましょう。

phFriNfc_MapTools.c#phFriNfc_MapTool_SetCardState


  64 NFCSTATUS phFriNfc_MapTool_SetCardState(phFriNfc_NdefMap_t *NdefMap,
65 uint32_t Length)
66 {
    ...

110 }
111 Result = ((NdefMap->CardState ==
112 PH_NDEFMAP_CARD_STATE_INVALID)?
113 PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
114 NFCSTATUS_NO_NDEF_SUPPORT):
115 Result);
116 return Result;
117 }

 
 ここで、 NdefMap->CardState が PH_NDEFMAP_CARD_STATE_INVALID だと NFCSTATUS_NO_NDEF_SUPPORT が帰るので
 NDEF としては認識してくれません。


ということで、Raw bytes をごりごりカードにかいて、NDEF として認識することができました。


 

1 件のコメント:

  1. eToro is the #1 forex trading platform for novice and professional traders.

    返信削除