7 #include <asm/byteorder.h>
9 #include <talloc/talloc.h>
10 #include <list/list.h>
13 #include "pb-protocol.h"
18 * 4-byte action, determines the remaining message content
19 * 4-byte total payload len
20 * - not including action and payload len header
22 * action = 0x1: device add message
26 * 4-byte len, description
27 * 4-byte len, icon_file
33 * 4-byte len, description
34 * 4-byte len, icon_file
35 * 4-byte len, boot_image_file
36 * 4-byte len, initrd_file
37 * 4-byte len, dtb_file
38 * 4-byte len, boot_args
40 * action = 0x2: device remove message
46 * 4-byte len, boot option id
47 * 4-byte len, boot_image_file
48 * 4-byte len, initrd_file
49 * 4-byte len, dtb_file
50 * 4-byte len, boot_args
54 void pb_protocol_dump_device(const struct device *dev, const char *text,
57 struct boot_option *opt;
59 fprintf(stream, "%snew dev:\n", text);
60 fprintf(stream, "%s\tid: %s\n", text, dev->id);
61 fprintf(stream, "%s\tname: %s\n", text, dev->name);
62 fprintf(stream, "%s\tdesc: %s\n", text, dev->description);
63 fprintf(stream, "%s\ticon: %s\n", text, dev->icon_file);
64 fprintf(stream, "%s\tboot options:\n", text);
65 list_for_each_entry(&dev->boot_options, opt, list) {
66 fprintf(stream, "%s\t\tid: %s\n", text, opt->id);
67 fprintf(stream, "%s\t\tname: %s\n", text, opt->name);
68 fprintf(stream, "%s\t\tdesc: %s\n", text, opt->description);
69 fprintf(stream, "%s\t\ticon: %s\n", text, opt->icon_file);
70 fprintf(stream, "%s\t\tboot: %s\n", text, opt->boot_image_file);
71 fprintf(stream, "%s\t\tinit: %s\n", text, opt->initrd_file);
72 fprintf(stream, "%s\t\tdtb: %s\n", text, opt->dtb_file);
73 fprintf(stream, "%s\t\targs: %s\n", text, opt->boot_args);
77 int pb_protocol_device_cmp(const struct device *a, const struct device *b)
79 return !strcmp(a->id, b->id);
82 int pb_protocol_boot_option_cmp(const struct boot_option *a,
83 const struct boot_option *b)
85 return !strcmp(a->id, b->id);
88 /* Write a string into the buffer, starting at pos.
90 * Returns the total length used for the write, including length header.
92 int pb_protocol_serialise_string(char *pos, const char *str)
99 *(uint32_t *)pos = __cpu_to_be32(len);
100 pos += sizeof(uint32_t);
102 memcpy(pos, str, len);
104 return len + sizeof(uint32_t);
107 /* Read a string from a buffer, allocating the new string as necessary.
109 * @param[in] ctx The talloc context to base the allocation on
110 * @param[in,out] pos Where to start reading
111 * @param[in,out] len The amount of data remaining in the buffer
112 * @param[out] str Pointer to resuling string
113 * @return zero on success, non-zero on failure
115 static int read_string(void *ctx, const char **pos, unsigned int *len,
118 uint32_t str_len, read_len;
120 if (*len < sizeof(uint32_t))
123 str_len = __be32_to_cpu(*(uint32_t *)(*pos));
124 read_len = sizeof(uint32_t);
126 if (read_len + str_len > *len)
132 *str = talloc_strndup(ctx, *pos + read_len, str_len);
136 /* all ok, update the caller's pointers */
143 char *pb_protocol_deserialise_string(void *ctx,
144 const struct pb_protocol_message *message)
150 len = message->payload_len;
151 buf = message->payload;
153 if (read_string(ctx, &buf, &len, &str))
159 static int optional_strlen(const char *str)
166 int pb_protocol_device_len(const struct device *dev)
168 return 4 + optional_strlen(dev->id) +
169 4 + optional_strlen(dev->name) +
170 4 + optional_strlen(dev->description) +
171 4 + optional_strlen(dev->icon_file);
174 int pb_protocol_boot_option_len(const struct boot_option *opt)
177 return 4 + optional_strlen(opt->device_id) +
178 4 + optional_strlen(opt->id) +
179 4 + optional_strlen(opt->name) +
180 4 + optional_strlen(opt->description) +
181 4 + optional_strlen(opt->icon_file) +
182 4 + optional_strlen(opt->boot_image_file) +
183 4 + optional_strlen(opt->initrd_file) +
184 4 + optional_strlen(opt->dtb_file) +
185 4 + optional_strlen(opt->boot_args) +
186 sizeof(opt->is_default);
189 int pb_protocol_boot_len(const struct boot_command *boot)
191 return 4 + optional_strlen(boot->option_id) +
192 4 + optional_strlen(boot->boot_image_file) +
193 4 + optional_strlen(boot->initrd_file) +
194 4 + optional_strlen(boot->dtb_file) +
195 4 + optional_strlen(boot->boot_args);
198 int pb_protocol_boot_status_len(const struct boot_status *status)
201 4 + optional_strlen(status->message) +
202 4 + optional_strlen(status->detail) +
206 int pb_protocol_serialise_device(const struct device *dev,
207 char *buf, int buf_len)
211 pos += pb_protocol_serialise_string(pos, dev->id);
212 pos += pb_protocol_serialise_string(pos, dev->name);
213 pos += pb_protocol_serialise_string(pos, dev->description);
214 pos += pb_protocol_serialise_string(pos, dev->icon_file);
216 assert(pos <= buf + buf_len);
222 int pb_protocol_serialise_boot_option(const struct boot_option *opt,
223 char *buf, int buf_len)
227 pos += pb_protocol_serialise_string(pos, opt->device_id);
228 pos += pb_protocol_serialise_string(pos, opt->id);
229 pos += pb_protocol_serialise_string(pos, opt->name);
230 pos += pb_protocol_serialise_string(pos, opt->description);
231 pos += pb_protocol_serialise_string(pos, opt->icon_file);
232 pos += pb_protocol_serialise_string(pos, opt->boot_image_file);
233 pos += pb_protocol_serialise_string(pos, opt->initrd_file);
234 pos += pb_protocol_serialise_string(pos, opt->dtb_file);
235 pos += pb_protocol_serialise_string(pos, opt->boot_args);
237 *(bool *)pos = opt->is_default;
240 assert(pos <= buf + buf_len);
246 int pb_protocol_serialise_boot_command(const struct boot_command *boot,
247 char *buf, int buf_len)
251 pos += pb_protocol_serialise_string(pos, boot->option_id);
252 pos += pb_protocol_serialise_string(pos, boot->boot_image_file);
253 pos += pb_protocol_serialise_string(pos, boot->initrd_file);
254 pos += pb_protocol_serialise_string(pos, boot->dtb_file);
255 pos += pb_protocol_serialise_string(pos, boot->boot_args);
257 assert(pos <= buf + buf_len);
263 int pb_protocol_serialise_boot_status(const struct boot_status *status,
264 char *buf, int buf_len)
268 *(uint32_t *)pos = __cpu_to_be32(status->type);
269 pos += sizeof(uint32_t);
271 pos += pb_protocol_serialise_string(pos, status->message);
272 pos += pb_protocol_serialise_string(pos, status->detail);
274 *(uint32_t *)pos = __cpu_to_be32(status->type);
275 pos += sizeof(uint32_t);
277 assert(pos <= buf + buf_len);
283 int pb_protocol_write_message(int fd, struct pb_protocol_message *message)
288 total_len = sizeof(*message) + message->payload_len;
290 message->payload_len = __cpu_to_be32(message->payload_len);
291 message->action = __cpu_to_be32(message->action);
293 for (pos = (void *)message; total_len;) {
294 rc = write(fd, pos, total_len);
303 talloc_free(message);
308 pb_log("%s: failed: %s\n", __func__, strerror(errno));
312 struct pb_protocol_message *pb_protocol_create_message(void *ctx,
313 enum pb_protocol_action action, int payload_len)
315 struct pb_protocol_message *message;
317 if (payload_len > PB_PROTOCOL_MAX_PAYLOAD_SIZE) {
318 pb_log("%s: payload too big %u/%u\n", __func__, payload_len,
319 PB_PROTOCOL_MAX_PAYLOAD_SIZE);
323 message = talloc_size(ctx, sizeof(*message) + payload_len);
325 /* we convert these to big-endian in write_message() */
326 message->action = action;
327 message->payload_len = payload_len;
333 struct pb_protocol_message *pb_protocol_read_message(void *ctx, int fd)
335 struct pb_protocol_message *message, m;
339 /* use the stack for the initial 8-byte read */
341 rc = read(fd, &m, sizeof(m));
345 m.payload_len = __be32_to_cpu(m.payload_len);
346 m.action = __be32_to_cpu(m.action);
348 if (m.payload_len > PB_PROTOCOL_MAX_PAYLOAD_SIZE) {
349 pb_log("%s: payload too big %u/%u\n", __func__, m.payload_len,
350 PB_PROTOCOL_MAX_PAYLOAD_SIZE);
354 message = talloc_size(ctx, sizeof(m) + m.payload_len);
355 memcpy(message, &m, sizeof(m));
357 for (len = 0; len < m.payload_len;) {
358 rc = read(fd, message->payload + len, m.payload_len - len);
361 talloc_free(message);
362 pb_log("%s: failed (%u): %s\n", __func__, len,
374 int pb_protocol_deserialise_device(struct device *dev,
375 const struct pb_protocol_message *message)
381 len = message->payload_len;
382 pos = message->payload;
384 if (read_string(dev, &pos, &len, &dev->id))
387 if (read_string(dev, &pos, &len, &dev->name))
390 if (read_string(dev, &pos, &len, &dev->description))
393 if (read_string(dev, &pos, &len, &dev->icon_file))
402 int pb_protocol_deserialise_boot_option(struct boot_option *opt,
403 const struct pb_protocol_message *message)
409 len = message->payload_len;
410 pos = message->payload;
412 if (read_string(opt, &pos, &len, &opt->device_id))
415 if (read_string(opt, &pos, &len, &opt->id))
418 if (read_string(opt, &pos, &len, &opt->name))
421 if (read_string(opt, &pos, &len, &opt->description))
424 if (read_string(opt, &pos, &len, &opt->icon_file))
427 if (read_string(opt, &pos, &len, &opt->boot_image_file))
430 if (read_string(opt, &pos, &len, &opt->initrd_file))
433 if (read_string(opt, &pos, &len, &opt->dtb_file))
436 if (read_string(opt, &pos, &len, &opt->boot_args))
439 if (len < sizeof(bool))
441 opt->is_default = *(bool *)(pos);
449 int pb_protocol_deserialise_boot_command(struct boot_command *cmd,
450 const struct pb_protocol_message *message)
456 len = message->payload_len;
457 pos = message->payload;
459 if (read_string(cmd, &pos, &len, &cmd->option_id))
462 if (read_string(cmd, &pos, &len, &cmd->boot_image_file))
465 if (read_string(cmd, &pos, &len, &cmd->initrd_file))
468 if (read_string(cmd, &pos, &len, &cmd->dtb_file))
471 if (read_string(cmd, &pos, &len, &cmd->boot_args))
480 int pb_protocol_deserialise_boot_status(struct boot_status *status,
481 const struct pb_protocol_message *message)
487 len = message->payload_len;
488 pos = message->payload;
490 /* first up, the type enum... */
491 if (len < sizeof(uint32_t))
494 status->type = __be32_to_cpu(*(uint32_t *)(pos));
496 switch (status->type) {
497 case BOOT_STATUS_ERROR:
498 case BOOT_STATUS_INFO:
504 pos += sizeof(uint32_t);
505 len -= sizeof(uint32_t);
507 /* message and detail strings */
508 if (read_string(status, &pos, &len, &status->message))
511 if (read_string(status, &pos, &len, &status->detail))
514 /* and finally, progress */
515 if (len < sizeof(uint32_t))
518 status->progress = __be32_to_cpu(*(uint32_t *)(pos));
521 if (status->progress > 100)
522 status->progress = 100;