6 #include <asm/byteorder.h>
8 #include <talloc/talloc.h>
12 #include "pb-protocol.h"
17 * 4-byte action, determines the remaining message content
18 * 4-byte total payload len
19 * - not including action and payload len header
21 * action = 0x1: device add message
25 * 4-byte len, description
26 * 4-byte len, icon_file
32 * 4-byte len, description
33 * 4-byte len, icon_file
34 * 4-byte len, boot_image_file
35 * 4-byte len, initrd_file
36 * 4-byte len, boot_args
38 * action = 0x2: device remove message
43 void pb_protocol_dump_device(const struct device *dev, const char *text,
46 struct boot_option *opt;
48 fprintf(stream, "%snew dev:\n", text);
49 fprintf(stream, "%s\tid: %s\n", text, dev->id);
50 fprintf(stream, "%s\tname: %s\n", text, dev->name);
51 fprintf(stream, "%s\tdesc: %s\n", text, dev->description);
52 fprintf(stream, "%s\ticon: %s\n", text, dev->icon_file);
53 fprintf(stream, "%s\tboot options:\n", text);
54 list_for_each_entry(&dev->boot_options, opt, list) {
55 fprintf(stream, "%s\t\tid: %s\n", text, opt->id);
56 fprintf(stream, "%s\t\tname: %s\n", text, opt->name);
57 fprintf(stream, "%s\t\tdesc: %s\n", text, opt->description);
58 fprintf(stream, "%s\t\ticon: %s\n", text, opt->icon_file);
59 fprintf(stream, "%s\t\tboot: %s\n", text, opt->boot_image_file);
60 fprintf(stream, "%s\t\tinit: %s\n", text, opt->initrd_file);
61 fprintf(stream, "%s\t\targs: %s\n", text, opt->boot_args);
65 int pb_protocol_device_cmp(const struct device *a, const struct device *b)
67 return !strcmp(a->id, b->id);
70 int pb_protocol_boot_option_cmp(const struct boot_option *a,
71 const struct boot_option *b)
73 return !strcmp(a->id, b->id);
76 /* Write a string into the buffer, starting at pos.
78 * Returns the total length used for the write, including length header.
80 int pb_protocol_serialise_string(char *pos, const char *str)
87 *(uint32_t *)pos = __cpu_to_be32(len);
88 pos += sizeof(uint32_t);
90 memcpy(pos, str, len);
92 return len + sizeof(uint32_t);
95 /* Read a string from a buffer, allocating the new string as necessary.
97 * @param[in] ctx The talloc context to base the allocation on
98 * @param[in,out] pos Where to start reading
99 * @param[in,out] len The amount of data remaining in the buffer
100 * @param[out] str Pointer to resuling string
101 * @return zero on success, non-zero on failure
103 static int read_string(void *ctx, const char **pos, unsigned int *len,
106 uint32_t str_len, read_len;
108 if (*len < sizeof(uint32_t))
111 str_len = __be32_to_cpu(*(uint32_t *)(*pos));
112 read_len = sizeof(uint32_t);
114 if (read_len + str_len > *len)
120 *str = talloc_strndup(ctx, *pos + read_len, str_len);
124 /* all ok, update the caller's pointers */
131 char *pb_protocol_deserialise_string(void *ctx,
132 const struct pb_protocol_message *message)
138 len = message->payload_len;
139 buf = message->payload;
141 if (read_string(ctx, &buf, &len, &str))
147 static int optional_strlen(const char *str)
154 int pb_protocol_device_len(const struct device *dev)
156 struct boot_option *opt;
159 len = 4 + optional_strlen(dev->id) +
160 4 + optional_strlen(dev->name) +
161 4 + optional_strlen(dev->description) +
162 4 + optional_strlen(dev->icon_file) +
165 list_for_each_entry(&dev->boot_options, opt, list) {
166 len += 4 + optional_strlen(opt->id) +
167 4 + optional_strlen(opt->name) +
168 4 + optional_strlen(opt->description) +
169 4 + optional_strlen(opt->icon_file) +
170 4 + optional_strlen(opt->boot_image_file) +
171 4 + optional_strlen(opt->initrd_file) +
172 4 + optional_strlen(opt->boot_args);
178 int pb_protocol_serialise_device(const struct device *dev, char *buf, int buf_len)
180 struct boot_option *opt;
186 /* construct payload into buffer */
187 pos += pb_protocol_serialise_string(pos, dev->id);
188 pos += pb_protocol_serialise_string(pos, dev->name);
189 pos += pb_protocol_serialise_string(pos, dev->description);
190 pos += pb_protocol_serialise_string(pos, dev->icon_file);
192 /* write option count */
195 list_for_each_entry(&dev->boot_options, opt, list)
198 *(uint32_t *)pos = __cpu_to_be32(n);
199 pos += sizeof(uint32_t);
201 /* write each option */
202 list_for_each_entry(&dev->boot_options, opt, list) {
203 pos += pb_protocol_serialise_string(pos, opt->id);
204 pos += pb_protocol_serialise_string(pos, opt->name);
205 pos += pb_protocol_serialise_string(pos, opt->description);
206 pos += pb_protocol_serialise_string(pos, opt->icon_file);
207 pos += pb_protocol_serialise_string(pos, opt->boot_image_file);
208 pos += pb_protocol_serialise_string(pos, opt->initrd_file);
209 pos += pb_protocol_serialise_string(pos, opt->boot_args);
212 assert(pos <= buf + buf_len);
218 int pb_protocol_write_message(int fd, struct pb_protocol_message *message)
223 total_len = sizeof(*message) + message->payload_len;
225 message->payload_len = __cpu_to_be32(message->payload_len);
226 message->action = __cpu_to_be32(message->action);
228 for (pos = (void *)message; total_len;) {
229 rc = write(fd, pos, total_len);
238 talloc_free(message);
243 pb_log("%s: failed: %s\n", __func__, strerror(errno));
247 struct pb_protocol_message *pb_protocol_create_message(void *ctx,
248 enum pb_protocol_action action, int payload_len)
250 struct pb_protocol_message *message;
252 if (payload_len > PB_PROTOCOL_MAX_PAYLOAD_SIZE) {
253 pb_log("%s: payload too big %u/%u\n", __func__, payload_len,
254 PB_PROTOCOL_MAX_PAYLOAD_SIZE);
258 message = talloc_size(ctx, sizeof(*message) + payload_len);
260 /* we convert these to big-endian in write_message() */
261 message->action = action;
262 message->payload_len = payload_len;
268 struct pb_protocol_message *pb_protocol_read_message(void *ctx, int fd)
270 struct pb_protocol_message *message, m;
274 /* use the stack for the initial 8-byte read */
276 rc = read(fd, &m, sizeof(m));
280 m.payload_len = __be32_to_cpu(m.payload_len);
281 m.action = __be32_to_cpu(m.action);
283 if (m.payload_len > PB_PROTOCOL_MAX_PAYLOAD_SIZE) {
284 pb_log("%s: payload too big %u/%u\n", __func__, m.payload_len,
285 PB_PROTOCOL_MAX_PAYLOAD_SIZE);
289 message = talloc_size(ctx, sizeof(m) + m.payload_len);
290 memcpy(message, &m, sizeof(m));
292 for (len = 0; len < m.payload_len;) {
293 rc = read(fd, message->payload + len, m.payload_len - len);
296 talloc_free(message);
297 pb_log("%s: failed (%u): %s\n", __func__, len,
309 struct device *pb_protocol_deserialise_device(void *ctx,
310 const struct pb_protocol_message *message)
317 len = message->payload_len;
318 pos = message->payload;
320 dev = talloc(ctx, struct device);
322 if (read_string(dev, &pos, &len, &dev->id))
325 if (read_string(dev, &pos, &len, &dev->name))
328 if (read_string(dev, &pos, &len, &dev->description))
331 if (read_string(dev, &pos, &len, &dev->icon_file))
334 n_options = __be32_to_cpu(*(uint32_t *)pos);
335 pos += sizeof(uint32_t);
337 dev->n_options = n_options;
339 list_init(&dev->boot_options);
341 for (i = 0; i < n_options; i++) {
342 struct boot_option *opt;
344 opt = talloc(dev, struct boot_option);
346 if (read_string(opt, &pos, &len, &opt->id))
348 if (read_string(opt, &pos, &len, &opt->name))
350 if (read_string(opt, &pos, &len,
353 if (read_string(opt, &pos, &len,
356 if (read_string(opt, &pos, &len,
357 &opt->boot_image_file))
359 if (read_string(opt, &pos, &len,
362 if (read_string(opt, &pos, &len,
366 list_add(&dev->boot_options, &opt->list);