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 // TODO: Temporary workaround, at some point all status words should be defined by the SDK and
29 // removed from the application
30 #define SW_OK 0x9000
31 #define SW_WRONG_RESPONSE_LENGTH 0xB000
32 
33 uint8_t G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
34 
38 static uint32_t G_output_len = 0;
39 
43 static io_state_e G_io_state = READY;
44 
45 #ifdef HAVE_BAGL
46 WEAK void io_seproxyhal_display(const bagl_element_t *element)
47 {
49 }
50 #endif // HAVE_BAGL
51 
52 // This function can be used to declare a callback to SEPROXYHAL_TAG_TICKER_EVENT in the application
54 
56 {
57  (void) channel;
58 
59  switch (G_io_seproxyhal_spi_buffer[0]) {
60  case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT:
62  break;
63  case SEPROXYHAL_TAG_STATUS_EVENT:
64  if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID && //
65  !(U4BE(G_io_seproxyhal_spi_buffer, 3) & //
66  SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) {
67  THROW(EXCEPTION_IO_RESET);
68  }
69  __attribute__((fallthrough));
70  case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT:
71 #ifdef HAVE_BAGL
73 #endif // HAVE_BAGL
74 #ifdef HAVE_NBGL
76 #endif // HAVE_NBGL
77  break;
78 #ifdef HAVE_NBGL
79  case SEPROXYHAL_TAG_FINGER_EVENT:
81  break;
82 #endif // HAVE_NBGL
83  case SEPROXYHAL_TAG_TICKER_EVENT:
86  break;
87  default:
89  break;
90  }
91 
92  if (!io_seproxyhal_spi_is_status_sent()) {
93  io_seproxyhal_general_status();
94  }
95 
96  return 1;
97 }
98 
100 {
101  switch (channel & ~(IO_FLAGS)) {
102  case CHANNEL_KEYBOARD:
103  break;
104  case CHANNEL_SPI:
105  if (tx_len) {
106  io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len);
107 
108  if (channel & IO_RESET_AFTER_REPLIED) {
109  halt();
110  }
111 
112  return 0;
113  }
114  else {
115  return io_seproxyhal_spi_recv(G_io_apdu_buffer, sizeof(G_io_apdu_buffer), 0);
116  }
117  default:
118  THROW(INVALID_PARAMETER);
119  }
120 
121  return 0;
122 }
123 
124 WEAK void io_init()
125 {
126  // Reset length of APDU response
127  G_output_len = 0;
128  G_io_state = READY;
129 }
130 
132 {
133  int ret = -1;
134 
135  switch (G_io_state) {
136  case READY:
137  ret = io_exchange(CHANNEL_APDU | IO_CONTINUE_RX, G_output_len);
138  G_io_state = RECEIVED;
139  break;
140  case RECEIVED:
141  G_io_state = WAITING;
142  ret = io_exchange(CHANNEL_APDU | IO_ASYNCH_REPLY, G_output_len);
143  G_io_state = RECEIVED;
144  break;
145  case WAITING:
146  G_io_state = READY;
147  ret = -1;
148  break;
149  }
150 
151  return ret;
152 }
153 
154 WEAK int io_send_response_buffers(const buffer_t *rdatalist, size_t count, uint16_t sw)
155 {
156  int ret = -1;
157 
158  G_output_len = 0;
159  if (rdatalist && count > 0) {
160  for (size_t i = 0; i < count; i++) {
161  const buffer_t *rdata = &rdatalist[i];
162 
163  if (!buffer_copy(rdata,
164  G_io_apdu_buffer + G_output_len,
165  sizeof(G_io_apdu_buffer) - G_output_len - 2)) {
166  return io_send_sw(SW_WRONG_RESPONSE_LENGTH);
167  }
168  G_output_len += rdata->size - rdata->offset;
169  if (count > 1) {
170  PRINTF("<= FRAG (%u/%u) RData=%.*H\n", i + 1, count, rdata->size, rdata->ptr);
171  }
172  }
173  PRINTF("<= SW=%04X | RData=%.*H\n", sw, G_output_len, G_io_apdu_buffer);
174  }
175  else {
176  PRINTF("<= SW=%04X | RData=\n", sw);
177  }
178 
179  write_u16_be(G_io_apdu_buffer, G_output_len, sw);
180  G_output_len += 2;
181 
182 #ifdef HAVE_SWAP
183  // If we are in swap mode and have validated a TX, we send it and immediately quit
185  PRINTF("Swap answer is processed. Send it\n");
186  if (io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, G_output_len) == 0) {
187  swap_finalize_exchange_sign_transaction(sw == SW_OK);
188  }
189  else {
190  PRINTF("Unrecoverable\n");
191  os_sched_exit(-1);
192  }
193  }
194 #endif // HAVE_SWAP
195 
196  switch (G_io_state) {
197  case READY:
198  ret = -1;
199  break;
200  case RECEIVED:
201 #ifdef STANDARD_APP_SYNC_RAPDU
202  // Send synchronously the APDU response.
203  // This is needed to send the response before displaying synchronous
204  // status message on the screen.
205  // This is not always done to spare the RAM (stack) on LNS.
206  __attribute__((fallthrough));
207 #else
208  G_io_state = READY;
209  ret = 0;
210  break;
211 #endif
212  case WAITING:
213  ret = io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, G_output_len);
214  G_output_len = 0;
215  G_io_state = READY;
216  break;
217  }
218 
219  return ret;
220 }
221 
222 #ifdef STANDARD_APP_SYNC_RAPDU
223 WEAK bool io_recv_and_process_event(void)
224 {
225  int apdu_state = G_io_app.apdu_state;
226 
227  os_io_seph_recv_and_process(0);
228 
229  // If an APDU was received in previous os_io_seph_recv_and_process call and
230  // is waiting to be processed, return true
231  if (apdu_state == APDU_IDLE && G_io_app.apdu_state != APDU_IDLE) {
232  return true;
233  }
234 
235  return false;
236 }
237 #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:33
WEAK uint16_t io_exchange_al(uint8_t channel, uint16_t tx_len)
Definition: io.c:99
#define SW_WRONG_RESPONSE_LENGTH
Definition: io.c:31
#define SW_OK
Definition: io.c:30
WEAK int io_send_response_buffers(const buffer_t *rdatalist, size_t count, uint16_t sw)
Definition: io.c:154
WEAK void io_init()
Definition: io.c:124
WEAK uint8_t io_event(uint8_t channel)
Definition: io.c:55
WEAK int io_recv_command()
Definition: io.c:131
WEAK void app_ticker_event_callback(void)
Definition: io.c:53
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