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, boot_args
39 * action = 0x2: device remove message
45 * 4-byte len, boot option id
46 * 4-byte len, boot_image_file
47 * 4-byte len, initrd_file
48 * 4-byte len, boot_args
52 void pb_protocol_dump_device(const struct device *dev, const char *text,
55 struct boot_option *opt;
57 fprintf(stream, "%snew dev:\n", text);
58 fprintf(stream, "%s\tid: %s\n", text, dev->id);
59 fprintf(stream, "%s\tname: %s\n", text, dev->name);
60 fprintf(stream, "%s\tdesc: %s\n", text, dev->description);
61 fprintf(stream, "%s\ticon: %s\n", text, dev->icon_file);
62 fprintf(stream, "%s\tboot options:\n", text);
63 list_for_each_entry(&dev->boot_options, opt, list) {
64 fprintf(stream, "%s\t\tid: %s\n", text, opt->id);
65 fprintf(stream, "%s\t\tname: %s\n", text, opt->name);
66 fprintf(stream, "%s\t\tdesc: %s\n", text, opt->description);
67 fprintf(stream, "%s\t\ticon: %s\n", text, opt->icon_file);
68 fprintf(stream, "%s\t\tboot: %s\n", text, opt->boot_image_file);
69 fprintf(stream, "%s\t\tinit: %s\n", text, opt->initrd_file);
70 fprintf(stream, "%s\t\targs: %s\n", text, opt->boot_args);
74 int pb_protocol_device_cmp(const struct device *a, const struct device *b)
76 return !strcmp(a->id, b->id);
79 int pb_protocol_boot_option_cmp(const struct boot_option *a,
80 const struct boot_option *b)
82 return !strcmp(a->id, b->id);
85 /* Write a string into the buffer, starting at pos.
87 * Returns the total length used for the write, including length header.
89 int pb_protocol_serialise_string(char *pos, const char *str)
96 *(uint32_t *)pos = __cpu_to_be32(len);
97 pos += sizeof(uint32_t);
99 memcpy(pos, str, len);
101 return len + sizeof(uint32_t);
104 /* Read a string from a buffer, allocating the new string as necessary.
106 * @param[in] ctx The talloc context to base the allocation on
107 * @param[in,out] pos Where to start reading
108 * @param[in,out] len The amount of data remaining in the buffer
109 * @param[out] str Pointer to resuling string
110 * @return zero on success, non-zero on failure
112 static int read_string(void *ctx, const char **pos, unsigned int *len,
115 uint32_t str_len, read_len;
117 if (*len < sizeof(uint32_t))
120 str_len = __be32_to_cpu(*(uint32_t *)(*pos));
121 read_len = sizeof(uint32_t);
123 if (read_len + str_len > *len)
129 *str = talloc_strndup(ctx, *pos + read_len, str_len);
133 /* all ok, update the caller's pointers */
140 char *pb_protocol_deserialise_string(void *ctx,
141 const struct pb_protocol_message *message)
147 len = message->payload_len;
148 buf = message->payload;
150 if (read_string(ctx, &buf, &len, &str))
156 static int optional_strlen(const char *str)
163 int pb_protocol_device_len(const struct device *dev)
165 return 4 + optional_strlen(dev->id) +
166 4 + optional_strlen(dev->name) +
167 4 + optional_strlen(dev->description) +
168 4 + optional_strlen(dev->icon_file);
171 int pb_protocol_boot_option_len(const struct boot_option *opt)
174 return 4 + optional_strlen(opt->device_id) +
175 4 + optional_strlen(opt->id) +
176 4 + optional_strlen(opt->name) +
177 4 + optional_strlen(opt->description) +
178 4 + optional_strlen(opt->icon_file) +
179 4 + optional_strlen(opt->boot_image_file) +
180 4 + optional_strlen(opt->initrd_file) +
181 4 + optional_strlen(opt->boot_args) +
182 sizeof(opt->is_default);
185 int pb_protocol_boot_len(const struct boot_command *boot)
187 return 4 + optional_strlen(boot->option_id) +
188 4 + optional_strlen(boot->boot_image_file) +
189 4 + optional_strlen(boot->initrd_file) +
190 4 + optional_strlen(boot->boot_args);
193 int pb_protocol_boot_status_len(const struct boot_status *status)
196 4 + optional_strlen(status->message) +
197 4 + optional_strlen(status->detail) +
201 int pb_protocol_serialise_device(const struct device *dev,
202 char *buf, int buf_len)
206 pos += pb_protocol_serialise_string(pos, dev->id);
207 pos += pb_protocol_serialise_string(pos, dev->name);
208 pos += pb_protocol_serialise_string(pos, dev->description);
209 pos += pb_protocol_serialise_string(pos, dev->icon_file);
211 assert(pos <= buf + buf_len);
217 int pb_protocol_serialise_boot_option(const struct boot_option *opt,
218 char *buf, int buf_len)
222 pos += pb_protocol_serialise_string(pos, opt->device_id);
223 pos += pb_protocol_serialise_string(pos, opt->id);
224 pos += pb_protocol_serialise_string(pos, opt->name);
225 pos += pb_protocol_serialise_string(pos, opt->description);
226 pos += pb_protocol_serialise_string(pos, opt->icon_file);
227 pos += pb_protocol_serialise_string(pos, opt->boot_image_file);
228 pos += pb_protocol_serialise_string(pos, opt->initrd_file);
229 pos += pb_protocol_serialise_string(pos, opt->boot_args);
231 *(bool *)pos = opt->is_default;
234 assert(pos <= buf + buf_len);
240 int pb_protocol_serialise_boot_command(const struct boot_command *boot,
241 char *buf, int buf_len)
245 pos += pb_protocol_serialise_string(pos, boot->option_id);
246 pos += pb_protocol_serialise_string(pos, boot->boot_image_file);
247 pos += pb_protocol_serialise_string(pos, boot->initrd_file);
248 pos += pb_protocol_serialise_string(pos, boot->boot_args);
250 assert(pos <= buf + buf_len);
256 int pb_protocol_serialise_boot_status(const struct boot_status *status,
257 char *buf, int buf_len)
261 *(uint32_t *)pos = __cpu_to_be32(status->type);
262 pos += sizeof(uint32_t);
264 pos += pb_protocol_serialise_string(pos, status->message);
265 pos += pb_protocol_serialise_string(pos, status->detail);
267 *(uint32_t *)pos = __cpu_to_be32(status->type);
268 pos += sizeof(uint32_t);
270 assert(pos <= buf + buf_len);
276 int pb_protocol_write_message(int fd, struct pb_protocol_message *message)
281 total_len = sizeof(*message) + message->payload_len;
283 message->payload_len = __cpu_to_be32(message->payload_len);
284 message->action = __cpu_to_be32(message->action);
286 for (pos = (void *)message; total_len;) {
287 rc = write(fd, pos, total_len);
296 talloc_free(message);
301 pb_log("%s: failed: %s\n", __func__, strerror(errno));
305 struct pb_protocol_message *pb_protocol_create_message(void *ctx,
306 enum pb_protocol_action action, int payload_len)
308 struct pb_protocol_message *message;
310 if (payload_len > PB_PROTOCOL_MAX_PAYLOAD_SIZE) {
311 pb_log("%s: payload too big %u/%u\n", __func__, payload_len,
312 PB_PROTOCOL_MAX_PAYLOAD_SIZE);
316 message = talloc_size(ctx, sizeof(*message) + payload_len);
318 /* we convert these to big-endian in write_message() */
319 message->action = action;
320 message->payload_len = payload_len;
326 struct pb_protocol_message *pb_protocol_read_message(void *ctx, int fd)
328 struct pb_protocol_message *message, m;
332 /* use the stack for the initial 8-byte read */
334 rc = read(fd, &m, sizeof(m));
338 m.payload_len = __be32_to_cpu(m.payload_len);
339 m.action = __be32_to_cpu(m.action);
341 if (m.payload_len > PB_PROTOCOL_MAX_PAYLOAD_SIZE) {
342 pb_log("%s: payload too big %u/%u\n", __func__, m.payload_len,
343 PB_PROTOCOL_MAX_PAYLOAD_SIZE);
347 message = talloc_size(ctx, sizeof(m) + m.payload_len);
348 memcpy(message, &m, sizeof(m));
350 for (len = 0; len < m.payload_len;) {
351 rc = read(fd, message->payload + len, m.payload_len - len);
354 talloc_free(message);
355 pb_log("%s: failed (%u): %s\n", __func__, len,
367 int pb_protocol_deserialise_device(struct device *dev,
368 const struct pb_protocol_message *message)
374 len = message->payload_len;
375 pos = message->payload;
377 if (read_string(dev, &pos, &len, &dev->id))
380 if (read_string(dev, &pos, &len, &dev->name))
383 if (read_string(dev, &pos, &len, &dev->description))
386 if (read_string(dev, &pos, &len, &dev->icon_file))
395 int pb_protocol_deserialise_boot_option(struct boot_option *opt,
396 const struct pb_protocol_message *message)
402 len = message->payload_len;
403 pos = message->payload;
405 if (read_string(opt, &pos, &len, &opt->device_id))
408 if (read_string(opt, &pos, &len, &opt->id))
411 if (read_string(opt, &pos, &len, &opt->name))
414 if (read_string(opt, &pos, &len, &opt->description))
417 if (read_string(opt, &pos, &len, &opt->icon_file))
420 if (read_string(opt, &pos, &len, &opt->boot_image_file))
423 if (read_string(opt, &pos, &len, &opt->initrd_file))
426 if (read_string(opt, &pos, &len, &opt->boot_args))
429 if (len < sizeof(bool))
431 opt->is_default = *(bool *)(pos);
439 int pb_protocol_deserialise_boot_command(struct boot_command *cmd,
440 const struct pb_protocol_message *message)
446 len = message->payload_len;
447 pos = message->payload;
449 if (read_string(cmd, &pos, &len, &cmd->option_id))
452 if (read_string(cmd, &pos, &len, &cmd->boot_image_file))
455 if (read_string(cmd, &pos, &len, &cmd->initrd_file))
458 if (read_string(cmd, &pos, &len, &cmd->boot_args))
467 int pb_protocol_deserialise_boot_status(struct boot_status *status,
468 const struct pb_protocol_message *message)
474 len = message->payload_len;
475 pos = message->payload;
477 /* first up, the type enum... */
478 if (len < sizeof(uint32_t))
481 status->type = __be32_to_cpu(*(uint32_t *)(pos));
483 switch (status->type) {
484 case BOOT_STATUS_ERROR:
485 case BOOT_STATUS_INFO:
491 pos += sizeof(uint32_t);
492 len -= sizeof(uint32_t);
494 /* message and detail strings */
495 if (read_string(status, &pos, &len, &status->message))
498 if (read_string(status, &pos, &len, &status->detail))
501 /* and finally, progress */
502 if (len < sizeof(uint32_t))
505 status->progress = __be32_to_cpu(*(uint32_t *)(pos));
508 if (status->progress > 100)
509 status->progress = 100;