Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
io.c
Go to the documentation of this file.
1/*****************************************************************************
2 * (c) 2021 Ledger SAS.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
16
17#include <stdint.h>
18#include <string.h>
19
20#include "os.h"
21#include "io.h"
22#include "write.h"
23
24#ifdef HAVE_SWAP
25#include "swap.h"
26#endif
27
28#ifdef HAVE_NFC_READER
29#include "os_io_nfc.h"
30#endif // HAVE_NFC_READER
31
32// TODO: Temporary workaround, at some point all status words should be defined by the SDK and
33// removed from the application
34#define SW_OK 0x9000
35#define SW_WRONG_RESPONSE_LENGTH 0xB000
36
37uint8_t G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
38
39#ifdef HAVE_NFC_READER
40struct nfc_reader_context G_io_reader_ctx;
41#endif
42
46static uint32_t G_output_len = 0;
47
51static io_state_e G_io_state = READY;
52
53#ifdef HAVE_BAGL
54WEAK void io_seproxyhal_display(const bagl_element_t *element)
55{
57}
58#endif // HAVE_BAGL
59
60// This function can be used to declare a callback to SEPROXYHAL_TAG_TICKER_EVENT in the application
62
64{
65 (void) channel;
66
67 switch (G_io_seproxyhal_spi_buffer[0]) {
68 case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT:
70 break;
71 case SEPROXYHAL_TAG_STATUS_EVENT:
72 if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID && //
73 !(U4BE(G_io_seproxyhal_spi_buffer, 3) & //
74 SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) {
75 THROW(EXCEPTION_IO_RESET);
76 }
77 __attribute__((fallthrough));
78 case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT:
79#ifdef HAVE_BAGL
81#endif // HAVE_BAGL
82#ifdef HAVE_NBGL
84#endif // HAVE_NBGL
85 break;
86#ifdef HAVE_NBGL
87 case SEPROXYHAL_TAG_FINGER_EVENT:
89 break;
90#endif // HAVE_NBGL
91 case SEPROXYHAL_TAG_TICKER_EVENT:
94#ifdef HAVE_NFC_READER
95 io_nfc_ticker();
96 io_nfc_process_events();
97#endif // HAVE_NFC_READER
98 break;
99 default:
101 break;
102 }
103
104 if (!io_seproxyhal_spi_is_status_sent()) {
105 io_seproxyhal_general_status();
106 }
107
108 return 1;
109}
110
112{
113 switch (channel & ~(IO_FLAGS)) {
114 case CHANNEL_KEYBOARD:
115 break;
116 case CHANNEL_SPI:
117 if (tx_len) {
118 io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len);
119
120 if (channel & IO_RESET_AFTER_REPLIED) {
121 halt();
122 }
123
124 return 0;
125 }
126 else {
127 return io_seproxyhal_spi_recv(G_io_apdu_buffer, sizeof(G_io_apdu_buffer), 0);
128 }
129 default:
130 THROW(INVALID_PARAMETER);
131 }
132
133 return 0;
134}
135
137{
138 // Reset length of APDU response
139 G_output_len = 0;
140 G_io_state = READY;
141}
142
144{
145 int ret = -1;
146
147 switch (G_io_state) {
148 case READY:
149 ret = io_exchange(CHANNEL_APDU | IO_CONTINUE_RX, G_output_len);
150 G_io_state = RECEIVED;
151 break;
152 case RECEIVED:
153 G_io_state = WAITING;
154 ret = io_exchange(CHANNEL_APDU | IO_ASYNCH_REPLY, G_output_len);
155 G_io_state = RECEIVED;
156 break;
157 case WAITING:
158 G_io_state = READY;
159 ret = -1;
160 break;
161 }
162
163 return ret;
164}
165
166WEAK int io_send_response_buffers(const buffer_t *rdatalist, size_t count, uint16_t sw)
167{
168 int ret = -1;
169
170 G_output_len = 0;
171 if (rdatalist && count > 0) {
172 for (size_t i = 0; i < count; i++) {
173 const buffer_t *rdata = &rdatalist[i];
174
175 if (!buffer_copy(rdata,
176 G_io_apdu_buffer + G_output_len,
177 sizeof(G_io_apdu_buffer) - G_output_len - 2)) {
178 return io_send_sw(SW_WRONG_RESPONSE_LENGTH);
179 }
180 G_output_len += rdata->size - rdata->offset;
181 if (count > 1) {
182 PRINTF("<= FRAG (%u/%u) RData=%.*H\n", i + 1, count, rdata->size, rdata->ptr);
183 }
184 }
185 PRINTF("<= SW=%04X | RData=%.*H\n", sw, G_output_len, G_io_apdu_buffer);
186 }
187 else {
188 PRINTF("<= SW=%04X | RData=\n", sw);
189 }
190
191 write_u16_be(G_io_apdu_buffer, G_output_len, sw);
192 G_output_len += 2;
193
194#ifdef HAVE_SWAP
195 // If we are in swap mode and have validated a TX, we send it and immediately quit
197 PRINTF("Swap answer is processed. Send it\n");
198 if (io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, G_output_len) == 0) {
199 PRINTF("Returning to Exchange with status %d\n", (sw == SW_OK));
201 PRINTF("os_lib_end\n");
202 os_lib_end();
203 }
204 else {
205 PRINTF("Unrecoverable\n");
206 os_sched_exit(-1);
207 }
208 }
209#endif // HAVE_SWAP
210
211 switch (G_io_state) {
212 case READY:
213 ret = -1;
214 break;
215 case RECEIVED:
216#ifdef STANDARD_APP_SYNC_RAPDU
217 // Send synchronously the APDU response.
218 // This is needed to send the response before displaying synchronous
219 // status message on the screen.
220 // This is not always done to spare the RAM (stack) on LNS.
221 __attribute__((fallthrough));
222#else
223 G_io_state = READY;
224 ret = 0;
225 break;
226#endif
227 case WAITING:
228 ret = io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, G_output_len);
229 G_output_len = 0;
230 G_io_state = READY;
231 break;
232 }
233
234 return ret;
235}
236
237#ifdef STANDARD_APP_SYNC_RAPDU
238WEAK bool io_recv_and_process_event(void)
239{
240 int apdu_state = G_io_app.apdu_state;
241
242 os_io_seph_recv_and_process(0);
243
244 // If an APDU was received in previous os_io_seph_recv_and_process call and
245 // is waiting to be processed, return true
246 if (apdu_state == APDU_IDLE && G_io_app.apdu_state != APDU_IDLE) {
247 return true;
248 }
249
250 return false;
251}
252#endif
bool buffer_copy(const buffer_t *buffer, uint8_t *out, size_t out_len)
Definition buffer.c:153
uint8_t G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B]
Definition io.c:37
WEAK uint16_t io_exchange_al(uint8_t channel, uint16_t tx_len)
Definition io.c:111
#define SW_WRONG_RESPONSE_LENGTH
Definition io.c:35
#define SW_OK
Definition io.c:34
WEAK int io_send_response_buffers(const buffer_t *rdatalist, size_t count, uint16_t sw)
Definition io.c:166
WEAK void io_init()
Definition io.c:136
WEAK uint8_t io_event(uint8_t channel)
Definition io.c:63
WEAK int io_recv_command()
Definition io.c:143
WEAK void app_ticker_event_callback(void)
Definition io.c:61
io_state_e
Definition io.h:14
@ RECEIVED
ready for new event
Definition io.h:16
@ READY
Definition io.h:15
@ WAITING
data received
Definition io.h:17
#define WEAK
Definition macros.h:8
__attribute__((section("._nbgl_fonts_"))) const
return the non-unicode font corresponding to the given font ID
Definition nbgl_fonts.c:67
const uint8_t * ptr
Definition buffer.h:19
size_t size
Pointer to byte buffer.
Definition buffer.h:20
size_t offset
Size of byte buffer.
Definition buffer.h:21
volatile bool G_called_from_swap
volatile bool G_swap_response_ready
volatile uint8_t * G_swap_signing_return_value_address
unsigned short uint16_t
Definition usbd_conf.h:54
unsigned char uint8_t
Definition usbd_conf.h:53
#define UX_TICKER_EVENT(seph_packet, callback)
Definition ux_bagl.h:623
#define UX_FINGER_EVENT(seph_packet)
Definition ux_bagl.h:618
void io_seproxyhal_display(const bagl_element_t *element)
void io_seproxyhal_display_default(const bagl_element_t *element)
#define UX_DEFAULT_EVENT()
Definition ux_bagl.h:650
#define UX_BUTTON_PUSH_EVENT(seph_packet)
Definition ux_bagl.h:607
#define UX_DISPLAYED_EVENT(displayed_callback)
Definition ux_bagl.h:569
void write_u16_be(uint8_t *ptr, size_t offset, uint16_t value)
Definition write.c:20