Embedded SDK
Embedded SDK
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 
37 uint8_t G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
38 
39 #ifdef HAVE_NFC_READER
40 struct nfc_reader_context G_io_reader_ctx;
41 #endif
42 
46 static uint32_t G_output_len = 0;
47 
51 static io_state_e G_io_state = READY;
52 
53 #ifdef HAVE_BAGL
54 WEAK 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 
136 WEAK void io_init()
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 
166 WEAK 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  swap_finalize_exchange_sign_transaction(sw == SW_OK);
200  }
201  else {
202  PRINTF("Unrecoverable\n");
203  os_sched_exit(-1);
204  }
205  }
206 #endif // HAVE_SWAP
207 
208  switch (G_io_state) {
209  case READY:
210  ret = -1;
211  break;
212  case RECEIVED:
213 #ifdef STANDARD_APP_SYNC_RAPDU
214  // Send synchronously the APDU response.
215  // This is needed to send the response before displaying synchronous
216  // status message on the screen.
217  // This is not always done to spare the RAM (stack) on LNS.
218  __attribute__((fallthrough));
219 #else
220  G_io_state = READY;
221  ret = 0;
222  break;
223 #endif
224  case WAITING:
225  ret = io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, G_output_len);
226  G_output_len = 0;
227  G_io_state = READY;
228  break;
229  }
230 
231  return ret;
232 }
233 
234 #ifdef STANDARD_APP_SYNC_RAPDU
235 WEAK bool io_recv_and_process_event(void)
236 {
237  int apdu_state = G_io_app.apdu_state;
238 
239  os_io_seph_recv_and_process(0);
240 
241  // If an APDU was received in previous os_io_seph_recv_and_process call and
242  // is waiting to be processed, return true
243  if (apdu_state == APDU_IDLE && G_io_app.apdu_state != APDU_IDLE) {
244  return true;
245  }
246 
247  return false;
248 }
249 #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:69
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
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