4 #include <asm/byteorder.h>
6 #include <talloc/talloc.h>
8 #include "pb-protocol.h"
13 * 4-byte action, determines the remaining message content
14 * 4-byte total payload len
15 * - not including action and payload len header
17 * action = 0x1: device add message
21 * 4-byte len, description
22 * 4-byte len, icon_file
28 * 4-byte len, description
29 * 4-byte len, icon_file
30 * 4-byte len, boot_image_file
31 * 4-byte len, initrd_file
32 * 4-byte len, boot_args
34 * action = 0x2: device remove message
40 /* Write a string into the buffer, starting at pos.
42 * Returns the total length used for the write, including length header.
44 int pb_protocol_serialise_string(char *pos, const char *str)
51 *(uint32_t *)pos = __cpu_to_be32(len);
52 pos += sizeof(uint32_t);
54 memcpy(pos, str, len);
56 return len + sizeof(uint32_t);
59 /* Read a string from a buffer, allocating the new string as necessary.
61 * @param[in] ctx The talloc context to base the allocation on
62 * @param[in,out] pos Where to start reading
63 * @param[in,out] len The amount of data remaining in the buffer
64 * @param[out] str Pointer to resuling string
65 * @return zero on success, non-zero on failure
67 static int read_string(void *ctx, char **pos, int *len, char **str)
69 uint32_t str_len, read_len;
71 if (*len < sizeof(uint32_t))
74 str_len = __be32_to_cpu(*(uint32_t *)(*pos));
75 read_len = sizeof(uint32_t);
77 if (read_len + str_len > *len)
83 *str = talloc_strndup(ctx, *pos + read_len, str_len);
87 /* all ok, update the caller's pointers */
94 char *pb_protocol_deserialise_string(void *ctx,
95 struct pb_protocol_message *message)
100 len = message->payload_len;
101 buf = message->payload;
103 if (read_string(ctx, &buf, &len, &str))
109 static int optional_strlen(const char *str)
116 int pb_protocol_device_len(struct device *dev)
120 len = 4 + optional_strlen(dev->id) +
121 4 + optional_strlen(dev->name) +
122 4 + optional_strlen(dev->description) +
123 4 + optional_strlen(dev->icon_file) +
126 for (i = 0; i < dev->n_options; i++) {
127 struct boot_option *opt = &dev->options[i];
128 len += 4 + optional_strlen(opt->id) +
129 4 + optional_strlen(opt->name) +
130 4 + optional_strlen(opt->description) +
131 4 + optional_strlen(opt->icon_file) +
132 4 + optional_strlen(opt->boot_image_file) +
133 4 + optional_strlen(opt->initrd_file) +
134 4 + optional_strlen(opt->boot_args);
140 int pb_protocol_serialise_device(struct device *dev, char *buf, int buf_len)
147 /* construct payload into buffer */
148 pos += pb_protocol_serialise_string(pos, dev->id);
149 pos += pb_protocol_serialise_string(pos, dev->name);
150 pos += pb_protocol_serialise_string(pos, dev->description);
151 pos += pb_protocol_serialise_string(pos, dev->icon_file);
153 /* write option count */
154 *(uint32_t *)pos = __cpu_to_be32(dev->n_options);
155 pos += sizeof(uint32_t);
157 /* write each option */
158 for (i = 0; i < dev->n_options; i++) {
159 struct boot_option *opt = &dev->options[i];
160 pos += pb_protocol_serialise_string(pos, opt->id);
161 pos += pb_protocol_serialise_string(pos, opt->name);
162 pos += pb_protocol_serialise_string(pos, opt->description);
163 pos += pb_protocol_serialise_string(pos, opt->icon_file);
164 pos += pb_protocol_serialise_string(pos, opt->boot_image_file);
165 pos += pb_protocol_serialise_string(pos, opt->initrd_file);
166 pos += pb_protocol_serialise_string(pos, opt->boot_args);
172 int pb_protocol_write_message(int fd, struct pb_protocol_message *message)
177 total_len = sizeof(*message) + message->payload_len;
179 message->payload_len = __cpu_to_be32(message->payload_len);
180 message->action = __cpu_to_be32(message->action);
182 for (pos = (void *)message; total_len;) {
183 rc = write(fd, pos, total_len);
192 talloc_free(message);
194 return total_len ? -1 : 0;
197 struct pb_protocol_message *pb_protocol_create_message(void *ctx,
198 int action, int payload_len)
200 struct pb_protocol_message *message;
202 if (payload_len > PB_PROTOCOL_MAX_PAYLOAD_SIZE)
205 message = talloc_size(ctx, sizeof(*message) + payload_len);
207 /* we convert these to big-endian in write_message() */
208 message->action = action;
209 message->payload_len = payload_len;
215 struct pb_protocol_message *pb_protocol_read_message(void *ctx, int fd)
217 struct pb_protocol_message *message, m;
220 /* use the stack for the initial 8-byte read */
222 rc = read(fd, &m, sizeof(m));
226 m.payload_len = __be32_to_cpu(m.payload_len);
227 m.action = __be32_to_cpu(m.action);
229 if (m.payload_len > PB_PROTOCOL_MAX_PAYLOAD_SIZE)
232 message = talloc_size(ctx, sizeof(m) + m.payload_len);
233 memcpy(message, &m, sizeof(m));
235 for (len = 0; len < m.payload_len;) {
236 rc = read(fd, message->payload + len, m.payload_len - len);
239 talloc_free(message);
250 struct device *pb_protocol_deserialise_device(void *ctx,
251 struct pb_protocol_message *message)
257 len = message->payload_len;
258 pos = message->payload;
260 dev = talloc(ctx, struct device);
262 if (read_string(dev, &pos, &len, &dev->id))
265 if (read_string(dev, &pos, &len, &dev->name))
268 if (read_string(dev, &pos, &len, &dev->description))
271 if (read_string(dev, &pos, &len, &dev->icon_file))
274 dev->n_options = __be32_to_cpu(*(uint32_t *)pos);
275 dev->options = talloc_array(dev, struct boot_option, dev->n_options);
276 pos += sizeof(uint32_t);
278 for (i = 0; i < dev->n_options; i++) {
279 struct boot_option *opt = &dev->options[i];
281 if (read_string(opt, &pos, &len, &opt->id))
283 if (read_string(opt, &pos, &len, &opt->name))
285 if (read_string(opt, &pos, &len,
288 if (read_string(opt, &pos, &len,
291 if (read_string(opt, &pos, &len,
292 &opt->boot_image_file))
294 if (read_string(opt, &pos, &len,
297 if (read_string(opt, &pos, &len,