root / backends / rng-egd.c @ feature-archipelago
History | View | Annotate | Download (5.2 kB)
1 | 1da2738f | Anthony Liguori | /*
|
---|---|---|---|
2 | 1da2738f | Anthony Liguori | * QEMU Random Number Generator Backend
|
3 | 1da2738f | Anthony Liguori | *
|
4 | 1da2738f | Anthony Liguori | * Copyright IBM, Corp. 2012
|
5 | 1da2738f | Anthony Liguori | *
|
6 | 1da2738f | Anthony Liguori | * Authors:
|
7 | 1da2738f | Anthony Liguori | * Anthony Liguori <aliguori@us.ibm.com>
|
8 | 1da2738f | Anthony Liguori | *
|
9 | 1da2738f | Anthony Liguori | * This work is licensed under the terms of the GNU GPL, version 2 or later.
|
10 | 1da2738f | Anthony Liguori | * See the COPYING file in the top-level directory.
|
11 | 1da2738f | Anthony Liguori | */
|
12 | 1da2738f | Anthony Liguori | |
13 | dccfcd0e | Paolo Bonzini | #include "sysemu/rng.h" |
14 | dccfcd0e | Paolo Bonzini | #include "sysemu/char.h" |
15 | 7b1b5d19 | Paolo Bonzini | #include "qapi/qmp/qerror.h" |
16 | 1da2738f | Anthony Liguori | #include "hw/qdev.h" /* just for DEFINE_PROP_CHR */ |
17 | 1da2738f | Anthony Liguori | |
18 | 1da2738f | Anthony Liguori | #define TYPE_RNG_EGD "rng-egd" |
19 | 1da2738f | Anthony Liguori | #define RNG_EGD(obj) OBJECT_CHECK(RngEgd, (obj), TYPE_RNG_EGD)
|
20 | 1da2738f | Anthony Liguori | |
21 | 1da2738f | Anthony Liguori | typedef struct RngEgd |
22 | 1da2738f | Anthony Liguori | { |
23 | 1da2738f | Anthony Liguori | RngBackend parent; |
24 | 1da2738f | Anthony Liguori | |
25 | 1da2738f | Anthony Liguori | CharDriverState *chr; |
26 | 1da2738f | Anthony Liguori | char *chr_name;
|
27 | 1da2738f | Anthony Liguori | |
28 | 1da2738f | Anthony Liguori | GSList *requests; |
29 | 1da2738f | Anthony Liguori | } RngEgd; |
30 | 1da2738f | Anthony Liguori | |
31 | 1da2738f | Anthony Liguori | typedef struct RngRequest |
32 | 1da2738f | Anthony Liguori | { |
33 | 1da2738f | Anthony Liguori | EntropyReceiveFunc *receive_entropy; |
34 | 1da2738f | Anthony Liguori | uint8_t *data; |
35 | 1da2738f | Anthony Liguori | void *opaque;
|
36 | 1da2738f | Anthony Liguori | size_t offset; |
37 | 1da2738f | Anthony Liguori | size_t size; |
38 | 1da2738f | Anthony Liguori | } RngRequest; |
39 | 1da2738f | Anthony Liguori | |
40 | 1da2738f | Anthony Liguori | static void rng_egd_request_entropy(RngBackend *b, size_t size, |
41 | 1da2738f | Anthony Liguori | EntropyReceiveFunc *receive_entropy, |
42 | 1da2738f | Anthony Liguori | void *opaque)
|
43 | 1da2738f | Anthony Liguori | { |
44 | 1da2738f | Anthony Liguori | RngEgd *s = RNG_EGD(b); |
45 | 1da2738f | Anthony Liguori | RngRequest *req; |
46 | 1da2738f | Anthony Liguori | |
47 | 1da2738f | Anthony Liguori | req = g_malloc(sizeof(*req));
|
48 | 1da2738f | Anthony Liguori | |
49 | 1da2738f | Anthony Liguori | req->offset = 0;
|
50 | 1da2738f | Anthony Liguori | req->size = size; |
51 | 1da2738f | Anthony Liguori | req->receive_entropy = receive_entropy; |
52 | 1da2738f | Anthony Liguori | req->opaque = opaque; |
53 | 1da2738f | Anthony Liguori | req->data = g_malloc(req->size); |
54 | 1da2738f | Anthony Liguori | |
55 | 1da2738f | Anthony Liguori | while (size > 0) { |
56 | 1da2738f | Anthony Liguori | uint8_t header[2];
|
57 | 1da2738f | Anthony Liguori | uint8_t len = MIN(size, 255);
|
58 | 1da2738f | Anthony Liguori | |
59 | 1da2738f | Anthony Liguori | /* synchronous entropy request */
|
60 | 1da2738f | Anthony Liguori | header[0] = 0x02; |
61 | 1da2738f | Anthony Liguori | header[1] = len;
|
62 | 1da2738f | Anthony Liguori | |
63 | 1da2738f | Anthony Liguori | qemu_chr_fe_write(s->chr, header, sizeof(header));
|
64 | 1da2738f | Anthony Liguori | |
65 | 1da2738f | Anthony Liguori | size -= len; |
66 | 1da2738f | Anthony Liguori | } |
67 | 1da2738f | Anthony Liguori | |
68 | 1da2738f | Anthony Liguori | s->requests = g_slist_append(s->requests, req); |
69 | 1da2738f | Anthony Liguori | } |
70 | 1da2738f | Anthony Liguori | |
71 | 1da2738f | Anthony Liguori | static void rng_egd_free_request(RngRequest *req) |
72 | 1da2738f | Anthony Liguori | { |
73 | 1da2738f | Anthony Liguori | g_free(req->data); |
74 | 1da2738f | Anthony Liguori | g_free(req); |
75 | 1da2738f | Anthony Liguori | } |
76 | 1da2738f | Anthony Liguori | |
77 | 1da2738f | Anthony Liguori | static int rng_egd_chr_can_read(void *opaque) |
78 | 1da2738f | Anthony Liguori | { |
79 | 1da2738f | Anthony Liguori | RngEgd *s = RNG_EGD(opaque); |
80 | 1da2738f | Anthony Liguori | GSList *i; |
81 | 1da2738f | Anthony Liguori | int size = 0; |
82 | 1da2738f | Anthony Liguori | |
83 | 1da2738f | Anthony Liguori | for (i = s->requests; i; i = i->next) {
|
84 | 1da2738f | Anthony Liguori | RngRequest *req = i->data; |
85 | 1da2738f | Anthony Liguori | size += req->size - req->offset; |
86 | 1da2738f | Anthony Liguori | } |
87 | 1da2738f | Anthony Liguori | |
88 | 1da2738f | Anthony Liguori | return size;
|
89 | 1da2738f | Anthony Liguori | } |
90 | 1da2738f | Anthony Liguori | |
91 | 1da2738f | Anthony Liguori | static void rng_egd_chr_read(void *opaque, const uint8_t *buf, int size) |
92 | 1da2738f | Anthony Liguori | { |
93 | 1da2738f | Anthony Liguori | RngEgd *s = RNG_EGD(opaque); |
94 | 1eb1bd9e | Amos Kong | size_t buf_offset = 0;
|
95 | 1da2738f | Anthony Liguori | |
96 | 1da2738f | Anthony Liguori | while (size > 0 && s->requests) { |
97 | 1da2738f | Anthony Liguori | RngRequest *req = s->requests->data; |
98 | 1da2738f | Anthony Liguori | int len = MIN(size, req->size - req->offset);
|
99 | 1da2738f | Anthony Liguori | |
100 | 1eb1bd9e | Amos Kong | memcpy(req->data + req->offset, buf + buf_offset, len); |
101 | 1eb1bd9e | Amos Kong | buf_offset += len; |
102 | 1da2738f | Anthony Liguori | req->offset += len; |
103 | 1da2738f | Anthony Liguori | size -= len; |
104 | 1da2738f | Anthony Liguori | |
105 | 1da2738f | Anthony Liguori | if (req->offset == req->size) {
|
106 | 1da2738f | Anthony Liguori | s->requests = g_slist_remove_link(s->requests, s->requests); |
107 | 1da2738f | Anthony Liguori | |
108 | 1da2738f | Anthony Liguori | req->receive_entropy(req->opaque, req->data, req->size); |
109 | 1da2738f | Anthony Liguori | |
110 | 1da2738f | Anthony Liguori | rng_egd_free_request(req); |
111 | 1da2738f | Anthony Liguori | } |
112 | 1da2738f | Anthony Liguori | } |
113 | 1da2738f | Anthony Liguori | } |
114 | 1da2738f | Anthony Liguori | |
115 | 9cb535fe | Anthony Liguori | static void rng_egd_free_requests(RngEgd *s) |
116 | 9cb535fe | Anthony Liguori | { |
117 | 9cb535fe | Anthony Liguori | GSList *i; |
118 | 9cb535fe | Anthony Liguori | |
119 | 9cb535fe | Anthony Liguori | for (i = s->requests; i; i = i->next) {
|
120 | 9cb535fe | Anthony Liguori | rng_egd_free_request(i->data); |
121 | 9cb535fe | Anthony Liguori | } |
122 | 9cb535fe | Anthony Liguori | |
123 | 9cb535fe | Anthony Liguori | g_slist_free(s->requests); |
124 | 9cb535fe | Anthony Liguori | s->requests = NULL;
|
125 | 9cb535fe | Anthony Liguori | } |
126 | 9cb535fe | Anthony Liguori | |
127 | 1da2738f | Anthony Liguori | static void rng_egd_cancel_requests(RngBackend *b) |
128 | 1da2738f | Anthony Liguori | { |
129 | 1da2738f | Anthony Liguori | RngEgd *s = RNG_EGD(b); |
130 | 1da2738f | Anthony Liguori | |
131 | 1da2738f | Anthony Liguori | /* We simply delete the list of pending requests. If there is data in the
|
132 | 1da2738f | Anthony Liguori | * queue waiting to be read, this is okay, because there will always be
|
133 | 1da2738f | Anthony Liguori | * more data than we requested originally
|
134 | 1da2738f | Anthony Liguori | */
|
135 | 9cb535fe | Anthony Liguori | rng_egd_free_requests(s); |
136 | 1da2738f | Anthony Liguori | } |
137 | 1da2738f | Anthony Liguori | |
138 | 1da2738f | Anthony Liguori | static void rng_egd_opened(RngBackend *b, Error **errp) |
139 | 1da2738f | Anthony Liguori | { |
140 | 1da2738f | Anthony Liguori | RngEgd *s = RNG_EGD(b); |
141 | 1da2738f | Anthony Liguori | |
142 | 1da2738f | Anthony Liguori | if (s->chr_name == NULL) { |
143 | 1da2738f | Anthony Liguori | error_set(errp, QERR_INVALID_PARAMETER_VALUE, |
144 | 1da2738f | Anthony Liguori | "chardev", "a valid character device"); |
145 | 1da2738f | Anthony Liguori | return;
|
146 | 1da2738f | Anthony Liguori | } |
147 | 1da2738f | Anthony Liguori | |
148 | 1da2738f | Anthony Liguori | s->chr = qemu_chr_find(s->chr_name); |
149 | 1da2738f | Anthony Liguori | if (s->chr == NULL) { |
150 | 1da2738f | Anthony Liguori | error_set(errp, QERR_DEVICE_NOT_FOUND, s->chr_name); |
151 | 1da2738f | Anthony Liguori | return;
|
152 | 1da2738f | Anthony Liguori | } |
153 | 1da2738f | Anthony Liguori | |
154 | 456d6069 | Hans de Goede | if (qemu_chr_fe_claim(s->chr) != 0) { |
155 | 456d6069 | Hans de Goede | error_set(errp, QERR_DEVICE_IN_USE, s->chr_name); |
156 | 456d6069 | Hans de Goede | return;
|
157 | 456d6069 | Hans de Goede | } |
158 | 456d6069 | Hans de Goede | |
159 | 1da2738f | Anthony Liguori | /* FIXME we should resubmit pending requests when the CDS reconnects. */
|
160 | 1da2738f | Anthony Liguori | qemu_chr_add_handlers(s->chr, rng_egd_chr_can_read, rng_egd_chr_read, |
161 | 1da2738f | Anthony Liguori | NULL, s);
|
162 | 1da2738f | Anthony Liguori | } |
163 | 1da2738f | Anthony Liguori | |
164 | 1da2738f | Anthony Liguori | static void rng_egd_set_chardev(Object *obj, const char *value, Error **errp) |
165 | 1da2738f | Anthony Liguori | { |
166 | 1da2738f | Anthony Liguori | RngBackend *b = RNG_BACKEND(obj); |
167 | 1da2738f | Anthony Liguori | RngEgd *s = RNG_EGD(b); |
168 | 1da2738f | Anthony Liguori | |
169 | 1da2738f | Anthony Liguori | if (b->opened) {
|
170 | 1da2738f | Anthony Liguori | error_set(errp, QERR_PERMISSION_DENIED); |
171 | 1da2738f | Anthony Liguori | } else {
|
172 | 1da2738f | Anthony Liguori | s->chr_name = g_strdup(value); |
173 | 1da2738f | Anthony Liguori | } |
174 | 1da2738f | Anthony Liguori | } |
175 | 1da2738f | Anthony Liguori | |
176 | 1da2738f | Anthony Liguori | static char *rng_egd_get_chardev(Object *obj, Error **errp) |
177 | 1da2738f | Anthony Liguori | { |
178 | 1da2738f | Anthony Liguori | RngEgd *s = RNG_EGD(obj); |
179 | 1da2738f | Anthony Liguori | |
180 | 1da2738f | Anthony Liguori | if (s->chr && s->chr->label) {
|
181 | 1da2738f | Anthony Liguori | return g_strdup(s->chr->label);
|
182 | 1da2738f | Anthony Liguori | } |
183 | 1da2738f | Anthony Liguori | |
184 | 1da2738f | Anthony Liguori | return NULL; |
185 | 1da2738f | Anthony Liguori | } |
186 | 1da2738f | Anthony Liguori | |
187 | 1da2738f | Anthony Liguori | static void rng_egd_init(Object *obj) |
188 | 1da2738f | Anthony Liguori | { |
189 | 1da2738f | Anthony Liguori | object_property_add_str(obj, "chardev",
|
190 | 1da2738f | Anthony Liguori | rng_egd_get_chardev, rng_egd_set_chardev, |
191 | 1da2738f | Anthony Liguori | NULL);
|
192 | 1da2738f | Anthony Liguori | } |
193 | 1da2738f | Anthony Liguori | |
194 | 1da2738f | Anthony Liguori | static void rng_egd_finalize(Object *obj) |
195 | 1da2738f | Anthony Liguori | { |
196 | 1da2738f | Anthony Liguori | RngEgd *s = RNG_EGD(obj); |
197 | 1da2738f | Anthony Liguori | |
198 | 1da2738f | Anthony Liguori | if (s->chr) {
|
199 | 1da2738f | Anthony Liguori | qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL); |
200 | 456d6069 | Hans de Goede | qemu_chr_fe_release(s->chr); |
201 | 1da2738f | Anthony Liguori | } |
202 | 1da2738f | Anthony Liguori | |
203 | 1da2738f | Anthony Liguori | g_free(s->chr_name); |
204 | 1da2738f | Anthony Liguori | |
205 | 9cb535fe | Anthony Liguori | rng_egd_free_requests(s); |
206 | 1da2738f | Anthony Liguori | } |
207 | 1da2738f | Anthony Liguori | |
208 | 1da2738f | Anthony Liguori | static void rng_egd_class_init(ObjectClass *klass, void *data) |
209 | 1da2738f | Anthony Liguori | { |
210 | 1da2738f | Anthony Liguori | RngBackendClass *rbc = RNG_BACKEND_CLASS(klass); |
211 | 1da2738f | Anthony Liguori | |
212 | 1da2738f | Anthony Liguori | rbc->request_entropy = rng_egd_request_entropy; |
213 | 1da2738f | Anthony Liguori | rbc->cancel_requests = rng_egd_cancel_requests; |
214 | 1da2738f | Anthony Liguori | rbc->opened = rng_egd_opened; |
215 | 1da2738f | Anthony Liguori | } |
216 | 1da2738f | Anthony Liguori | |
217 | 8c43a6f0 | Andreas Färber | static const TypeInfo rng_egd_info = { |
218 | 1da2738f | Anthony Liguori | .name = TYPE_RNG_EGD, |
219 | 1da2738f | Anthony Liguori | .parent = TYPE_RNG_BACKEND, |
220 | 1da2738f | Anthony Liguori | .instance_size = sizeof(RngEgd),
|
221 | 1da2738f | Anthony Liguori | .class_init = rng_egd_class_init, |
222 | 1da2738f | Anthony Liguori | .instance_init = rng_egd_init, |
223 | 1da2738f | Anthony Liguori | .instance_finalize = rng_egd_finalize, |
224 | 1da2738f | Anthony Liguori | }; |
225 | 1da2738f | Anthony Liguori | |
226 | 1da2738f | Anthony Liguori | static void register_types(void) |
227 | 1da2738f | Anthony Liguori | { |
228 | 1da2738f | Anthony Liguori | type_register_static(&rng_egd_info); |
229 | 1da2738f | Anthony Liguori | } |
230 | 1da2738f | Anthony Liguori | |
231 | 1da2738f | Anthony Liguori | type_init(register_types); |