5 #include <asm/byteorder.h>
7 #include <talloc/talloc.h>
10 #include "pb-protocol.h"
15 * 4-byte action, determines the remaining message content
16 * 4-byte total payload len
17 * - not including action and payload len header
19 * action = 0x1: device add message
23 * 4-byte len, description
24 * 4-byte len, icon_file
30 * 4-byte len, description
31 * 4-byte len, icon_file
32 * 4-byte len, boot_image_file
33 * 4-byte len, initrd_file
34 * 4-byte len, boot_args
36 * action = 0x2: device remove message
41 /* Deep copy a boot_option.
43 struct boot_option *boot_option_copy(void* ctx, const struct boot_option *opt)
45 struct boot_option *new = talloc(ctx, struct boot_option);
48 new->id = talloc_strdup(new, opt->id);
49 new->name = talloc_strdup(new, opt->name);
50 new->description = talloc_strdup(new, opt->description);
51 new->icon_file = talloc_strdup(new, opt->icon_file);
52 new->boot_image_file = talloc_strdup(new, opt->boot_image_file);
53 new->initrd_file = talloc_strdup(new, opt->initrd_file);
54 new->boot_args = talloc_strdup(new, opt->boot_args);
55 memset(&new->list, 0, sizeof(new->list));
61 int pb_protocol_device_cmp(const struct device *a, const struct device *b)
63 return !strcmp(a->id, b->id);
66 int pb_protocol_boot_option_cmp(const struct boot_option *a,
67 const struct boot_option *b)
69 return !strcmp(a->id, b->id);
72 /* Write a string into the buffer, starting at pos.
74 * Returns the total length used for the write, including length header.
76 int pb_protocol_serialise_string(char *pos, const char *str)
83 *(uint32_t *)pos = __cpu_to_be32(len);
84 pos += sizeof(uint32_t);
86 memcpy(pos, str, len);
88 return len + sizeof(uint32_t);
91 /* Read a string from a buffer, allocating the new string as necessary.
93 * @param[in] ctx The talloc context to base the allocation on
94 * @param[in,out] pos Where to start reading
95 * @param[in,out] len The amount of data remaining in the buffer
96 * @param[out] str Pointer to resuling string
97 * @return zero on success, non-zero on failure
99 static int read_string(void *ctx, const char **pos, unsigned int *len,
102 uint32_t str_len, read_len;
104 if (*len < sizeof(uint32_t))
107 str_len = __be32_to_cpu(*(uint32_t *)(*pos));
108 read_len = sizeof(uint32_t);
110 if (read_len + str_len > *len)
116 *str = talloc_strndup(ctx, *pos + read_len, str_len);
120 /* all ok, update the caller's pointers */
127 char *pb_protocol_deserialise_string(void *ctx,
128 const struct pb_protocol_message *message)
134 len = message->payload_len;
135 buf = message->payload;
137 if (read_string(ctx, &buf, &len, &str))
143 static int optional_strlen(const char *str)
150 int pb_protocol_device_len(const struct device *dev)
152 struct boot_option *opt;
155 len = 4 + optional_strlen(dev->id) +
156 4 + optional_strlen(dev->name) +
157 4 + optional_strlen(dev->description) +
158 4 + optional_strlen(dev->icon_file) +
161 list_for_each_entry(&dev->boot_options, opt, list) {
162 len += 4 + optional_strlen(opt->id) +
163 4 + optional_strlen(opt->name) +
164 4 + optional_strlen(opt->description) +
165 4 + optional_strlen(opt->icon_file) +
166 4 + optional_strlen(opt->boot_image_file) +
167 4 + optional_strlen(opt->initrd_file) +
168 4 + optional_strlen(opt->boot_args);
174 int pb_protocol_serialise_device(const struct device *dev, char *buf, int buf_len)
176 struct boot_option *opt;
182 /* construct payload into buffer */
183 pos += pb_protocol_serialise_string(pos, dev->id);
184 pos += pb_protocol_serialise_string(pos, dev->name);
185 pos += pb_protocol_serialise_string(pos, dev->description);
186 pos += pb_protocol_serialise_string(pos, dev->icon_file);
188 /* write option count */
191 list_for_each_entry(&dev->boot_options, opt, list)
194 *(uint32_t *)pos = __cpu_to_be32(n);
195 pos += sizeof(uint32_t);
197 /* write each option */
198 list_for_each_entry(&dev->boot_options, opt, list) {
199 pos += pb_protocol_serialise_string(pos, opt->id);
200 pos += pb_protocol_serialise_string(pos, opt->name);
201 pos += pb_protocol_serialise_string(pos, opt->description);
202 pos += pb_protocol_serialise_string(pos, opt->icon_file);
203 pos += pb_protocol_serialise_string(pos, opt->boot_image_file);
204 pos += pb_protocol_serialise_string(pos, opt->initrd_file);
205 pos += pb_protocol_serialise_string(pos, opt->boot_args);
208 assert(pos <= buf + buf_len);
213 int pb_protocol_write_message(int fd, struct pb_protocol_message *message)
218 total_len = sizeof(*message) + message->payload_len;
220 message->payload_len = __cpu_to_be32(message->payload_len);
221 message->action = __cpu_to_be32(message->action);
223 for (pos = (void *)message; total_len;) {
224 rc = write(fd, pos, total_len);
233 talloc_free(message);
235 return total_len ? -1 : 0;
238 struct pb_protocol_message *pb_protocol_create_message(void *ctx,
239 enum pb_protocol_action action, int payload_len)
241 struct pb_protocol_message *message;
243 if (payload_len > PB_PROTOCOL_MAX_PAYLOAD_SIZE)
246 message = talloc_size(ctx, sizeof(*message) + payload_len);
248 /* we convert these to big-endian in write_message() */
249 message->action = action;
250 message->payload_len = payload_len;
256 struct pb_protocol_message *pb_protocol_read_message(void *ctx, int fd)
258 struct pb_protocol_message *message, m;
262 /* use the stack for the initial 8-byte read */
264 rc = read(fd, &m, sizeof(m));
268 m.payload_len = __be32_to_cpu(m.payload_len);
269 m.action = __be32_to_cpu(m.action);
271 if (m.payload_len > PB_PROTOCOL_MAX_PAYLOAD_SIZE)
274 message = talloc_size(ctx, sizeof(m) + m.payload_len);
275 memcpy(message, &m, sizeof(m));
277 for (len = 0; len < m.payload_len;) {
278 rc = read(fd, message->payload + len, m.payload_len - len);
281 talloc_free(message);
292 struct device *pb_protocol_deserialise_device(void *ctx,
293 const struct pb_protocol_message *message)
300 len = message->payload_len;
301 pos = message->payload;
303 dev = talloc(ctx, struct device);
305 if (read_string(dev, &pos, &len, &dev->id))
308 if (read_string(dev, &pos, &len, &dev->name))
311 if (read_string(dev, &pos, &len, &dev->description))
314 if (read_string(dev, &pos, &len, &dev->icon_file))
317 n_options = __be32_to_cpu(*(uint32_t *)pos);
318 pos += sizeof(uint32_t);
320 list_init(&dev->boot_options);
322 for (i = 0; i < n_options; i++) {
323 struct boot_option *opt;
325 opt = talloc(dev, struct boot_option);
327 if (read_string(opt, &pos, &len, &opt->id))
329 if (read_string(opt, &pos, &len, &opt->name))
331 if (read_string(opt, &pos, &len,
334 if (read_string(opt, &pos, &len,
337 if (read_string(opt, &pos, &len,
338 &opt->boot_image_file))
340 if (read_string(opt, &pos, &len,
343 if (read_string(opt, &pos, &len,
347 list_add(&dev->boot_options, &opt->list);