xref: /openbmc/qemu/hw/usb/u2f-emulated.c (revision ae420c95)
1a983b113SCésar Belley /*
2a983b113SCésar Belley  * U2F USB Emulated device.
3a983b113SCésar Belley  *
4a983b113SCésar Belley  * Copyright (c) 2020 César Belley <cesar.belley@lse.epita.fr>
5a983b113SCésar Belley  * Written by César Belley <cesar.belley@lse.epita.fr>
6a983b113SCésar Belley  *
7a983b113SCésar Belley  * Permission is hereby granted, free of charge, to any person obtaining a copy
8a983b113SCésar Belley  * of this software and associated documentation files (the "Software"), to deal
9a983b113SCésar Belley  * in the Software without restriction, including without limitation the rights
10a983b113SCésar Belley  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11a983b113SCésar Belley  * copies of the Software, and to permit persons to whom the Software is
12a983b113SCésar Belley  * furnished to do so, subject to the following conditions:
13a983b113SCésar Belley  *
14a983b113SCésar Belley  * The above copyright notice and this permission notice shall be included in
15a983b113SCésar Belley  * all copies or substantial portions of the Software.
16a983b113SCésar Belley  *
17a983b113SCésar Belley  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18a983b113SCésar Belley  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19a983b113SCésar Belley  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20a983b113SCésar Belley  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21a983b113SCésar Belley  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22a983b113SCésar Belley  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23a983b113SCésar Belley  * THE SOFTWARE.
24a983b113SCésar Belley  */
25a983b113SCésar Belley 
26a983b113SCésar Belley #include "qemu/osdep.h"
27a983b113SCésar Belley #include "qemu/module.h"
28a983b113SCésar Belley #include "qemu/thread.h"
29a983b113SCésar Belley #include "qemu/main-loop.h"
30a983b113SCésar Belley #include "qapi/error.h"
31a983b113SCésar Belley #include "hw/usb.h"
32a983b113SCésar Belley #include "hw/qdev-properties.h"
33a983b113SCésar Belley 
34a983b113SCésar Belley #include <u2f-emu/u2f-emu.h>
35a983b113SCésar Belley 
36a983b113SCésar Belley #include "u2f.h"
37a983b113SCésar Belley 
38a983b113SCésar Belley /* Counter which sync with a file */
39a983b113SCésar Belley struct synced_counter {
40a983b113SCésar Belley     /* Emulated device counter */
41a983b113SCésar Belley     struct u2f_emu_vdev_counter vdev_counter;
42a983b113SCésar Belley 
43a983b113SCésar Belley     /* Private attributes */
44a983b113SCésar Belley     uint32_t value;
45a983b113SCésar Belley     FILE *fp;
46a983b113SCésar Belley };
47a983b113SCésar Belley 
counter_increment(struct u2f_emu_vdev_counter * vdev_counter)48a983b113SCésar Belley static void counter_increment(struct u2f_emu_vdev_counter *vdev_counter)
49a983b113SCésar Belley {
50a983b113SCésar Belley     struct synced_counter *counter = (struct synced_counter *)vdev_counter;
51a983b113SCésar Belley     ++counter->value;
52a983b113SCésar Belley 
53a983b113SCésar Belley     /* Write back */
54a983b113SCésar Belley     if (fseek(counter->fp, 0, SEEK_SET) == -1) {
55a983b113SCésar Belley         return;
56a983b113SCésar Belley     }
57a983b113SCésar Belley     fprintf(counter->fp, "%u\n", counter->value);
58a983b113SCésar Belley }
59a983b113SCésar Belley 
counter_read(struct u2f_emu_vdev_counter * vdev_counter)60a983b113SCésar Belley static uint32_t counter_read(struct u2f_emu_vdev_counter *vdev_counter)
61a983b113SCésar Belley {
62a983b113SCésar Belley     struct synced_counter *counter = (struct synced_counter *)vdev_counter;
63a983b113SCésar Belley     return counter->value;
64a983b113SCésar Belley }
65a983b113SCésar Belley 
66a983b113SCésar Belley typedef struct U2FEmulatedState U2FEmulatedState;
67a983b113SCésar Belley 
68a983b113SCésar Belley #define PENDING_OUT_NUM 32
69a983b113SCésar Belley 
70a983b113SCésar Belley struct U2FEmulatedState {
71a983b113SCésar Belley     U2FKeyState base;
72a983b113SCésar Belley 
73a983b113SCésar Belley     /* U2F virtual emulated device */
74a983b113SCésar Belley     u2f_emu_vdev *vdev;
75a983b113SCésar Belley     QemuMutex vdev_mutex;
76a983b113SCésar Belley 
77a983b113SCésar Belley     /* Properties */
78a983b113SCésar Belley     char *dir;
79a983b113SCésar Belley     char *cert;
80a983b113SCésar Belley     char *privkey;
81a983b113SCésar Belley     char *entropy;
82a983b113SCésar Belley     char *counter;
83a983b113SCésar Belley     struct synced_counter synced_counter;
84a983b113SCésar Belley 
85a983b113SCésar Belley     /* Pending packets received from the guest */
86a983b113SCésar Belley     uint8_t pending_out[PENDING_OUT_NUM][U2FHID_PACKET_SIZE];
87a983b113SCésar Belley     uint8_t pending_out_start;
88a983b113SCésar Belley     uint8_t pending_out_end;
89a983b113SCésar Belley     uint8_t pending_out_num;
90a983b113SCésar Belley     QemuMutex pending_out_mutex;
91a983b113SCésar Belley 
92a983b113SCésar Belley     /* Emulation thread and sync */
93a983b113SCésar Belley     QemuCond key_cond;
94a983b113SCésar Belley     QemuMutex key_mutex;
95a983b113SCésar Belley     QemuThread key_thread;
96a983b113SCésar Belley     bool stop_thread;
97a983b113SCésar Belley     EventNotifier notifier;
98a983b113SCésar Belley };
99a983b113SCésar Belley 
100a983b113SCésar Belley #define TYPE_U2F_EMULATED "u2f-emulated"
101a983b113SCésar Belley #define EMULATED_U2F_KEY(obj) \
102a983b113SCésar Belley     OBJECT_CHECK(U2FEmulatedState, (obj), TYPE_U2F_EMULATED)
103a983b113SCésar Belley 
u2f_emulated_reset(U2FEmulatedState * key)104a983b113SCésar Belley static void u2f_emulated_reset(U2FEmulatedState *key)
105a983b113SCésar Belley {
106a983b113SCésar Belley     key->pending_out_start = 0;
107a983b113SCésar Belley     key->pending_out_end = 0;
108a983b113SCésar Belley     key->pending_out_num = 0;
109a983b113SCésar Belley }
110a983b113SCésar Belley 
u2f_pending_out_add(U2FEmulatedState * key,const uint8_t packet[U2FHID_PACKET_SIZE])111a983b113SCésar Belley static void u2f_pending_out_add(U2FEmulatedState *key,
112a983b113SCésar Belley                                 const uint8_t packet[U2FHID_PACKET_SIZE])
113a983b113SCésar Belley {
114a983b113SCésar Belley     int index;
115a983b113SCésar Belley 
116a983b113SCésar Belley     if (key->pending_out_num >= PENDING_OUT_NUM) {
117a983b113SCésar Belley         return;
118a983b113SCésar Belley     }
119a983b113SCésar Belley 
120a983b113SCésar Belley     index = key->pending_out_end;
121a983b113SCésar Belley     key->pending_out_end = (index + 1) % PENDING_OUT_NUM;
122a983b113SCésar Belley     ++key->pending_out_num;
123a983b113SCésar Belley 
124a983b113SCésar Belley     memcpy(&key->pending_out[index], packet, U2FHID_PACKET_SIZE);
125a983b113SCésar Belley }
126a983b113SCésar Belley 
u2f_pending_out_get(U2FEmulatedState * key)127a983b113SCésar Belley static uint8_t *u2f_pending_out_get(U2FEmulatedState *key)
128a983b113SCésar Belley {
129a983b113SCésar Belley     int index;
130a983b113SCésar Belley 
131a983b113SCésar Belley     if (key->pending_out_num == 0) {
132a983b113SCésar Belley         return NULL;
133a983b113SCésar Belley     }
134a983b113SCésar Belley 
135a983b113SCésar Belley     index  = key->pending_out_start;
136a983b113SCésar Belley     key->pending_out_start = (index + 1) % PENDING_OUT_NUM;
137a983b113SCésar Belley     --key->pending_out_num;
138a983b113SCésar Belley 
139a983b113SCésar Belley     return key->pending_out[index];
140a983b113SCésar Belley }
141a983b113SCésar Belley 
u2f_emulated_recv_from_guest(U2FKeyState * base,const uint8_t packet[U2FHID_PACKET_SIZE])142a983b113SCésar Belley static void u2f_emulated_recv_from_guest(U2FKeyState *base,
143a983b113SCésar Belley                                     const uint8_t packet[U2FHID_PACKET_SIZE])
144a983b113SCésar Belley {
145a983b113SCésar Belley     U2FEmulatedState *key = EMULATED_U2F_KEY(base);
146a983b113SCésar Belley 
147a983b113SCésar Belley     qemu_mutex_lock(&key->pending_out_mutex);
148a983b113SCésar Belley     u2f_pending_out_add(key, packet);
149a983b113SCésar Belley     qemu_mutex_unlock(&key->pending_out_mutex);
150a983b113SCésar Belley 
151a983b113SCésar Belley     qemu_mutex_lock(&key->key_mutex);
152a983b113SCésar Belley     qemu_cond_signal(&key->key_cond);
153a983b113SCésar Belley     qemu_mutex_unlock(&key->key_mutex);
154a983b113SCésar Belley }
155a983b113SCésar Belley 
u2f_emulated_thread(void * arg)156a983b113SCésar Belley static void *u2f_emulated_thread(void* arg)
157a983b113SCésar Belley {
158a983b113SCésar Belley     U2FEmulatedState *key = arg;
159a983b113SCésar Belley     uint8_t packet[U2FHID_PACKET_SIZE];
160a983b113SCésar Belley     uint8_t *packet_out = NULL;
161a983b113SCésar Belley 
162a983b113SCésar Belley 
163a983b113SCésar Belley     while (true) {
164a983b113SCésar Belley         /* Wait signal */
165a983b113SCésar Belley         qemu_mutex_lock(&key->key_mutex);
166a983b113SCésar Belley         qemu_cond_wait(&key->key_cond, &key->key_mutex);
167a983b113SCésar Belley         qemu_mutex_unlock(&key->key_mutex);
168a983b113SCésar Belley 
169a983b113SCésar Belley         /* Exit thread check */
170a983b113SCésar Belley         if (key->stop_thread) {
171a983b113SCésar Belley             key->stop_thread = false;
172a983b113SCésar Belley             break;
173a983b113SCésar Belley         }
174a983b113SCésar Belley 
175a983b113SCésar Belley         qemu_mutex_lock(&key->pending_out_mutex);
176a983b113SCésar Belley         packet_out = u2f_pending_out_get(key);
177a983b113SCésar Belley         if (packet_out == NULL) {
178a983b113SCésar Belley             qemu_mutex_unlock(&key->pending_out_mutex);
179a983b113SCésar Belley             continue;
180a983b113SCésar Belley         }
181a983b113SCésar Belley         memcpy(packet, packet_out, U2FHID_PACKET_SIZE);
182a983b113SCésar Belley         qemu_mutex_unlock(&key->pending_out_mutex);
183a983b113SCésar Belley 
184a983b113SCésar Belley         qemu_mutex_lock(&key->vdev_mutex);
185a983b113SCésar Belley         u2f_emu_vdev_send(key->vdev, U2F_EMU_USB, packet,
186a983b113SCésar Belley                           U2FHID_PACKET_SIZE);
187a983b113SCésar Belley 
188a983b113SCésar Belley         /* Notify response */
189a983b113SCésar Belley         if (u2f_emu_vdev_has_response(key->vdev, U2F_EMU_USB)) {
190a983b113SCésar Belley             event_notifier_set(&key->notifier);
191a983b113SCésar Belley         }
192a983b113SCésar Belley         qemu_mutex_unlock(&key->vdev_mutex);
193a983b113SCésar Belley     }
194a983b113SCésar Belley     return NULL;
195a983b113SCésar Belley }
196a983b113SCésar Belley 
u2f_emulated_read(const char * path,char * buffer,size_t buffer_len)197a983b113SCésar Belley static ssize_t u2f_emulated_read(const char *path, char *buffer,
198a983b113SCésar Belley                                  size_t buffer_len)
199a983b113SCésar Belley {
200a983b113SCésar Belley     int fd;
201a983b113SCésar Belley     ssize_t ret;
202a983b113SCésar Belley 
20326d56f48SGerd Hoffmann     fd = qemu_open_old(path, O_RDONLY);
204a983b113SCésar Belley     if (fd < 0) {
205a983b113SCésar Belley         return -1;
206a983b113SCésar Belley     }
207a983b113SCésar Belley 
208a983b113SCésar Belley     ret = read(fd, buffer, buffer_len);
209a983b113SCésar Belley     close(fd);
210a983b113SCésar Belley 
211a983b113SCésar Belley     return ret;
212a983b113SCésar Belley }
213a983b113SCésar Belley 
u2f_emulated_setup_counter(const char * path,struct synced_counter * counter)214a983b113SCésar Belley static bool u2f_emulated_setup_counter(const char *path,
215a983b113SCésar Belley                                        struct synced_counter *counter)
216a983b113SCésar Belley {
217a983b113SCésar Belley     int fd, ret;
218a983b113SCésar Belley     FILE *fp;
219a983b113SCésar Belley 
22026d56f48SGerd Hoffmann     fd = qemu_open_old(path, O_RDWR);
221a983b113SCésar Belley     if (fd < 0) {
222a983b113SCésar Belley         return false;
223a983b113SCésar Belley     }
224a983b113SCésar Belley     fp = fdopen(fd, "r+");
225a983b113SCésar Belley     if (fp == NULL) {
226a983b113SCésar Belley         close(fd);
227a983b113SCésar Belley         return false;
228a983b113SCésar Belley     }
229a983b113SCésar Belley     ret = fscanf(fp, "%u", &counter->value);
230a983b113SCésar Belley     if (ret == EOF) {
231a983b113SCésar Belley         fclose(fp);
232a983b113SCésar Belley         return false;
233a983b113SCésar Belley     }
234a983b113SCésar Belley     counter->fp = fp;
235a983b113SCésar Belley     counter->vdev_counter.counter_increment = counter_increment;
236a983b113SCésar Belley     counter->vdev_counter.counter_read = counter_read;
237a983b113SCésar Belley 
238a983b113SCésar Belley     return true;
239a983b113SCésar Belley }
240a983b113SCésar Belley 
u2f_emulated_setup_vdev_manualy(U2FEmulatedState * key)241a983b113SCésar Belley static u2f_emu_rc u2f_emulated_setup_vdev_manualy(U2FEmulatedState *key)
242a983b113SCésar Belley {
243a983b113SCésar Belley     ssize_t ret;
244a983b113SCésar Belley     char cert_pem[4096], privkey_pem[2048];
245a983b113SCésar Belley     struct u2f_emu_vdev_setup setup_info;
246a983b113SCésar Belley 
247a983b113SCésar Belley     /* Certificate */
248a983b113SCésar Belley     ret = u2f_emulated_read(key->cert, cert_pem, sizeof(cert_pem));
249a983b113SCésar Belley     if (ret < 0) {
250a983b113SCésar Belley         return -1;
251a983b113SCésar Belley     }
252a983b113SCésar Belley 
253a983b113SCésar Belley     /* Private key */
254a983b113SCésar Belley     ret = u2f_emulated_read(key->privkey, privkey_pem, sizeof(privkey_pem));
255a983b113SCésar Belley     if (ret < 0) {
256a983b113SCésar Belley         return -1;
257a983b113SCésar Belley     }
258a983b113SCésar Belley 
259a983b113SCésar Belley     /* Entropy */
260a983b113SCésar Belley     ret = u2f_emulated_read(key->entropy, (char *)&setup_info.entropy,
261a983b113SCésar Belley                             sizeof(setup_info.entropy));
262a983b113SCésar Belley     if (ret < 0) {
263a983b113SCésar Belley         return -1;
264a983b113SCésar Belley     }
265a983b113SCésar Belley 
266a983b113SCésar Belley     /* Counter */
267a983b113SCésar Belley     if (!u2f_emulated_setup_counter(key->counter, &key->synced_counter)) {
268a983b113SCésar Belley         return -1;
269a983b113SCésar Belley     }
270a983b113SCésar Belley 
271a983b113SCésar Belley     /* Setup */
272a983b113SCésar Belley     setup_info.certificate = cert_pem;
273a983b113SCésar Belley     setup_info.private_key = privkey_pem;
274a983b113SCésar Belley     setup_info.counter = (struct u2f_emu_vdev_counter *)&key->synced_counter;
275a983b113SCésar Belley 
276a983b113SCésar Belley     return u2f_emu_vdev_new(&key->vdev, &setup_info);
277a983b113SCésar Belley }
278a983b113SCésar Belley 
u2f_emulated_event_handler(EventNotifier * notifier)279a983b113SCésar Belley static void u2f_emulated_event_handler(EventNotifier *notifier)
280a983b113SCésar Belley {
281a983b113SCésar Belley     U2FEmulatedState *key = container_of(notifier, U2FEmulatedState, notifier);
282a983b113SCésar Belley     size_t packet_size;
283a983b113SCésar Belley     uint8_t *packet_in = NULL;
284a983b113SCésar Belley 
285a983b113SCésar Belley     event_notifier_test_and_clear(&key->notifier);
286a983b113SCésar Belley     qemu_mutex_lock(&key->vdev_mutex);
287a983b113SCésar Belley     while (u2f_emu_vdev_has_response(key->vdev, U2F_EMU_USB)) {
288a983b113SCésar Belley         packet_size = u2f_emu_vdev_get_response(key->vdev, U2F_EMU_USB,
289a983b113SCésar Belley                                                 &packet_in);
290a983b113SCésar Belley         if (packet_size == U2FHID_PACKET_SIZE) {
291a983b113SCésar Belley             u2f_send_to_guest(&key->base, packet_in);
292a983b113SCésar Belley         }
293a983b113SCésar Belley         u2f_emu_vdev_free_response(packet_in);
294a983b113SCésar Belley     }
295a983b113SCésar Belley     qemu_mutex_unlock(&key->vdev_mutex);
296a983b113SCésar Belley }
297a983b113SCésar Belley 
u2f_emulated_realize(U2FKeyState * base,Error ** errp)298a983b113SCésar Belley static void u2f_emulated_realize(U2FKeyState *base, Error **errp)
299a983b113SCésar Belley {
300a983b113SCésar Belley     U2FEmulatedState *key = EMULATED_U2F_KEY(base);
301a983b113SCésar Belley     u2f_emu_rc rc;
302a983b113SCésar Belley 
303a983b113SCésar Belley     if (key->cert != NULL || key->privkey != NULL || key->entropy != NULL
304a983b113SCésar Belley         || key->counter != NULL) {
305a983b113SCésar Belley         if (key->cert != NULL && key->privkey != NULL
306a983b113SCésar Belley             && key->entropy != NULL && key->counter != NULL) {
307a983b113SCésar Belley             rc = u2f_emulated_setup_vdev_manualy(key);
308a983b113SCésar Belley         } else {
309a983b113SCésar Belley             error_setg(errp, "%s: cert, priv, entropy and counter "
310*ae420c95SCai Huoqing                        "parameters must be provided to manually configure "
311a983b113SCésar Belley                        "the emulated device", TYPE_U2F_EMULATED);
312a983b113SCésar Belley             return;
313a983b113SCésar Belley         }
314a983b113SCésar Belley     } else if (key->dir != NULL) {
315a983b113SCésar Belley         rc = u2f_emu_vdev_new_from_dir(&key->vdev, key->dir);
316a983b113SCésar Belley     } else {
317a983b113SCésar Belley         rc = u2f_emu_vdev_new_ephemeral(&key->vdev);
318a983b113SCésar Belley     }
319a983b113SCésar Belley 
320a983b113SCésar Belley     if (rc != U2F_EMU_OK) {
321a983b113SCésar Belley         error_setg(errp, "%s: Failed to setup the key", TYPE_U2F_EMULATED);
322a983b113SCésar Belley         return;
323a983b113SCésar Belley     }
324a983b113SCésar Belley 
325a983b113SCésar Belley     if (event_notifier_init(&key->notifier, false) < 0) {
326a983b113SCésar Belley         error_setg(errp, "%s: Failed to initialize notifier",
327a983b113SCésar Belley                    TYPE_U2F_EMULATED);
328a983b113SCésar Belley         return;
329a983b113SCésar Belley     }
330a983b113SCésar Belley     /* Notifier */
331a983b113SCésar Belley     event_notifier_set_handler(&key->notifier, u2f_emulated_event_handler);
332a983b113SCésar Belley 
333a983b113SCésar Belley     /* Synchronization */
334a983b113SCésar Belley     qemu_cond_init(&key->key_cond);
335a983b113SCésar Belley     qemu_mutex_init(&key->vdev_mutex);
336a983b113SCésar Belley     qemu_mutex_init(&key->pending_out_mutex);
337a983b113SCésar Belley     qemu_mutex_init(&key->key_mutex);
338a983b113SCésar Belley     u2f_emulated_reset(key);
339a983b113SCésar Belley 
340a983b113SCésar Belley     /* Thread */
341a983b113SCésar Belley     key->stop_thread = false;
342a983b113SCésar Belley     qemu_thread_create(&key->key_thread, "u2f-key", u2f_emulated_thread,
343a983b113SCésar Belley                        key, QEMU_THREAD_JOINABLE);
344a983b113SCésar Belley }
345a983b113SCésar Belley 
u2f_emulated_unrealize(U2FKeyState * base)346a983b113SCésar Belley static void u2f_emulated_unrealize(U2FKeyState *base)
347a983b113SCésar Belley {
348a983b113SCésar Belley     U2FEmulatedState *key = EMULATED_U2F_KEY(base);
349a983b113SCésar Belley 
350a983b113SCésar Belley     /* Thread */
351a983b113SCésar Belley     key->stop_thread = true;
352a983b113SCésar Belley     qemu_cond_signal(&key->key_cond);
353a983b113SCésar Belley     qemu_thread_join(&key->key_thread);
354a983b113SCésar Belley 
355a983b113SCésar Belley     /* Notifier */
356a983b113SCésar Belley     event_notifier_set_handler(&key->notifier, NULL);
357a983b113SCésar Belley     event_notifier_cleanup(&key->notifier);
358a983b113SCésar Belley 
359a983b113SCésar Belley     /* Synchronization */
360a983b113SCésar Belley     qemu_cond_destroy(&key->key_cond);
361a983b113SCésar Belley     qemu_mutex_destroy(&key->vdev_mutex);
362a983b113SCésar Belley     qemu_mutex_destroy(&key->key_mutex);
363a983b113SCésar Belley     qemu_mutex_destroy(&key->pending_out_mutex);
364a983b113SCésar Belley 
365a983b113SCésar Belley     /* Vdev */
366a983b113SCésar Belley     u2f_emu_vdev_free(key->vdev);
367a983b113SCésar Belley     if (key->synced_counter.fp != NULL) {
368a983b113SCésar Belley         fclose(key->synced_counter.fp);
369a983b113SCésar Belley     }
370a983b113SCésar Belley }
371a983b113SCésar Belley 
372a983b113SCésar Belley static Property u2f_emulated_properties[] = {
373a983b113SCésar Belley     DEFINE_PROP_STRING("dir", U2FEmulatedState, dir),
374a983b113SCésar Belley     DEFINE_PROP_STRING("cert", U2FEmulatedState, cert),
375a983b113SCésar Belley     DEFINE_PROP_STRING("privkey", U2FEmulatedState, privkey),
376a983b113SCésar Belley     DEFINE_PROP_STRING("entropy", U2FEmulatedState, entropy),
377a983b113SCésar Belley     DEFINE_PROP_STRING("counter", U2FEmulatedState, counter),
378a983b113SCésar Belley     DEFINE_PROP_END_OF_LIST(),
379a983b113SCésar Belley };
380a983b113SCésar Belley 
u2f_emulated_class_init(ObjectClass * klass,void * data)381a983b113SCésar Belley static void u2f_emulated_class_init(ObjectClass *klass, void *data)
382a983b113SCésar Belley {
383a983b113SCésar Belley     DeviceClass *dc = DEVICE_CLASS(klass);
384a983b113SCésar Belley     U2FKeyClass *kc = U2F_KEY_CLASS(klass);
385a983b113SCésar Belley 
386a983b113SCésar Belley     kc->realize = u2f_emulated_realize;
387a983b113SCésar Belley     kc->unrealize = u2f_emulated_unrealize;
388a983b113SCésar Belley     kc->recv_from_guest = u2f_emulated_recv_from_guest;
389a983b113SCésar Belley     dc->desc = "QEMU U2F emulated key";
390a983b113SCésar Belley     device_class_set_props(dc, u2f_emulated_properties);
391a983b113SCésar Belley }
392a983b113SCésar Belley 
393a983b113SCésar Belley static const TypeInfo u2f_key_emulated_info = {
394a983b113SCésar Belley     .name = TYPE_U2F_EMULATED,
395a983b113SCésar Belley     .parent = TYPE_U2F_KEY,
396a983b113SCésar Belley     .instance_size = sizeof(U2FEmulatedState),
397a983b113SCésar Belley     .class_init = u2f_emulated_class_init
398a983b113SCésar Belley };
399a983b113SCésar Belley 
u2f_key_emulated_register_types(void)400a983b113SCésar Belley static void u2f_key_emulated_register_types(void)
401a983b113SCésar Belley {
402a983b113SCésar Belley     type_register_static(&u2f_key_emulated_info);
403a983b113SCésar Belley }
404a983b113SCésar Belley 
405a983b113SCésar Belley type_init(u2f_key_emulated_register_types)
406