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 int pb_protocol_device_cmp(const struct device *a, const struct device *b)
43 return !strcmp(a->id, b->id);
46 int pb_protocol_boot_option_cmp(const struct boot_option *a,
47 const struct boot_option *b)
49 return !strcmp(a->id, b->id);
52 /* Write a string into the buffer, starting at pos.
54 * Returns the total length used for the write, including length header.
56 int pb_protocol_serialise_string(char *pos, const char *str)
63 *(uint32_t *)pos = __cpu_to_be32(len);
64 pos += sizeof(uint32_t);
66 memcpy(pos, str, len);
68 return len + sizeof(uint32_t);
71 /* Read a string from a buffer, allocating the new string as necessary.
73 * @param[in] ctx The talloc context to base the allocation on
74 * @param[in,out] pos Where to start reading
75 * @param[in,out] len The amount of data remaining in the buffer
76 * @param[out] str Pointer to resuling string
77 * @return zero on success, non-zero on failure
79 static int read_string(void *ctx, const char **pos, unsigned int *len,
82 uint32_t str_len, read_len;
84 if (*len < sizeof(uint32_t))
87 str_len = __be32_to_cpu(*(uint32_t *)(*pos));
88 read_len = sizeof(uint32_t);
90 if (read_len + str_len > *len)
96 *str = talloc_strndup(ctx, *pos + read_len, str_len);
100 /* all ok, update the caller's pointers */
107 char *pb_protocol_deserialise_string(void *ctx,
108 const struct pb_protocol_message *message)
114 len = message->payload_len;
115 buf = message->payload;
117 if (read_string(ctx, &buf, &len, &str))
123 static int optional_strlen(const char *str)
130 int pb_protocol_device_len(const struct device *dev)
132 struct boot_option *opt;
135 len = 4 + optional_strlen(dev->id) +
136 4 + optional_strlen(dev->name) +
137 4 + optional_strlen(dev->description) +
138 4 + optional_strlen(dev->icon_file) +
141 list_for_each_entry(&dev->boot_options, opt, list) {
142 len += 4 + optional_strlen(opt->id) +
143 4 + optional_strlen(opt->name) +
144 4 + optional_strlen(opt->description) +
145 4 + optional_strlen(opt->icon_file) +
146 4 + optional_strlen(opt->boot_image_file) +
147 4 + optional_strlen(opt->initrd_file) +
148 4 + optional_strlen(opt->boot_args);
154 int pb_protocol_serialise_device(const struct device *dev, char *buf, int buf_len)
156 struct boot_option *opt;
162 /* construct payload into buffer */
163 pos += pb_protocol_serialise_string(pos, dev->id);
164 pos += pb_protocol_serialise_string(pos, dev->name);
165 pos += pb_protocol_serialise_string(pos, dev->description);
166 pos += pb_protocol_serialise_string(pos, dev->icon_file);
168 /* write option count */
171 list_for_each_entry(&dev->boot_options, opt, list)
174 *(uint32_t *)pos = __cpu_to_be32(n);
175 pos += sizeof(uint32_t);
177 /* write each option */
178 list_for_each_entry(&dev->boot_options, opt, list) {
179 pos += pb_protocol_serialise_string(pos, opt->id);
180 pos += pb_protocol_serialise_string(pos, opt->name);
181 pos += pb_protocol_serialise_string(pos, opt->description);
182 pos += pb_protocol_serialise_string(pos, opt->icon_file);
183 pos += pb_protocol_serialise_string(pos, opt->boot_image_file);
184 pos += pb_protocol_serialise_string(pos, opt->initrd_file);
185 pos += pb_protocol_serialise_string(pos, opt->boot_args);
188 assert(pos <= buf + buf_len);
193 int pb_protocol_write_message(int fd, struct pb_protocol_message *message)
198 total_len = sizeof(*message) + message->payload_len;
200 message->payload_len = __cpu_to_be32(message->payload_len);
201 message->action = __cpu_to_be32(message->action);
203 for (pos = (void *)message; total_len;) {
204 rc = write(fd, pos, total_len);
213 talloc_free(message);
215 return total_len ? -1 : 0;
218 struct pb_protocol_message *pb_protocol_create_message(void *ctx,
219 enum pb_protocol_action action, int payload_len)
221 struct pb_protocol_message *message;
223 if (payload_len > PB_PROTOCOL_MAX_PAYLOAD_SIZE)
226 message = talloc_size(ctx, sizeof(*message) + payload_len);
228 /* we convert these to big-endian in write_message() */
229 message->action = action;
230 message->payload_len = payload_len;
236 struct pb_protocol_message *pb_protocol_read_message(void *ctx, int fd)
238 struct pb_protocol_message *message, m;
242 /* use the stack for the initial 8-byte read */
244 rc = read(fd, &m, sizeof(m));
248 m.payload_len = __be32_to_cpu(m.payload_len);
249 m.action = __be32_to_cpu(m.action);
251 if (m.payload_len > PB_PROTOCOL_MAX_PAYLOAD_SIZE)
254 message = talloc_size(ctx, sizeof(m) + m.payload_len);
255 memcpy(message, &m, sizeof(m));
257 for (len = 0; len < m.payload_len;) {
258 rc = read(fd, message->payload + len, m.payload_len - len);
261 talloc_free(message);
272 struct device *pb_protocol_deserialise_device(void *ctx,
273 const struct pb_protocol_message *message)
280 len = message->payload_len;
281 pos = message->payload;
283 dev = talloc(ctx, struct device);
285 if (read_string(dev, &pos, &len, &dev->id))
288 if (read_string(dev, &pos, &len, &dev->name))
291 if (read_string(dev, &pos, &len, &dev->description))
294 if (read_string(dev, &pos, &len, &dev->icon_file))
297 n_options = __be32_to_cpu(*(uint32_t *)pos);
298 pos += sizeof(uint32_t);
300 list_init(&dev->boot_options);
302 for (i = 0; i < n_options; i++) {
303 struct boot_option *opt;
305 opt = talloc(dev, struct boot_option);
307 if (read_string(opt, &pos, &len, &opt->id))
309 if (read_string(opt, &pos, &len, &opt->name))
311 if (read_string(opt, &pos, &len,
314 if (read_string(opt, &pos, &len,
317 if (read_string(opt, &pos, &len,
318 &opt->boot_image_file))
320 if (read_string(opt, &pos, &len,
323 if (read_string(opt, &pos, &len,
327 list_add(&dev->boot_options, &opt->list);