Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: nRF51_Vdd TextLCD BME280
TYBLE16_os5_BASE/features/nfc/stack/tech/iso7816/iso7816.c@6:6dd8c932bd56, 2019-12-19 (annotated)
- Committer:
- kenjiArai
- Date:
- Thu Dec 19 07:27:50 2019 +0000
- Revision:
- 6:6dd8c932bd56
- Parent:
- 4:e9dfb4ca4277
updated each main.cpp
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
kenjiArai | 4:e9dfb4ca4277 | 1 | /* |
kenjiArai | 4:e9dfb4ca4277 | 2 | * Copyright (c) 2015-2018, ARM Limited, All Rights Reserved |
kenjiArai | 4:e9dfb4ca4277 | 3 | * SPDX-License-Identifier: Apache-2.0 |
kenjiArai | 4:e9dfb4ca4277 | 4 | * |
kenjiArai | 4:e9dfb4ca4277 | 5 | * Licensed under the Apache License, Version 2.0 (the "License"); you may |
kenjiArai | 4:e9dfb4ca4277 | 6 | * not use this file except in compliance with the License. |
kenjiArai | 4:e9dfb4ca4277 | 7 | * You may obtain a copy of the License at |
kenjiArai | 4:e9dfb4ca4277 | 8 | * |
kenjiArai | 4:e9dfb4ca4277 | 9 | * http://www.apache.org/licenses/LICENSE-2.0 |
kenjiArai | 4:e9dfb4ca4277 | 10 | * |
kenjiArai | 4:e9dfb4ca4277 | 11 | * Unless required by applicable law or agreed to in writing, software |
kenjiArai | 4:e9dfb4ca4277 | 12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
kenjiArai | 4:e9dfb4ca4277 | 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
kenjiArai | 4:e9dfb4ca4277 | 14 | * See the License for the specific language governing permissions and |
kenjiArai | 4:e9dfb4ca4277 | 15 | * limitations under the License. |
kenjiArai | 4:e9dfb4ca4277 | 16 | */ |
kenjiArai | 4:e9dfb4ca4277 | 17 | /** |
kenjiArai | 4:e9dfb4ca4277 | 18 | * \file iso7816.c |
kenjiArai | 4:e9dfb4ca4277 | 19 | * \copyright Copyright (c) ARM Ltd 2015 |
kenjiArai | 4:e9dfb4ca4277 | 20 | * \author Donatien Garnier |
kenjiArai | 4:e9dfb4ca4277 | 21 | */ |
kenjiArai | 4:e9dfb4ca4277 | 22 | |
kenjiArai | 4:e9dfb4ca4277 | 23 | #define __DEBUG__ 0 |
kenjiArai | 4:e9dfb4ca4277 | 24 | #ifndef __MODULE__ |
kenjiArai | 4:e9dfb4ca4277 | 25 | #define __MODULE__ "iso7816.c" |
kenjiArai | 4:e9dfb4ca4277 | 26 | #endif |
kenjiArai | 4:e9dfb4ca4277 | 27 | |
kenjiArai | 4:e9dfb4ca4277 | 28 | #include "stack/nfc_errors.h" |
kenjiArai | 4:e9dfb4ca4277 | 29 | |
kenjiArai | 4:e9dfb4ca4277 | 30 | #include "iso7816.h" |
kenjiArai | 4:e9dfb4ca4277 | 31 | #include "iso7816_app.h" |
kenjiArai | 4:e9dfb4ca4277 | 32 | #include "iso7816_defs.h" |
kenjiArai | 4:e9dfb4ca4277 | 33 | #include "tech/isodep/isodep_target.h" |
kenjiArai | 4:e9dfb4ca4277 | 34 | #include "platform/nfc_debug.h" |
kenjiArai | 4:e9dfb4ca4277 | 35 | |
kenjiArai | 4:e9dfb4ca4277 | 36 | static void iso7816_disconnected(nfc_tech_iso7816_t *pIso7816, bool deselected); |
kenjiArai | 4:e9dfb4ca4277 | 37 | |
kenjiArai | 4:e9dfb4ca4277 | 38 | static nfc_err_t iso7816_parse(nfc_tech_iso7816_t *pIso7816); |
kenjiArai | 4:e9dfb4ca4277 | 39 | |
kenjiArai | 4:e9dfb4ca4277 | 40 | static void iso7816_receive(nfc_tech_iso7816_t *pIso7816); |
kenjiArai | 4:e9dfb4ca4277 | 41 | static nfc_err_t iso7816_transmit(nfc_tech_iso7816_t *pIso7816); |
kenjiArai | 4:e9dfb4ca4277 | 42 | |
kenjiArai | 4:e9dfb4ca4277 | 43 | static bool iso7816_mf_command(nfc_tech_iso7816_t *pIso7816); |
kenjiArai | 4:e9dfb4ca4277 | 44 | |
kenjiArai | 4:e9dfb4ca4277 | 45 | static void iso_dep_received_cb(nfc_tech_isodep_t *pIsodep, nfc_err_t ret, void *pUserData); |
kenjiArai | 4:e9dfb4ca4277 | 46 | static void iso_dep_transmitted_cb(nfc_tech_isodep_t *pIsodep, nfc_err_t ret, void *pUserData); |
kenjiArai | 4:e9dfb4ca4277 | 47 | static void iso_dep_disconnected_cb(nfc_tech_isodep_t *pIsodep, bool deselected, void *pUserData); |
kenjiArai | 4:e9dfb4ca4277 | 48 | |
kenjiArai | 4:e9dfb4ca4277 | 49 | static void iso_dep_stream_transmit_cb(ac_buffer_t *ppDataIn, bool *pClose, size_t maxLength, void *pUserParam); |
kenjiArai | 4:e9dfb4ca4277 | 50 | static void iso_dep_stream_receive_cb(ac_buffer_t *pDataOut, bool closed, void *pUserParam); |
kenjiArai | 4:e9dfb4ca4277 | 51 | |
kenjiArai | 4:e9dfb4ca4277 | 52 | void nfc_tech_iso7816_init(nfc_tech_iso7816_t *pIso7816, nfc_transceiver_t *pTransceiver, nfc_tech_iso7816_disconnected_cb disconnectedCb, void *pUserData) |
kenjiArai | 4:e9dfb4ca4277 | 53 | { |
kenjiArai | 4:e9dfb4ca4277 | 54 | ac_buffer_init(&pIso7816->hist, NULL, 0); |
kenjiArai | 4:e9dfb4ca4277 | 55 | nfc_tech_isodep_target_init(&pIso7816->isoDepTarget, pTransceiver, &pIso7816->hist, iso_dep_disconnected_cb, pIso7816); |
kenjiArai | 4:e9dfb4ca4277 | 56 | pIso7816->pAppList = NULL; |
kenjiArai | 4:e9dfb4ca4277 | 57 | pIso7816->pSelectedApp = NULL; |
kenjiArai | 4:e9dfb4ca4277 | 58 | pIso7816->disconnectedCb = disconnectedCb; |
kenjiArai | 4:e9dfb4ca4277 | 59 | |
kenjiArai | 4:e9dfb4ca4277 | 60 | ac_istream_init(&pIso7816->inputStream, iso_dep_stream_transmit_cb, pIso7816); |
kenjiArai | 4:e9dfb4ca4277 | 61 | ac_ostream_init(&pIso7816->outputStream, iso_dep_stream_receive_cb, pIso7816); |
kenjiArai | 4:e9dfb4ca4277 | 62 | |
kenjiArai | 4:e9dfb4ca4277 | 63 | ac_buffer_builder_init(&pIso7816->txBldr, pIso7816->txBuf, 2); //Just enough to fit sw |
kenjiArai | 4:e9dfb4ca4277 | 64 | |
kenjiArai | 4:e9dfb4ca4277 | 65 | ac_buffer_builder_init(&pIso7816->rxBldr, pIso7816->rxBuf, ISO7816_RX_BUFFER_SIZE); |
kenjiArai | 4:e9dfb4ca4277 | 66 | |
kenjiArai | 4:e9dfb4ca4277 | 67 | pIso7816->pUserData = pUserData; |
kenjiArai | 4:e9dfb4ca4277 | 68 | } |
kenjiArai | 4:e9dfb4ca4277 | 69 | |
kenjiArai | 4:e9dfb4ca4277 | 70 | void nfc_tech_iso7816_connect(nfc_tech_iso7816_t *pIso7816) |
kenjiArai | 4:e9dfb4ca4277 | 71 | { |
kenjiArai | 4:e9dfb4ca4277 | 72 | pIso7816->disconnected = false; |
kenjiArai | 4:e9dfb4ca4277 | 73 | pIso7816->responseReady = true; |
kenjiArai | 4:e9dfb4ca4277 | 74 | |
kenjiArai | 4:e9dfb4ca4277 | 75 | iso7816_receive(pIso7816); |
kenjiArai | 4:e9dfb4ca4277 | 76 | nfc_tech_isodep_target_connect(&pIso7816->isoDepTarget); |
kenjiArai | 4:e9dfb4ca4277 | 77 | } |
kenjiArai | 4:e9dfb4ca4277 | 78 | |
kenjiArai | 4:e9dfb4ca4277 | 79 | void nfc_tech_iso7816_disconnect(nfc_tech_iso7816_t *pIso7816) |
kenjiArai | 4:e9dfb4ca4277 | 80 | { |
kenjiArai | 4:e9dfb4ca4277 | 81 | nfc_tech_isodep_target_disconnect(&pIso7816->isoDepTarget); |
kenjiArai | 4:e9dfb4ca4277 | 82 | } |
kenjiArai | 4:e9dfb4ca4277 | 83 | |
kenjiArai | 4:e9dfb4ca4277 | 84 | void nfc_tech_iso7816_add_app(nfc_tech_iso7816_t *pIso7816, nfc_tech_iso7816_app_t *pIso7816App) |
kenjiArai | 4:e9dfb4ca4277 | 85 | { |
kenjiArai | 4:e9dfb4ca4277 | 86 | nfc_tech_iso7816_app_t **ppPrevApp = &pIso7816->pAppList; |
kenjiArai | 4:e9dfb4ca4277 | 87 | while (*ppPrevApp != NULL) { |
kenjiArai | 4:e9dfb4ca4277 | 88 | ppPrevApp = &((*ppPrevApp)->pNext); |
kenjiArai | 4:e9dfb4ca4277 | 89 | } |
kenjiArai | 4:e9dfb4ca4277 | 90 | *ppPrevApp = pIso7816App; |
kenjiArai | 4:e9dfb4ca4277 | 91 | pIso7816App->pNext = NULL; |
kenjiArai | 4:e9dfb4ca4277 | 92 | } |
kenjiArai | 4:e9dfb4ca4277 | 93 | |
kenjiArai | 4:e9dfb4ca4277 | 94 | nfc_err_t nfc_tech_iso7816_reply(nfc_tech_iso7816_t *pIso7816) |
kenjiArai | 4:e9dfb4ca4277 | 95 | { |
kenjiArai | 4:e9dfb4ca4277 | 96 | nfc_err_t ret; |
kenjiArai | 4:e9dfb4ca4277 | 97 | |
kenjiArai | 4:e9dfb4ca4277 | 98 | //Serialize APDU and send |
kenjiArai | 4:e9dfb4ca4277 | 99 | ac_buffer_builder_reset(&pIso7816->txBldr); |
kenjiArai | 4:e9dfb4ca4277 | 100 | ac_buffer_builder_write_nu16(&pIso7816->txBldr, pIso7816->rApdu.sw); |
kenjiArai | 4:e9dfb4ca4277 | 101 | |
kenjiArai | 4:e9dfb4ca4277 | 102 | ac_buffer_append(&pIso7816->rApdu.dataOut, ac_buffer_builder_buffer(&pIso7816->txBldr)); |
kenjiArai | 4:e9dfb4ca4277 | 103 | |
kenjiArai | 4:e9dfb4ca4277 | 104 | NFC_DBG("R-ADPU: (LE):%02X SW:%04X", ac_buffer_reader_readable(&pIso7816->rApdu.dataOut), pIso7816->rApdu.sw); |
kenjiArai | 4:e9dfb4ca4277 | 105 | NFC_DBG_BLOCK(ac_buffer_dump(&pIso7816->rApdu.dataOut);) |
kenjiArai | 4:e9dfb4ca4277 | 106 | |
kenjiArai | 4:e9dfb4ca4277 | 107 | ret = iso7816_transmit(pIso7816); |
kenjiArai | 4:e9dfb4ca4277 | 108 | if (ret) { |
kenjiArai | 4:e9dfb4ca4277 | 109 | return ret; |
kenjiArai | 4:e9dfb4ca4277 | 110 | } |
kenjiArai | 4:e9dfb4ca4277 | 111 | |
kenjiArai | 4:e9dfb4ca4277 | 112 | return NFC_OK; |
kenjiArai | 4:e9dfb4ca4277 | 113 | } |
kenjiArai | 4:e9dfb4ca4277 | 114 | |
kenjiArai | 4:e9dfb4ca4277 | 115 | void iso7816_disconnected(nfc_tech_iso7816_t *pIso7816, bool deselected) |
kenjiArai | 4:e9dfb4ca4277 | 116 | { |
kenjiArai | 4:e9dfb4ca4277 | 117 | pIso7816->disconnected = true; |
kenjiArai | 4:e9dfb4ca4277 | 118 | if (pIso7816->pSelectedApp != NULL) { |
kenjiArai | 4:e9dfb4ca4277 | 119 | //Deselect previous app |
kenjiArai | 4:e9dfb4ca4277 | 120 | pIso7816->pSelectedApp->deselected(pIso7816->pSelectedApp, pIso7816->pSelectedApp->pUserData); |
kenjiArai | 4:e9dfb4ca4277 | 121 | pIso7816->pSelectedApp = NULL; |
kenjiArai | 4:e9dfb4ca4277 | 122 | } |
kenjiArai | 4:e9dfb4ca4277 | 123 | if (!deselected) { |
kenjiArai | 4:e9dfb4ca4277 | 124 | pIso7816->disconnectedCb(pIso7816, pIso7816->pUserData); |
kenjiArai | 4:e9dfb4ca4277 | 125 | } |
kenjiArai | 4:e9dfb4ca4277 | 126 | } |
kenjiArai | 4:e9dfb4ca4277 | 127 | |
kenjiArai | 4:e9dfb4ca4277 | 128 | nfc_err_t iso7816_parse(nfc_tech_iso7816_t *pIso7816) |
kenjiArai | 4:e9dfb4ca4277 | 129 | { |
kenjiArai | 4:e9dfb4ca4277 | 130 | //Reset R-APDU |
kenjiArai | 4:e9dfb4ca4277 | 131 | ac_buffer_init(&pIso7816->rApdu.dataOut, NULL, 0); |
kenjiArai | 4:e9dfb4ca4277 | 132 | pIso7816->rApdu.sw = ISO7816_SW_OK; |
kenjiArai | 4:e9dfb4ca4277 | 133 | |
kenjiArai | 4:e9dfb4ca4277 | 134 | NFC_DBG_BLOCK(ac_buffer_dump(ac_buffer_builder_buffer(&pIso7816->rxBldr));) |
kenjiArai | 4:e9dfb4ca4277 | 135 | |
kenjiArai | 4:e9dfb4ca4277 | 136 | if (ac_buffer_reader_readable(ac_buffer_builder_buffer(&pIso7816->rxBldr)) < 4) { |
kenjiArai | 4:e9dfb4ca4277 | 137 | NFC_ERR("C-APDU is too small"); |
kenjiArai | 4:e9dfb4ca4277 | 138 | pIso7816->rApdu.sw = ISO7816_SW_INVALID_CLASS; |
kenjiArai | 4:e9dfb4ca4277 | 139 | nfc_tech_iso7816_reply(pIso7816); |
kenjiArai | 4:e9dfb4ca4277 | 140 | return NFC_ERR_PROTOCOL; |
kenjiArai | 4:e9dfb4ca4277 | 141 | } |
kenjiArai | 4:e9dfb4ca4277 | 142 | |
kenjiArai | 4:e9dfb4ca4277 | 143 | pIso7816->cApdu.cla = ac_buffer_read_nu8(ac_buffer_builder_buffer(&pIso7816->rxBldr)); |
kenjiArai | 4:e9dfb4ca4277 | 144 | pIso7816->cApdu.ins = ac_buffer_read_nu8(ac_buffer_builder_buffer(&pIso7816->rxBldr)); |
kenjiArai | 4:e9dfb4ca4277 | 145 | pIso7816->cApdu.p1 = ac_buffer_read_nu8(ac_buffer_builder_buffer(&pIso7816->rxBldr)); |
kenjiArai | 4:e9dfb4ca4277 | 146 | pIso7816->cApdu.p2 = ac_buffer_read_nu8(ac_buffer_builder_buffer(&pIso7816->rxBldr)); |
kenjiArai | 4:e9dfb4ca4277 | 147 | ac_buffer_init(&pIso7816->cApdu.dataIn, NULL, 0); |
kenjiArai | 4:e9dfb4ca4277 | 148 | pIso7816->cApdu.maxRespLength = 0; |
kenjiArai | 4:e9dfb4ca4277 | 149 | |
kenjiArai | 4:e9dfb4ca4277 | 150 | if (ac_buffer_reader_readable(ac_buffer_builder_buffer(&pIso7816->rxBldr)) > 1) { |
kenjiArai | 4:e9dfb4ca4277 | 151 | size_t lc = ac_buffer_read_nu8(ac_buffer_builder_buffer(&pIso7816->rxBldr)); |
kenjiArai | 4:e9dfb4ca4277 | 152 | if (ac_buffer_reader_readable(ac_buffer_builder_buffer(&pIso7816->rxBldr)) >= lc) { |
kenjiArai | 4:e9dfb4ca4277 | 153 | ac_buffer_split(&pIso7816->cApdu.dataIn, ac_buffer_builder_buffer(&pIso7816->rxBldr), ac_buffer_builder_buffer(&pIso7816->rxBldr), lc); |
kenjiArai | 4:e9dfb4ca4277 | 154 | } else { |
kenjiArai | 4:e9dfb4ca4277 | 155 | pIso7816->rApdu.sw = ISO7816_SW_WRONG_LENGTH; |
kenjiArai | 4:e9dfb4ca4277 | 156 | nfc_tech_iso7816_reply(pIso7816); |
kenjiArai | 4:e9dfb4ca4277 | 157 | return NFC_ERR_LENGTH; //Not a valid frame |
kenjiArai | 4:e9dfb4ca4277 | 158 | } |
kenjiArai | 4:e9dfb4ca4277 | 159 | } |
kenjiArai | 4:e9dfb4ca4277 | 160 | |
kenjiArai | 4:e9dfb4ca4277 | 161 | if (ac_buffer_reader_readable(ac_buffer_builder_buffer(&pIso7816->rxBldr)) >= 1) { |
kenjiArai | 4:e9dfb4ca4277 | 162 | pIso7816->cApdu.maxRespLength = ac_buffer_read_nu8(ac_buffer_builder_buffer(&pIso7816->rxBldr)); |
kenjiArai | 4:e9dfb4ca4277 | 163 | } |
kenjiArai | 4:e9dfb4ca4277 | 164 | |
kenjiArai | 4:e9dfb4ca4277 | 165 | NFC_DBG("C-APDU: CLA:%02X INS:%02X P1:%02X P2:%02X LC:%02X LE:%02X", pIso7816->cApdu.cla, pIso7816->cApdu.ins, pIso7816->cApdu.p1, pIso7816->cApdu.p2, |
kenjiArai | 4:e9dfb4ca4277 | 166 | ac_buffer_reader_readable(&pIso7816->cApdu.dataIn), pIso7816->cApdu.maxRespLength); |
kenjiArai | 4:e9dfb4ca4277 | 167 | |
kenjiArai | 4:e9dfb4ca4277 | 168 | if (ac_buffer_reader_readable(ac_buffer_builder_buffer(&pIso7816->rxBldr)) > 0) { |
kenjiArai | 4:e9dfb4ca4277 | 169 | pIso7816->rApdu.sw = ISO7816_SW_WRONG_LENGTH; |
kenjiArai | 4:e9dfb4ca4277 | 170 | nfc_tech_iso7816_reply(pIso7816); |
kenjiArai | 4:e9dfb4ca4277 | 171 | return NFC_ERR_LENGTH; //Not a valid frame |
kenjiArai | 4:e9dfb4ca4277 | 172 | } |
kenjiArai | 4:e9dfb4ca4277 | 173 | |
kenjiArai | 4:e9dfb4ca4277 | 174 | //See if can select an app |
kenjiArai | 4:e9dfb4ca4277 | 175 | if (iso7816_mf_command(pIso7816)) { |
kenjiArai | 4:e9dfb4ca4277 | 176 | nfc_tech_iso7816_reply(pIso7816); |
kenjiArai | 4:e9dfb4ca4277 | 177 | return NFC_OK; |
kenjiArai | 4:e9dfb4ca4277 | 178 | } |
kenjiArai | 4:e9dfb4ca4277 | 179 | |
kenjiArai | 4:e9dfb4ca4277 | 180 | //Pass command to selected app |
kenjiArai | 4:e9dfb4ca4277 | 181 | if (pIso7816->pSelectedApp == NULL) { |
kenjiArai | 4:e9dfb4ca4277 | 182 | pIso7816->rApdu.sw = ISO7816_SW_NOT_FOUND; |
kenjiArai | 4:e9dfb4ca4277 | 183 | nfc_tech_iso7816_reply(pIso7816); |
kenjiArai | 4:e9dfb4ca4277 | 184 | return NFC_ERR_NOT_FOUND; //Not a valid frame |
kenjiArai | 4:e9dfb4ca4277 | 185 | } |
kenjiArai | 4:e9dfb4ca4277 | 186 | |
kenjiArai | 4:e9dfb4ca4277 | 187 | pIso7816->pSelectedApp->apdu(pIso7816->pSelectedApp, pIso7816->pSelectedApp->pUserData); |
kenjiArai | 4:e9dfb4ca4277 | 188 | |
kenjiArai | 4:e9dfb4ca4277 | 189 | return NFC_OK; |
kenjiArai | 4:e9dfb4ca4277 | 190 | } |
kenjiArai | 4:e9dfb4ca4277 | 191 | |
kenjiArai | 4:e9dfb4ca4277 | 192 | void iso7816_receive(nfc_tech_iso7816_t *pIso7816) |
kenjiArai | 4:e9dfb4ca4277 | 193 | { |
kenjiArai | 4:e9dfb4ca4277 | 194 | ac_buffer_builder_reset(&pIso7816->rxBldr); |
kenjiArai | 4:e9dfb4ca4277 | 195 | nfc_tech_isodep_target_receive(&pIso7816->isoDepTarget, &pIso7816->outputStream, iso_dep_received_cb, pIso7816); |
kenjiArai | 4:e9dfb4ca4277 | 196 | } |
kenjiArai | 4:e9dfb4ca4277 | 197 | |
kenjiArai | 4:e9dfb4ca4277 | 198 | nfc_err_t iso7816_transmit(nfc_tech_iso7816_t *pIso7816) |
kenjiArai | 4:e9dfb4ca4277 | 199 | { |
kenjiArai | 4:e9dfb4ca4277 | 200 | return nfc_tech_isodep_target_transmit(&pIso7816->isoDepTarget, &pIso7816->inputStream, iso_dep_transmitted_cb, pIso7816); |
kenjiArai | 4:e9dfb4ca4277 | 201 | } |
kenjiArai | 4:e9dfb4ca4277 | 202 | |
kenjiArai | 4:e9dfb4ca4277 | 203 | /** Handle ISO7816-4 command |
kenjiArai | 4:e9dfb4ca4277 | 204 | * \param pTarget pointer to target instance |
kenjiArai | 4:e9dfb4ca4277 | 205 | * \param CLA ISO7816-4 class byte |
kenjiArai | 4:e9dfb4ca4277 | 206 | * \param INS ISO7816-4 instruction byte |
kenjiArai | 4:e9dfb4ca4277 | 207 | * \param P1 ISO7816-4 P1 byte |
kenjiArai | 4:e9dfb4ca4277 | 208 | * \param P2 ISO7816-4 P2 byte |
kenjiArai | 4:e9dfb4ca4277 | 209 | * \param pDataIn ISO7816-4 command payload |
kenjiArai | 4:e9dfb4ca4277 | 210 | * \param pDataOut ISO7816-4 response payload |
kenjiArai | 4:e9dfb4ca4277 | 211 | * \param SW status word |
kenjiArai | 4:e9dfb4ca4277 | 212 | * \return true if command was handled, false if it should be passed to the selected application |
kenjiArai | 4:e9dfb4ca4277 | 213 | */ |
kenjiArai | 4:e9dfb4ca4277 | 214 | bool iso7816_mf_command(nfc_tech_iso7816_t *pIso7816) |
kenjiArai | 4:e9dfb4ca4277 | 215 | { |
kenjiArai | 4:e9dfb4ca4277 | 216 | nfc_tech_iso7816_app_t *pApp; |
kenjiArai | 4:e9dfb4ca4277 | 217 | if (pIso7816->cApdu.cla != 0x00) { |
kenjiArai | 4:e9dfb4ca4277 | 218 | return false; |
kenjiArai | 4:e9dfb4ca4277 | 219 | } |
kenjiArai | 4:e9dfb4ca4277 | 220 | switch (pIso7816->cApdu.ins) { |
kenjiArai | 4:e9dfb4ca4277 | 221 | case ISO7816_INS_SELECT: |
kenjiArai | 4:e9dfb4ca4277 | 222 | switch (pIso7816->cApdu.p1) { |
kenjiArai | 4:e9dfb4ca4277 | 223 | case 0x04: //Selection by DF name |
kenjiArai | 4:e9dfb4ca4277 | 224 | pApp = pIso7816->pAppList; |
kenjiArai | 4:e9dfb4ca4277 | 225 | while (pApp != NULL) { |
kenjiArai | 4:e9dfb4ca4277 | 226 | if (ac_buffer_reader_readable(&pIso7816->cApdu.dataIn) <= pApp->aidSize) { |
kenjiArai | 4:e9dfb4ca4277 | 227 | if (ac_buffer_reader_cmp_bytes(&pIso7816->cApdu.dataIn, pApp->aid, ac_buffer_reader_readable(&pIso7816->cApdu.dataIn))) { |
kenjiArai | 4:e9dfb4ca4277 | 228 | if (pIso7816->pSelectedApp != NULL) { |
kenjiArai | 4:e9dfb4ca4277 | 229 | //Deselect previous app |
kenjiArai | 4:e9dfb4ca4277 | 230 | pIso7816->pSelectedApp->deselected(pIso7816->pSelectedApp, pIso7816->pSelectedApp->pUserData); |
kenjiArai | 4:e9dfb4ca4277 | 231 | } |
kenjiArai | 4:e9dfb4ca4277 | 232 | pIso7816->pSelectedApp = pApp; |
kenjiArai | 4:e9dfb4ca4277 | 233 | pIso7816->pSelectedApp->selected(pIso7816->pSelectedApp, pIso7816->pSelectedApp->pUserData); |
kenjiArai | 4:e9dfb4ca4277 | 234 | pIso7816->rApdu.sw = ISO7816_SW_OK; |
kenjiArai | 4:e9dfb4ca4277 | 235 | return true; |
kenjiArai | 4:e9dfb4ca4277 | 236 | } |
kenjiArai | 4:e9dfb4ca4277 | 237 | } |
kenjiArai | 4:e9dfb4ca4277 | 238 | pApp = pApp->pNext; |
kenjiArai | 4:e9dfb4ca4277 | 239 | } |
kenjiArai | 4:e9dfb4ca4277 | 240 | pIso7816->rApdu.sw = ISO7816_SW_NOT_FOUND; |
kenjiArai | 4:e9dfb4ca4277 | 241 | return true; |
kenjiArai | 4:e9dfb4ca4277 | 242 | default: |
kenjiArai | 4:e9dfb4ca4277 | 243 | if (pIso7816->pSelectedApp == NULL) { |
kenjiArai | 4:e9dfb4ca4277 | 244 | pIso7816->rApdu.sw = ISO7816_SW_NOT_FOUND; |
kenjiArai | 4:e9dfb4ca4277 | 245 | return true; |
kenjiArai | 4:e9dfb4ca4277 | 246 | } else { |
kenjiArai | 4:e9dfb4ca4277 | 247 | return false; |
kenjiArai | 4:e9dfb4ca4277 | 248 | } |
kenjiArai | 4:e9dfb4ca4277 | 249 | } |
kenjiArai | 4:e9dfb4ca4277 | 250 | break; |
kenjiArai | 4:e9dfb4ca4277 | 251 | default: |
kenjiArai | 4:e9dfb4ca4277 | 252 | if (pIso7816->pSelectedApp == NULL) { |
kenjiArai | 4:e9dfb4ca4277 | 253 | pIso7816->rApdu.sw = ISO7816_SW_INVALID_INS; |
kenjiArai | 4:e9dfb4ca4277 | 254 | return true; |
kenjiArai | 4:e9dfb4ca4277 | 255 | } else { |
kenjiArai | 4:e9dfb4ca4277 | 256 | return false; |
kenjiArai | 4:e9dfb4ca4277 | 257 | } |
kenjiArai | 4:e9dfb4ca4277 | 258 | break; |
kenjiArai | 4:e9dfb4ca4277 | 259 | } |
kenjiArai | 4:e9dfb4ca4277 | 260 | } |
kenjiArai | 4:e9dfb4ca4277 | 261 | |
kenjiArai | 4:e9dfb4ca4277 | 262 | void iso_dep_received_cb(nfc_tech_isodep_t *pIsodep, nfc_err_t ret, void *pUserData) |
kenjiArai | 4:e9dfb4ca4277 | 263 | { |
kenjiArai | 4:e9dfb4ca4277 | 264 | nfc_tech_iso7816_t *pIso7816 = (nfc_tech_iso7816_t *) pUserData; |
kenjiArai | 4:e9dfb4ca4277 | 265 | |
kenjiArai | 4:e9dfb4ca4277 | 266 | (void) pIsodep; |
kenjiArai | 4:e9dfb4ca4277 | 267 | |
kenjiArai | 4:e9dfb4ca4277 | 268 | if (ret) { |
kenjiArai | 4:e9dfb4ca4277 | 269 | NFC_WARN("Got error %d", ret); |
kenjiArai | 4:e9dfb4ca4277 | 270 | return; |
kenjiArai | 4:e9dfb4ca4277 | 271 | } |
kenjiArai | 4:e9dfb4ca4277 | 272 | |
kenjiArai | 4:e9dfb4ca4277 | 273 | //Parse received APDU |
kenjiArai | 4:e9dfb4ca4277 | 274 | ret = iso7816_parse(pIso7816); |
kenjiArai | 4:e9dfb4ca4277 | 275 | if (ret) { |
kenjiArai | 4:e9dfb4ca4277 | 276 | NFC_WARN("Got error %d", ret); |
kenjiArai | 4:e9dfb4ca4277 | 277 | return; |
kenjiArai | 4:e9dfb4ca4277 | 278 | } |
kenjiArai | 4:e9dfb4ca4277 | 279 | } |
kenjiArai | 4:e9dfb4ca4277 | 280 | |
kenjiArai | 4:e9dfb4ca4277 | 281 | void iso_dep_transmitted_cb(nfc_tech_isodep_t *pIsodep, nfc_err_t ret, void *pUserData) |
kenjiArai | 4:e9dfb4ca4277 | 282 | { |
kenjiArai | 4:e9dfb4ca4277 | 283 | nfc_tech_iso7816_t *pIso7816 = (nfc_tech_iso7816_t *) pUserData; |
kenjiArai | 4:e9dfb4ca4277 | 284 | |
kenjiArai | 4:e9dfb4ca4277 | 285 | (void) pIsodep; |
kenjiArai | 4:e9dfb4ca4277 | 286 | |
kenjiArai | 4:e9dfb4ca4277 | 287 | if (ret) { |
kenjiArai | 4:e9dfb4ca4277 | 288 | NFC_WARN("Got error %d", ret); |
kenjiArai | 4:e9dfb4ca4277 | 289 | return; |
kenjiArai | 4:e9dfb4ca4277 | 290 | } |
kenjiArai | 4:e9dfb4ca4277 | 291 | |
kenjiArai | 4:e9dfb4ca4277 | 292 | //Advertise that we have space in our buffer? |
kenjiArai | 4:e9dfb4ca4277 | 293 | |
kenjiArai | 4:e9dfb4ca4277 | 294 | //Switch to receive mode! |
kenjiArai | 4:e9dfb4ca4277 | 295 | iso7816_receive(pIso7816); |
kenjiArai | 4:e9dfb4ca4277 | 296 | } |
kenjiArai | 4:e9dfb4ca4277 | 297 | |
kenjiArai | 4:e9dfb4ca4277 | 298 | void iso_dep_disconnected_cb(nfc_tech_isodep_t *pIsodep, bool deselected, void *pUserData) |
kenjiArai | 4:e9dfb4ca4277 | 299 | { |
kenjiArai | 4:e9dfb4ca4277 | 300 | nfc_tech_iso7816_t *pIso7816 = (nfc_tech_iso7816_t *) pUserData; |
kenjiArai | 4:e9dfb4ca4277 | 301 | |
kenjiArai | 4:e9dfb4ca4277 | 302 | (void) pIsodep; |
kenjiArai | 4:e9dfb4ca4277 | 303 | |
kenjiArai | 4:e9dfb4ca4277 | 304 | NFC_DBG("ISO DEP %s", deselected ? "deselected" : "disconnected"); |
kenjiArai | 4:e9dfb4ca4277 | 305 | iso7816_disconnected(pIso7816, deselected); |
kenjiArai | 4:e9dfb4ca4277 | 306 | |
kenjiArai | 4:e9dfb4ca4277 | 307 | if (deselected) { |
kenjiArai | 4:e9dfb4ca4277 | 308 | // Re-connect immediately |
kenjiArai | 4:e9dfb4ca4277 | 309 | nfc_tech_iso7816_connect(pIso7816); |
kenjiArai | 4:e9dfb4ca4277 | 310 | } |
kenjiArai | 4:e9dfb4ca4277 | 311 | } |
kenjiArai | 4:e9dfb4ca4277 | 312 | |
kenjiArai | 4:e9dfb4ca4277 | 313 | void iso_dep_stream_transmit_cb(ac_buffer_t *pDataIn, bool *pClose, size_t maxLength, void *pUserParam) |
kenjiArai | 4:e9dfb4ca4277 | 314 | { |
kenjiArai | 4:e9dfb4ca4277 | 315 | nfc_tech_iso7816_t *pIso7816 = (nfc_tech_iso7816_t *) pUserParam; |
kenjiArai | 4:e9dfb4ca4277 | 316 | |
kenjiArai | 4:e9dfb4ca4277 | 317 | //Only close if buffer fits in this frame |
kenjiArai | 4:e9dfb4ca4277 | 318 | if (maxLength >= ac_buffer_reader_readable(&pIso7816->rApdu.dataOut)) |
kenjiArai | 4:e9dfb4ca4277 | 319 | //if( ac_buffer_total_length(&pLlcp->tx) <= maxLength ) |
kenjiArai | 4:e9dfb4ca4277 | 320 | { |
kenjiArai | 4:e9dfb4ca4277 | 321 | maxLength = ac_buffer_reader_readable(&pIso7816->rApdu.dataOut); |
kenjiArai | 4:e9dfb4ca4277 | 322 | *pClose = true; |
kenjiArai | 4:e9dfb4ca4277 | 323 | } else { |
kenjiArai | 4:e9dfb4ca4277 | 324 | *pClose = false; |
kenjiArai | 4:e9dfb4ca4277 | 325 | } |
kenjiArai | 4:e9dfb4ca4277 | 326 | |
kenjiArai | 4:e9dfb4ca4277 | 327 | ac_buffer_split(pDataIn, &pIso7816->rApdu.dataOut, &pIso7816->rApdu.dataOut, maxLength); |
kenjiArai | 4:e9dfb4ca4277 | 328 | } |
kenjiArai | 4:e9dfb4ca4277 | 329 | |
kenjiArai | 4:e9dfb4ca4277 | 330 | void iso_dep_stream_receive_cb(ac_buffer_t *pDataOut, bool closed, void *pUserParam) |
kenjiArai | 4:e9dfb4ca4277 | 331 | { |
kenjiArai | 4:e9dfb4ca4277 | 332 | nfc_tech_iso7816_t *pIso7816 = (nfc_tech_iso7816_t *) pUserParam; |
kenjiArai | 4:e9dfb4ca4277 | 333 | |
kenjiArai | 4:e9dfb4ca4277 | 334 | (void) closed; |
kenjiArai | 4:e9dfb4ca4277 | 335 | |
kenjiArai | 4:e9dfb4ca4277 | 336 | if (ac_buffer_reader_readable(pDataOut) > ac_buffer_builder_writable(&pIso7816->rxBldr)) { |
kenjiArai | 4:e9dfb4ca4277 | 337 | NFC_ERR("Frame will not fit (%u > %u)", ac_buffer_reader_readable(pDataOut), ac_buffer_builder_writable(&pIso7816->rxBldr)); |
kenjiArai | 4:e9dfb4ca4277 | 338 | } |
kenjiArai | 4:e9dfb4ca4277 | 339 | |
kenjiArai | 4:e9dfb4ca4277 | 340 | //Feed rx buffer |
kenjiArai | 4:e9dfb4ca4277 | 341 | ac_buffer_builder_copy_n_bytes(&pIso7816->rxBldr, pDataOut, ac_buffer_reader_readable(pDataOut)); |
kenjiArai | 4:e9dfb4ca4277 | 342 | } |
kenjiArai | 4:e9dfb4ca4277 | 343 |