Skip to content

Commit ee3caef

Browse files
committed
FeliCa: Handle non-hardware Polling commands
NFC TagInfo and possibly other readers rely on Polling commands with Request Code of 1 (default System Code request) or non-FFFF System Code to detect card type. Since the NFC controller doesn't seem to handle them in hardware and simply bubbles them up, and then the Flipper firmware will just ignore them and refuse to respond afterwards, this causes the reading operation to fail. This commit adds a simple handler for such Polling commands so that readers behaving like NFC TagInfo could read the emulated card without failing.
1 parent 5b911f5 commit ee3caef

File tree

3 files changed

+85
-2
lines changed

3 files changed

+85
-2
lines changed

lib/nfc/protocols/felica/felica.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ typedef enum {
5858
FelicaErrorWrongCrc,
5959
FelicaErrorProtocol,
6060
FelicaErrorTimeout,
61+
FelicaErrorIgnoreRequest,
6162
} FelicaError;
6263

6364
typedef struct {

lib/nfc/protocols/felica/felica_listener.c

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,17 @@
55
#include <furi_hal_nfc.h>
66

77
#define FELICA_LISTENER_MAX_BUFFER_SIZE (128)
8+
#define FELICA_CMD_POLLING (0x00U)
9+
#define FELICA_LISTENER_RESPONSE_POLLING (FELICA_CMD_POLLING | 1U)
810
#define FELICA_LISTENER_RESPONSE_CODE_READ (0x07)
911
#define FELICA_LISTENER_RESPONSE_CODE_WRITE (0x09)
1012

13+
#define FELICA_POLLING_REQUEST_NONE (0x00U)
14+
#define FELICA_POLLING_REQUEST_SYSTEM_CODE (0x01U)
15+
#define FELICA_POLLING_REQUEST_PERFORMANCE (0x02U)
16+
17+
#define FELICA_SYSTEM_CODE_LITES (0xB488U)
18+
1119
#define TAG "FelicaListener"
1220

1321
FelicaListener* felica_listener_alloc(Nfc* nfc, FelicaData* data) {
@@ -136,6 +144,45 @@ static FelicaError felica_listener_command_handler_write(
136144
return felica_listener_frame_exchange(instance, instance->tx_buffer);
137145
}
138146

147+
static FelicaError felica_listener_user_polling_handler(
148+
FelicaListener* instance,
149+
const FelicaListenerGenericRequest* generic_request) {
150+
switch(generic_request->polling.request_code) {
151+
case FELICA_POLLING_REQUEST_NONE: {
152+
if(generic_request->polling.system_code != FELICA_SYSTEM_CODE_CODE) {
153+
return FelicaErrorIgnoreRequest;
154+
} else {
155+
FURI_LOG_E(
156+
TAG,
157+
"NFC controller should have handled this Polling request. Please report this issue.");
158+
return FelicaErrorNotPresent;
159+
}
160+
break;
161+
}
162+
case FELICA_POLLING_REQUEST_SYSTEM_CODE: {
163+
FelicaPollingResponseWithRequest* resp = malloc(sizeof(FelicaPollingResponseWithRequest));
164+
resp->base.length = sizeof(FelicaPollingResponseWithRequest);
165+
resp->base.response_code = FELICA_LISTENER_RESPONSE_POLLING;
166+
resp->base.idm = instance->data->idm;
167+
resp->base.pmm = instance->data->pmm;
168+
resp->request_data = FELICA_SYSTEM_CODE_LITES;
169+
170+
bit_buffer_reset(instance->tx_buffer);
171+
bit_buffer_append_bytes(instance->tx_buffer, (uint8_t*)resp, resp->base.length);
172+
173+
free(resp);
174+
break;
175+
}
176+
default:
177+
FURI_LOG_E(
178+
TAG,
179+
"FeliCa unhandled polling request code %02X",
180+
generic_request->polling.request_code);
181+
return FelicaErrorNotPresent;
182+
}
183+
return felica_listener_frame_exchange(instance, instance->tx_buffer);
184+
}
185+
139186
static FelicaError felica_listener_process_request(
140187
FelicaListener* instance,
141188
const FelicaListenerGenericRequest* generic_request) {
@@ -187,7 +234,16 @@ NfcCommand felica_listener_run(NfcGenericEvent event, void* context) {
187234
break;
188235
}
189236

190-
if(!felica_listener_check_idm(instance, &request->header.idm)) {
237+
if(request->header.code == FELICA_CMD_POLLING) {
238+
// Catch any Request Code requests that were not handled in hardware.
239+
FelicaError error = felica_listener_user_polling_handler(instance, request);
240+
if(error == FelicaErrorIgnoreRequest) {
241+
command = NfcCommandReset;
242+
} else if(error != FelicaErrorNone) {
243+
FURI_LOG_E(TAG, "User polling handler error: %2X", error);
244+
}
245+
break;
246+
} else if(!felica_listener_check_idm(instance, &request->header.idm)) {
191247
FURI_LOG_E(TAG, "Wrong IDm");
192248
break;
193249
}

lib/nfc/protocols/felica/felica_listener_i.h

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,36 @@ typedef enum {
1212
Felica_ListenerStateActivated,
1313
} FelicaListenerState;
1414

15+
#pragma pack(push, 1)
16+
typedef struct {
17+
uint8_t code;
18+
uint16_t system_code;
19+
uint8_t request_code;
20+
uint8_t time_slot;
21+
} FelicaListenerPollingHeader;
22+
#pragma pack(pop)
23+
24+
typedef struct {
25+
uint8_t length;
26+
uint8_t response_code;
27+
FelicaIDm idm;
28+
FelicaPMm pmm;
29+
} FelicaListenerPollingResponse;
30+
31+
#pragma pack(push, 1)
32+
typedef struct {
33+
FelicaListenerPollingResponse base;
34+
uint16_t request_data;
35+
} FelicaPollingResponseWithRequest;
36+
#pragma pack(pop)
37+
1538
/** Generic Felica request same for both read and write operations. */
1639
typedef struct {
1740
uint8_t length;
18-
FelicaCommandHeader header;
41+
union {
42+
FelicaCommandHeader header;
43+
FelicaListenerPollingHeader polling;
44+
};
1945
} FelicaListenerGenericRequest;
2046

2147
/** Generic request but with list of requested elements. */

0 commit comments

Comments
 (0)