Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions io/include/os_io_nfc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*****************************************************************************
* (c) 2025 Ledger SAS.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*****************************************************************************/

#pragma once

#ifdef HAVE_NFC_READER

enum card_tech {
NFC_A,
NFC_B
};

enum nfc_event {
CARD_DETECTED,
CARD_REMOVED,
};

struct card_info {
enum card_tech tech;
uint8_t nfcid[7];
size_t nfcid_len;
};

typedef void (*nfc_evt_callback_t)(enum nfc_event event, struct card_info *info);
typedef void (*nfc_resp_callback_t)(bool error, bool timeout, uint8_t *resp_data, size_t resp_len);

bool os_io_nfc_reader_send(const uint8_t *cmd_data,
size_t cmd_len,
nfc_resp_callback_t callback,
int timeout_ms);

/* Return false if nfc reader can not be started in current conditions */
bool os_io_nfc_reader_start(nfc_evt_callback_t callback);
void os_io_nfc_reader_stop(void);
#endif // HAVE_NFC_READER
167 changes: 167 additions & 0 deletions io/src/os_io_nfc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
#ifdef HAVE_NFC_READER

/* Includes ------------------------------------------------------------------*/
#include <string.h>
#include "os_io.h"
#include "os_io_seph_cmd.h"
#include "checks.h"
#include "errors.h"
#include "os_io_nfc.h"
#include "os_pic.h"
#include "decorators.h"

#ifdef HAVE_PRINTF
#define LOG_IO PRINTF
// #define LOG_IO(...)
#else // !HAVE_PRINTF
#define LOG_IO(...)
#endif // !HAVE_PRINTF

/* Private enumerations ------------------------------------------------------*/

/* Private types, structures, unions -----------------------------------------*/

struct nfc_reader_context {
nfc_resp_callback_t resp_callback;
nfc_evt_callback_t evt_callback;
bool reader_mode;
unsigned int remaining_ms;
struct card_info card;
};

/* Private defines------------------------------------------------------------*/

/* Private macros-------------------------------------------------------------*/

/* Private functions prototypes ----------------------------------------------*/
static void nfc_event(uint8_t *buffer_in, size_t buffer_in_length);
static void nfc_ticker(void);

/* Private variables ---------------------------------------------------------*/

static struct nfc_reader_context G_io_reader_ctx = {};

/* Private functions ---------------------------------------------------------*/

static void nfc_event(uint8_t *buffer_in, size_t buffer_in_length)
{
if (buffer_in_length < 3) {
return;
}
size_t size = U2BE(buffer_in, 1);
if (buffer_in_length < 3 + size) {
return;
}

if (size >= 1) {
switch (buffer_in[3]) {
case SEPROXYHAL_TAG_NFC_EVENT_CARD_DETECTED: {
G_io_reader_ctx.card.tech
= (buffer_in[4] == SEPROXYHAL_TAG_NFC_EVENT_CARD_DETECTED_A) ? NFC_A : NFC_B;
G_io_reader_ctx.card.nfcid_len = MIN(size - 2, sizeof(G_io_reader_ctx.card.nfcid));
memcpy((void *) G_io_reader_ctx.card.nfcid,
buffer_in + 5,
G_io_reader_ctx.card.nfcid_len);

if (G_io_reader_ctx.evt_callback != NULL) {
G_io_reader_ctx.evt_callback(CARD_DETECTED,
(struct card_info *) &G_io_reader_ctx.card);
}
} break;

case SEPROXYHAL_TAG_NFC_EVENT_CARD_LOST:
// If card is removed during an APDU processing, call the resp_callback with an
// error
if (G_io_reader_ctx.resp_callback != NULL) {
nfc_resp_callback_t resp_cb = G_io_reader_ctx.resp_callback;
G_io_reader_ctx.resp_callback = NULL;
resp_cb(true, false, NULL, 0);
}

if (G_io_reader_ctx.evt_callback != NULL) {
G_io_reader_ctx.evt_callback(CARD_REMOVED,
(struct card_info *) &G_io_reader_ctx.card);
}
memset((void *) &G_io_reader_ctx.card, 0, sizeof(G_io_reader_ctx.card));
break;
}
}
}

static void nfc_ticker(void)
{
if (G_io_reader_ctx.resp_callback != NULL) {
if (G_io_reader_ctx.remaining_ms <= 100) {
G_io_reader_ctx.remaining_ms = 0;
nfc_resp_callback_t resp_cb = G_io_reader_ctx.resp_callback;
G_io_reader_ctx.resp_callback = NULL;
resp_cb(false, true, NULL, 0);
}
else {
G_io_reader_ctx.remaining_ms -= 100;
}
}
}

/* Exported functions --------------------------------------------------------*/

void os_io_nfc_reader_rx(uint8_t *in_buffer, size_t in_buffer_len)
{
if (G_io_reader_ctx.resp_callback != NULL) {
nfc_resp_callback_t resp_cb = G_io_reader_ctx.resp_callback;
G_io_reader_ctx.resp_callback = NULL;
resp_cb(false, false, in_buffer, in_buffer_len);
}
}

void os_io_nfc_evt(uint8_t *buffer_in, size_t buffer_in_length)
{
switch (buffer_in[0]) {
case SEPROXYHAL_TAG_NFC_EVENT:
nfc_event(buffer_in, buffer_in_length);
break;

case SEPROXYHAL_TAG_TICKER_EVENT:
nfc_ticker();
break;

default:
break;
}
}

bool os_io_nfc_reader_send(const uint8_t *cmd_data,
size_t cmd_len,
nfc_resp_callback_t callback,
int timeout_ms)
{
G_io_reader_ctx.resp_callback = PIC(callback);
os_io_tx_cmd(APDU_TYPE_NFC, PIC(cmd_data), cmd_len, 0);

G_io_reader_ctx.remaining_ms = timeout_ms;

return true;
}

bool os_io_nfc_reader_start(nfc_evt_callback_t callback)
{
G_io_reader_ctx.evt_callback = PIC(callback);
G_io_reader_ctx.reader_mode = true;
G_io_reader_ctx.resp_callback = NULL;
os_io_nfc_cmd_start_reader();
return true;
}

void os_io_nfc_reader_stop(void)
{
G_io_reader_ctx.evt_callback = NULL;
G_io_reader_ctx.reader_mode = false;
G_io_reader_ctx.resp_callback = NULL;
os_io_nfc_cmd_stop();
}

bool os_io_nfc_is_reader(void)
{
return G_io_reader_ctx.reader_mode;
}
#endif // HAVE_NFC_READER
14 changes: 0 additions & 14 deletions io_legacy/include/os_io_legacy.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,6 @@ extern unsigned char G_io_asynch_ux_callback;

/* Exported variables --------------------------------------------------------*/
extern unsigned char G_io_seproxyhal_spi_buffer[OS_IO_SEPH_BUFFER_SIZE];
#ifdef HAVE_NFC_READER
extern struct nfc_reader_context G_io_reader_ctx;
#endif // HAVE_NFC_READER

/* Exported functions prototypes--------------------------------------------- */
SYSCALL void io_seph_send(const unsigned char *buffer PLENGTH(length), unsigned short length);
Expand Down Expand Up @@ -98,14 +95,3 @@ unsigned char io_event(unsigned char channel);

int io_legacy_apdu_rx(uint8_t handle_ux_events);
int io_legacy_apdu_tx(const unsigned char *buffer, unsigned short length);

#ifdef HAVE_NFC_READER
bool io_nfc_reader_send(const uint8_t *cmd_data,
size_t cmd_len,
nfc_resp_callback_t callback,
int timeout_ms);

/* Return false if nfc reader can not be started in current conditions */
bool io_nfc_reader_start(nfc_evt_callback_t callback);
void io_nfc_reader_stop(void);
#endif // HAVE_NFC_READER
37 changes: 0 additions & 37 deletions io_legacy/include/os_io_legacy_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,6 @@ typedef enum {
APDU_USB_WEBUSB,
} io_apdu_state_e;

#ifdef HAVE_NFC_READER
enum card_tech {
NFC_A,
NFC_B
};

enum nfc_event {
CARD_DETECTED,
CARD_REMOVED,
};
#endif // HAVE_NFC_READER

/* Exported types, structures, unions ----------------------------------------*/
typedef struct {
io_apdu_state_e apdu_state; // by default
Expand All @@ -77,31 +65,6 @@ typedef struct {
#endif // HAVE_BLE
} io_seph_app_t;

#ifdef HAVE_NFC_READER
struct card_info {
enum card_tech tech;
uint8_t nfcid[7];
size_t nfcid_len;
};

typedef void (*nfc_evt_callback_t)(enum nfc_event event, struct card_info *info);
typedef void (*nfc_resp_callback_t)(bool error, bool timeout, uint8_t *resp_data, size_t resp_len);

struct nfc_reader_context {
nfc_resp_callback_t resp_callback;
nfc_evt_callback_t evt_callback;
bool reader_mode;
bool event_happened;
bool response_received;
unsigned int remaining_ms;
enum nfc_event last_event;
struct card_info card;
uint8_t *apdu_rx;
size_t apdu_rx_len; // Used length
size_t apdu_rx_max_size; // Max size of buffer
};
#endif // HAVE_NFC_READER

/* Exported defines --------------------------------------------------------*/
#ifdef IO_SEPROXYHAL_BUFFER_SIZE_B
#undef IO_SEPROXYHAL_BUFFER_SIZE_B
Expand Down
Loading