types: Remove detail and progress from struct status
[petitboot] / lib / pb-protocol / pb-protocol.c
1
2 #include <assert.h>
3 #include <errno.h>
4 #include <string.h>
5 #include <stdbool.h>
6 #include <stdint.h>
7 #include <asm/byteorder.h>
8
9 #include <talloc/talloc.h>
10 #include <list/list.h>
11 #include <log/log.h>
12
13 #include "pb-protocol.h"
14
15
16 /* Message format:
17  *
18  * 4-byte action, determines the remaining message content
19  * 4-byte total payload len
20  *   - not including action and payload len header
21  *
22  * action = 0x1: device add message
23  *  payload:
24  *   4-byte len, id
25  *   1-byte type
26  *   4-byte len, name
27  *   4-byte len, description
28  *   4-byte len, icon_file
29  *
30  *   4-byte option count
31  *   for each option:
32  *    4-byte len, id
33  *    4-byte len, name
34  *    4-byte len, description
35  *    4-byte len, icon_file
36  *    4-byte len, boot_image_file
37  *    4-byte len, initrd_file
38  *    4-byte len, dtb_file
39  *    4-byte len, boot_args
40  *    4-byte len, args_sig_file
41  *
42  * action = 0x2: device remove message
43  *  payload:
44  *   4-byte len, id
45  *
46  * action = 0x3: boot
47  *  payload:
48  *   4-byte len, boot option id
49  *   4-byte len, boot_image_file
50  *   4-byte len, initrd_file
51  *   4-byte len, dtb_file
52  *   4-byte len, boot_args
53  *   4-byte len, args_sig_file
54  *
55  */
56
57 void pb_protocol_dump_device(const struct device *dev, const char *text,
58         FILE *stream)
59 {
60         struct boot_option *opt;
61
62         fprintf(stream, "%snew dev:\n", text);
63         fprintf(stream, "%s\tid:   %s\n", text, dev->id);
64         fprintf(stream, "%s\tname: %s\n", text, dev->name);
65         fprintf(stream, "%s\tdesc: %s\n", text, dev->description);
66         fprintf(stream, "%s\ticon: %s\n", text, dev->icon_file);
67         fprintf(stream, "%s\tboot options:\n", text);
68         list_for_each_entry(&dev->boot_options, opt, list) {
69                 fprintf(stream, "%s\t\tid:   %s\n", text, opt->id);
70                 fprintf(stream, "%s\t\tname: %s\n", text, opt->name);
71                 fprintf(stream, "%s\t\tdesc: %s\n", text, opt->description);
72                 fprintf(stream, "%s\t\ticon: %s\n", text, opt->icon_file);
73                 fprintf(stream, "%s\t\tboot: %s\n", text, opt->boot_image_file);
74                 fprintf(stream, "%s\t\tinit: %s\n", text, opt->initrd_file);
75                 fprintf(stream, "%s\t\tdtb:  %s\n", text, opt->dtb_file);
76                 fprintf(stream, "%s\t\targs: %s\n", text, opt->boot_args);
77                 fprintf(stream, "%s\t\tasig: %s\n", text, opt->args_sig_file);
78         }
79 }
80
81 int pb_protocol_device_cmp(const struct device *a, const struct device *b)
82 {
83         return !strcmp(a->id, b->id);
84 }
85
86 int pb_protocol_boot_option_cmp(const struct boot_option *a,
87         const struct boot_option *b)
88 {
89         return !strcmp(a->id, b->id);
90 }
91
92 /* Write a string into the buffer, starting at pos.
93  *
94  * Returns the total length used for the write, including length header.
95  */
96 int pb_protocol_serialise_string(char *pos, const char *str)
97 {
98         int len = 0;
99
100         if (str)
101                 len = strlen(str);
102
103         *(uint32_t *)pos = __cpu_to_be32(len);
104         pos += sizeof(uint32_t);
105
106         memcpy(pos, str, len);
107
108         return len + sizeof(uint32_t);
109 }
110
111 /* Read a string from a buffer, allocating the new string as necessary.
112  *
113  * @param[in] ctx       The talloc context to base the allocation on
114  * @param[in,out] pos   Where to start reading
115  * @param[in,out] len   The amount of data remaining in the buffer
116  * @param[out] str      Pointer to resuling string
117  * @return              zero on success, non-zero on failure
118  */
119 static int read_string(void *ctx, const char **pos, unsigned int *len,
120         char **str)
121 {
122         uint32_t str_len, read_len;
123
124         if (*len < sizeof(uint32_t))
125                 return -1;
126
127         str_len = __be32_to_cpu(*(uint32_t *)(*pos));
128         read_len = sizeof(uint32_t);
129
130         if (read_len + str_len > *len)
131                 return -1;
132
133         if (str_len == 0)
134                 *str = NULL;
135         else
136                 *str = talloc_strndup(ctx, *pos + read_len, str_len);
137
138         read_len += str_len;
139
140         /* all ok, update the caller's pointers */
141         *pos += read_len;
142         *len -= read_len;
143
144         return 0;
145 }
146
147 static int read_u32(const char **pos, unsigned int *len, unsigned int *p)
148 {
149         if (*len < sizeof(uint32_t))
150                 return -1;
151
152         *p = (unsigned int)__be32_to_cpu(*(uint32_t *)(*pos));
153         *pos += sizeof(uint32_t);
154         *len -= sizeof(uint32_t);
155
156         return 0;
157 }
158
159 char *pb_protocol_deserialise_string(void *ctx,
160                 const struct pb_protocol_message *message)
161 {
162         const char *buf;
163         char *str;
164         unsigned int len;
165
166         len = message->payload_len;
167         buf = message->payload;
168
169         if (read_string(ctx, &buf, &len, &str))
170                 return NULL;
171
172         return str;
173 }
174
175 static int optional_strlen(const char *str)
176 {
177         if (!str)
178                 return 0;
179         return strlen(str);
180 }
181
182 int pb_protocol_device_len(const struct device *dev)
183 {
184         return  4 + optional_strlen(dev->id) +
185                 sizeof(dev->type) +
186                 4 + optional_strlen(dev->name) +
187                 4 + optional_strlen(dev->description) +
188                 4 + optional_strlen(dev->icon_file);
189 }
190
191 int pb_protocol_boot_option_len(const struct boot_option *opt)
192 {
193
194         return  4 + optional_strlen(opt->device_id) +
195                 4 + optional_strlen(opt->id) +
196                 4 + optional_strlen(opt->name) +
197                 4 + optional_strlen(opt->description) +
198                 4 + optional_strlen(opt->icon_file) +
199                 4 + optional_strlen(opt->boot_image_file) +
200                 4 + optional_strlen(opt->initrd_file) +
201                 4 + optional_strlen(opt->dtb_file) +
202                 4 + optional_strlen(opt->boot_args) +
203                 4 + optional_strlen(opt->args_sig_file) +
204                 sizeof(opt->is_default);
205 }
206
207 int pb_protocol_boot_len(const struct boot_command *boot)
208 {
209         return  4 + optional_strlen(boot->option_id) +
210                 4 + optional_strlen(boot->boot_image_file) +
211                 4 + optional_strlen(boot->initrd_file) +
212                 4 + optional_strlen(boot->dtb_file) +
213                 4 + optional_strlen(boot->boot_args) +
214                 4 + optional_strlen(boot->args_sig_file) +
215                 4 + optional_strlen(boot->console);
216 }
217
218 int pb_protocol_boot_status_len(const struct status *status)
219 {
220         return  4 +
221                 4 + optional_strlen(status->message) +
222                 4;
223 }
224
225 int pb_protocol_system_info_len(const struct system_info *sysinfo)
226 {
227         unsigned int len, i;
228
229         len =   4 + optional_strlen(sysinfo->type) +
230                 4 + optional_strlen(sysinfo->identifier) +
231                 4 + 4;
232
233         len +=  4;
234         for (i = 0; i < sysinfo->n_primary; i++)
235                 len += 4 + optional_strlen(sysinfo->platform_primary[i]);
236         len +=  4;
237         for (i = 0; i < sysinfo->n_other; i++)
238                 len += 4 + optional_strlen(sysinfo->platform_other[i]);
239
240         len +=  4;
241         for (i = 0; i < sysinfo->n_bmc_current; i++)
242                 len += 4 + optional_strlen(sysinfo->bmc_current[i]);
243         len +=  4;
244         for (i = 0; i < sysinfo->n_bmc_golden; i++)
245                 len += 4 + optional_strlen(sysinfo->bmc_golden[i]);
246
247         for (i = 0; i < sysinfo->n_interfaces; i++) {
248                 struct interface_info *if_info = sysinfo->interfaces[i];
249                 len +=  4 + if_info->hwaddr_size +
250                         4 + optional_strlen(if_info->name) +
251                         sizeof(if_info->link);
252         }
253
254         for (i = 0; i < sysinfo->n_blockdevs; i++) {
255                 struct blockdev_info *bd_info = sysinfo->blockdevs[i];
256                 len +=  4 + optional_strlen(bd_info->name) +
257                         4 + optional_strlen(bd_info->uuid) +
258                         4 + optional_strlen(bd_info->mountpoint);
259         }
260
261         /* BMC MAC */
262         len += HWADDR_SIZE;
263
264         return len;
265 }
266
267 static int pb_protocol_interface_config_len(struct interface_config *conf)
268 {
269         unsigned int len;
270
271         len =   sizeof(conf->hwaddr) +
272                 4 /* conf->ignore */;
273
274         if (conf->ignore)
275                 return len;
276
277         len += 4 /* conf->method */;
278
279         if (conf->method == CONFIG_METHOD_STATIC) {
280                 len += 4 + optional_strlen(conf->static_config.address);
281                 len += 4 + optional_strlen(conf->static_config.gateway);
282                 len += 4 + optional_strlen(conf->static_config.url);
283         }
284
285         len += 4 /* conf->override */;
286
287         return len;
288 }
289
290 int pb_protocol_config_len(const struct config *config)
291 {
292         unsigned int i, len;
293
294         len =   4 /* config->autoboot_enabled */ +
295                 4 /* config->autoboot_timeout_sec */ +
296                 4 /* config->safe_mode */;
297
298         len += 4;
299         for (i = 0; i < config->network.n_interfaces; i++)
300                 len += pb_protocol_interface_config_len(
301                                 config->network.interfaces[i]);
302
303         len += 4;
304         for (i = 0; i < config->network.n_dns_servers; i++)
305                 len += 4 + optional_strlen(config->network.dns_servers[i]);
306
307         len += 4 + optional_strlen(config->http_proxy);
308         len += 4 + optional_strlen(config->https_proxy);
309
310         len += 4;
311         for (i = 0; i < config->n_autoboot_opts; i++) {
312                 if (config->autoboot_opts[i].boot_type == BOOT_DEVICE_TYPE)
313                         len += 4 + 4;
314                 else
315                         len += 4 + 4 +
316                                 optional_strlen(config->autoboot_opts[i].uuid);
317         }
318
319         len += 4 + 4; /* ipmi_bootdev, ipmi_bootdev_persistent */
320
321         len += 4; /* allow_writes */
322
323         len += 4; /* n_consoles */
324         for (i = 0; i < config->n_consoles; i++)
325                 len += 4 + optional_strlen(config->consoles[i]);
326
327         len += 4 + optional_strlen(config->boot_console);
328         len += 4; /* manual_console */
329
330         len += 4 + optional_strlen(config->lang);
331
332         return len;
333 }
334
335 int pb_protocol_url_len(const char *url)
336 {
337         /* url + length field */
338         return 4 + optional_strlen(url);
339 }
340
341 int pb_protocol_serialise_device(const struct device *dev,
342                 char *buf, int buf_len)
343 {
344         char *pos = buf;
345
346         pos += pb_protocol_serialise_string(pos, dev->id);
347         *(enum device_type *)pos = dev->type;
348         pos += sizeof(enum device_type);
349         pos += pb_protocol_serialise_string(pos, dev->name);
350         pos += pb_protocol_serialise_string(pos, dev->description);
351         pos += pb_protocol_serialise_string(pos, dev->icon_file);
352
353         assert(pos <= buf + buf_len);
354         (void)buf_len;
355
356         return 0;
357 }
358
359 int pb_protocol_serialise_boot_option(const struct boot_option *opt,
360                 char *buf, int buf_len)
361 {
362         char *pos = buf;
363
364         pos += pb_protocol_serialise_string(pos, opt->device_id);
365         pos += pb_protocol_serialise_string(pos, opt->id);
366         pos += pb_protocol_serialise_string(pos, opt->name);
367         pos += pb_protocol_serialise_string(pos, opt->description);
368         pos += pb_protocol_serialise_string(pos, opt->icon_file);
369         pos += pb_protocol_serialise_string(pos, opt->boot_image_file);
370         pos += pb_protocol_serialise_string(pos, opt->initrd_file);
371         pos += pb_protocol_serialise_string(pos, opt->dtb_file);
372         pos += pb_protocol_serialise_string(pos, opt->boot_args);
373         pos += pb_protocol_serialise_string(pos, opt->args_sig_file);
374
375         *(bool *)pos = opt->is_default;
376         pos += sizeof(bool);
377
378         assert(pos <= buf + buf_len);
379         (void)buf_len;
380
381         return 0;
382 }
383
384 int pb_protocol_serialise_boot_command(const struct boot_command *boot,
385                 char *buf, int buf_len)
386 {
387         char *pos = buf;
388
389         pos += pb_protocol_serialise_string(pos, boot->option_id);
390         pos += pb_protocol_serialise_string(pos, boot->boot_image_file);
391         pos += pb_protocol_serialise_string(pos, boot->initrd_file);
392         pos += pb_protocol_serialise_string(pos, boot->dtb_file);
393         pos += pb_protocol_serialise_string(pos, boot->boot_args);
394         pos += pb_protocol_serialise_string(pos, boot->args_sig_file);
395         pos += pb_protocol_serialise_string(pos, boot->console);
396
397         assert(pos <= buf + buf_len);
398         (void)buf_len;
399
400         return 0;
401 }
402
403 int pb_protocol_serialise_boot_status(const struct status *status,
404                 char *buf, int buf_len)
405 {
406         char *pos = buf;
407
408         *(uint32_t *)pos = __cpu_to_be32(status->type);
409         pos += sizeof(uint32_t);
410
411         pos += pb_protocol_serialise_string(pos, status->message);
412
413         assert(pos <= buf + buf_len);
414         (void)buf_len;
415
416         return 0;
417 }
418
419 int pb_protocol_serialise_system_info(const struct system_info *sysinfo,
420                 char *buf, int buf_len)
421 {
422         char *pos = buf;
423         unsigned int i;
424
425         pos += pb_protocol_serialise_string(pos, sysinfo->type);
426         pos += pb_protocol_serialise_string(pos, sysinfo->identifier);
427
428         *(uint32_t *)pos = __cpu_to_be32(sysinfo->n_primary);
429         pos += sizeof(uint32_t);
430         for (i = 0; i < sysinfo->n_primary; i++)
431                 pos += pb_protocol_serialise_string(pos, sysinfo->platform_primary[i]);
432
433         *(uint32_t *)pos = __cpu_to_be32(sysinfo->n_other);
434         pos += sizeof(uint32_t);
435         for (i = 0; i < sysinfo->n_other; i++)
436                 pos += pb_protocol_serialise_string(pos, sysinfo->platform_other[i]);
437
438         *(uint32_t *)pos = __cpu_to_be32(sysinfo->n_bmc_current);
439         pos += sizeof(uint32_t);
440         for (i = 0; i < sysinfo->n_bmc_current; i++)
441                 pos += pb_protocol_serialise_string(pos, sysinfo->bmc_current[i]);
442
443         *(uint32_t *)pos = __cpu_to_be32(sysinfo->n_bmc_golden);
444         pos += sizeof(uint32_t);
445         for (i = 0; i < sysinfo->n_bmc_golden; i++)
446                 pos += pb_protocol_serialise_string(pos, sysinfo->bmc_golden[i]);
447
448         *(uint32_t *)pos = __cpu_to_be32(sysinfo->n_interfaces);
449         pos += sizeof(uint32_t);
450
451         for (i = 0; i < sysinfo->n_interfaces; i++) {
452                 struct interface_info *if_info = sysinfo->interfaces[i];
453
454                 *(uint32_t *)pos = __cpu_to_be32(if_info->hwaddr_size);
455                 pos += sizeof(uint32_t);
456
457                 memcpy(pos, if_info->hwaddr, if_info->hwaddr_size);
458                 pos += if_info->hwaddr_size;
459
460                 pos += pb_protocol_serialise_string(pos, if_info->name);
461
462                 *(bool *)pos = if_info->link;
463                 pos += sizeof(bool);
464         }
465
466         *(uint32_t *)pos = __cpu_to_be32(sysinfo->n_blockdevs);
467         pos += sizeof(uint32_t);
468
469         for (i = 0; i < sysinfo->n_blockdevs; i++) {
470                 struct blockdev_info *bd_info = sysinfo->blockdevs[i];
471
472                 pos += pb_protocol_serialise_string(pos, bd_info->name);
473                 pos += pb_protocol_serialise_string(pos, bd_info->uuid);
474                 pos += pb_protocol_serialise_string(pos, bd_info->mountpoint);
475         }
476
477         if (sysinfo->bmc_mac)
478                 memcpy(pos, sysinfo->bmc_mac, HWADDR_SIZE);
479         else
480                 memset(pos, 0, HWADDR_SIZE);
481         pos += HWADDR_SIZE;
482
483         assert(pos <= buf + buf_len);
484         (void)buf_len;
485
486         return 0;
487 }
488
489 static int pb_protocol_serialise_config_interface(char *buf,
490                 struct interface_config *conf)
491 {
492         char *pos = buf;
493
494         memcpy(pos, conf->hwaddr, sizeof(conf->hwaddr));
495         pos += sizeof(conf->hwaddr);
496
497         *(uint32_t *)pos = conf->ignore;
498         pos += 4;
499
500         if (conf->ignore)
501                 return pos - buf;
502
503         *(uint32_t *)pos = __cpu_to_be32(conf->method);
504         pos += 4;
505
506         if (conf->method == CONFIG_METHOD_STATIC) {
507                 pos += pb_protocol_serialise_string(pos,
508                                 conf->static_config.address);
509                 pos += pb_protocol_serialise_string(pos,
510                                 conf->static_config.gateway);
511                 pos += pb_protocol_serialise_string(pos,
512                                 conf->static_config.url);
513         }
514
515         *(uint32_t *)pos = conf->override;
516         pos += 4;
517
518         return pos - buf;
519 }
520
521 int pb_protocol_serialise_config(const struct config *config,
522                 char *buf, int buf_len)
523 {
524         char *pos = buf;
525         unsigned int i;
526
527         *(uint32_t *)pos = config->autoboot_enabled;
528         pos += 4;
529
530         *(uint32_t *)pos = __cpu_to_be32(config->autoboot_timeout_sec);
531         pos += 4;
532
533         *(uint32_t *)pos = config->safe_mode;
534         pos += 4;
535
536         *(uint32_t *)pos = __cpu_to_be32(config->network.n_interfaces);
537         pos += 4;
538         for (i = 0; i < config->network.n_interfaces; i++) {
539                 struct interface_config *iface =
540                         config->network.interfaces[i];
541                 pos += pb_protocol_serialise_config_interface(pos, iface);
542         }
543
544         *(uint32_t *)pos = __cpu_to_be32(config->network.n_dns_servers);
545         pos += 4;
546         for (i = 0; i < config->network.n_dns_servers; i++) {
547                 pos += pb_protocol_serialise_string(pos,
548                                 config->network.dns_servers[i]);
549         }
550
551         pos += pb_protocol_serialise_string(pos, config->http_proxy);
552         pos += pb_protocol_serialise_string(pos, config->https_proxy);
553
554         *(uint32_t *)pos = __cpu_to_be32(config->n_autoboot_opts);
555         pos += 4;
556         for (i = 0; i < config->n_autoboot_opts; i++) {
557                 *(uint32_t *)pos =
558                         __cpu_to_be32(config->autoboot_opts[i].boot_type);
559                 pos += 4;
560                 if (config->autoboot_opts[i].boot_type == BOOT_DEVICE_TYPE) {
561                         *(uint32_t *)pos =
562                                 __cpu_to_be32(config->autoboot_opts[i].type);
563                         pos += 4;
564                 } else {
565                         pos += pb_protocol_serialise_string(pos,
566                                                 config->autoboot_opts[i].uuid);
567                 }
568         }
569
570         *(uint32_t *)pos = __cpu_to_be32(config->ipmi_bootdev);
571         pos += 4;
572         *(uint32_t *)pos = config->ipmi_bootdev_persistent;
573         pos += 4;
574
575         *(uint32_t *)pos = config->allow_writes;
576         pos += 4;
577
578         *(uint32_t *)pos = __cpu_to_be32(config->n_consoles);
579         pos += 4;
580         for (i = 0; i < config->n_consoles; i++)
581                 pos += pb_protocol_serialise_string(pos, config->consoles[i]);
582
583         pos += pb_protocol_serialise_string(pos, config->boot_console);
584         *(uint32_t *)pos = config->manual_console;
585         pos += 4;
586
587         pos += pb_protocol_serialise_string(pos, config->lang);
588
589         assert(pos <= buf + buf_len);
590         (void)buf_len;
591
592         return 0;
593 }
594
595 int pb_protocol_serialise_url(const char *url, char *buf, int buf_len)
596 {
597         char *pos = buf;
598
599         pos += pb_protocol_serialise_string(pos, url);
600
601         assert(pos <=buf+buf_len);
602         (void)buf_len;
603
604         return 0;
605 }
606
607 int pb_protocol_write_message(int fd, struct pb_protocol_message *message)
608 {
609         int total_len, rc;
610         char *pos;
611
612         total_len = sizeof(*message) + message->payload_len;
613
614         message->payload_len = __cpu_to_be32(message->payload_len);
615         message->action = __cpu_to_be32(message->action);
616
617         for (pos = (void *)message; total_len;) {
618                 rc = write(fd, pos, total_len);
619
620                 if (rc <= 0)
621                         break;
622
623                 total_len -= rc;
624                 pos += rc;
625         }
626
627         talloc_free(message);
628
629         if (!total_len)
630                 return 0;
631
632         pb_log("%s: failed: %s\n", __func__, strerror(errno));
633         return -1;
634 }
635
636 struct pb_protocol_message *pb_protocol_create_message(void *ctx,
637                 enum pb_protocol_action action, int payload_len)
638 {
639         struct pb_protocol_message *message;
640
641         if (payload_len > PB_PROTOCOL_MAX_PAYLOAD_SIZE) {
642                 pb_log("%s: payload too big %u/%u\n", __func__, payload_len,
643                         PB_PROTOCOL_MAX_PAYLOAD_SIZE);
644                 return NULL;
645         }
646
647         message = talloc_size(ctx, sizeof(*message) + payload_len);
648
649         /* we convert these to big-endian in write_message() */
650         message->action = action;
651         message->payload_len = payload_len;
652
653         return message;
654
655 }
656
657 struct pb_protocol_message *pb_protocol_read_message(void *ctx, int fd)
658 {
659         struct pb_protocol_message *message, m;
660         int rc;
661         unsigned int len;
662
663         /* use the stack for the initial 8-byte read */
664
665         rc = read(fd, &m, sizeof(m));
666         if (rc != sizeof(m))
667                 return NULL;
668
669         m.payload_len = __be32_to_cpu(m.payload_len);
670         m.action = __be32_to_cpu(m.action);
671
672         if (m.payload_len > PB_PROTOCOL_MAX_PAYLOAD_SIZE) {
673                 pb_log("%s: payload too big %u/%u\n", __func__, m.payload_len,
674                         PB_PROTOCOL_MAX_PAYLOAD_SIZE);
675                 return NULL;
676         }
677
678         message = talloc_size(ctx, sizeof(m) + m.payload_len);
679         memcpy(message, &m, sizeof(m));
680
681         for (len = 0; len < m.payload_len;) {
682                 rc = read(fd, message->payload + len, m.payload_len - len);
683
684                 if (rc <= 0) {
685                         talloc_free(message);
686                         pb_log("%s: failed (%u): %s\n", __func__, len,
687                                 strerror(errno));
688                         return NULL;
689                 }
690
691                 len += rc;
692         }
693
694         return message;
695 }
696
697
698 int pb_protocol_deserialise_device(struct device *dev,
699                 const struct pb_protocol_message *message)
700 {
701         unsigned int len;
702         const char *pos;
703         int rc = -1;
704
705         len = message->payload_len;
706         pos = message->payload;
707
708         if (read_string(dev, &pos, &len, &dev->id))
709                 goto out;
710
711         if (len < sizeof(enum device_type))
712                 goto out;
713         dev->type = *(enum device_type *)(pos);
714         pos += sizeof(enum device_type);
715         len -= sizeof(enum device_type);
716
717         if (read_string(dev, &pos, &len, &dev->name))
718                 goto out;
719
720         if (read_string(dev, &pos, &len, &dev->description))
721                 goto out;
722
723         if (read_string(dev, &pos, &len, &dev->icon_file))
724                 goto out;
725
726         rc = 0;
727
728 out:
729         return rc;
730 }
731
732 int pb_protocol_deserialise_boot_option(struct boot_option *opt,
733                 const struct pb_protocol_message *message)
734 {
735         unsigned int len;
736         const char *pos;
737         int rc = -1;
738
739         len = message->payload_len;
740         pos = message->payload;
741
742         if (read_string(opt, &pos, &len, &opt->device_id))
743                 goto out;
744
745         if (read_string(opt, &pos, &len, &opt->id))
746                 goto out;
747
748         if (read_string(opt, &pos, &len, &opt->name))
749                 goto out;
750
751         if (read_string(opt, &pos, &len, &opt->description))
752                 goto out;
753
754         if (read_string(opt, &pos, &len, &opt->icon_file))
755                 goto out;
756
757         if (read_string(opt, &pos, &len, &opt->boot_image_file))
758                 goto out;
759
760         if (read_string(opt, &pos, &len, &opt->initrd_file))
761                 goto out;
762
763         if (read_string(opt, &pos, &len, &opt->dtb_file))
764                 goto out;
765
766         if (read_string(opt, &pos, &len, &opt->boot_args))
767                 goto out;
768
769         if (read_string(opt, &pos, &len, &opt->args_sig_file))
770                 goto out;
771
772         if (len < sizeof(bool))
773                 goto out;
774         opt->is_default = *(bool *)(pos);
775
776         rc = 0;
777
778 out:
779         return rc;
780 }
781
782 int pb_protocol_deserialise_boot_command(struct boot_command *cmd,
783                 const struct pb_protocol_message *message)
784 {
785         unsigned int len;
786         const char *pos;
787         int rc = -1;
788
789         len = message->payload_len;
790         pos = message->payload;
791
792         if (read_string(cmd, &pos, &len, &cmd->option_id))
793                 goto out;
794
795         if (read_string(cmd, &pos, &len, &cmd->boot_image_file))
796                 goto out;
797
798         if (read_string(cmd, &pos, &len, &cmd->initrd_file))
799                 goto out;
800
801         if (read_string(cmd, &pos, &len, &cmd->dtb_file))
802                 goto out;
803
804         if (read_string(cmd, &pos, &len, &cmd->boot_args))
805                 goto out;
806
807         if (read_string(cmd, &pos, &len, &cmd->args_sig_file))
808                 goto out;
809
810         if (read_string(cmd, &pos, &len, &cmd->console))
811                 goto out;
812
813         rc = 0;
814
815 out:
816         return rc;
817 }
818
819 int pb_protocol_deserialise_boot_status(struct status *status,
820                 const struct pb_protocol_message *message)
821 {
822         unsigned int len;
823         const char *pos;
824         int rc = -1;
825
826         len = message->payload_len;
827         pos = message->payload;
828
829         /* first up, the type enum... */
830         if (len < sizeof(uint32_t))
831                 goto out;
832
833         status->type = __be32_to_cpu(*(uint32_t *)(pos));
834
835         switch (status->type) {
836         case STATUS_ERROR:
837         case STATUS_INFO:
838                 break;
839         default:
840                 goto out;
841         }
842
843         pos += sizeof(uint32_t);
844         len -= sizeof(uint32_t);
845
846         /* message string */
847         if (read_string(status, &pos, &len, &status->message))
848                 goto out;
849
850         rc = 0;
851
852 out:
853         return rc;
854 }
855
856 int pb_protocol_deserialise_system_info(struct system_info *sysinfo,
857                 const struct pb_protocol_message *message)
858 {
859         unsigned int len, i;
860         const char *pos;
861         int rc = -1;
862         char *tmp;
863
864         len = message->payload_len;
865         pos = message->payload;
866
867         /* type and identifier strings */
868         if (read_string(sysinfo, &pos, &len, &sysinfo->type))
869                 goto out;
870
871         if (read_string(sysinfo, &pos, &len, &sysinfo->identifier))
872                 goto out;
873
874         /* Platform version strings for openpower platforms */
875         if (read_u32(&pos, &len, &sysinfo->n_primary))
876                 goto out;
877         sysinfo->platform_primary = talloc_array(sysinfo, char *,
878                                                 sysinfo->n_primary);
879         for (i = 0; i < sysinfo->n_primary; i++) {
880                 if (read_string(sysinfo, &pos, &len, &tmp))
881                         goto out;
882                 sysinfo->platform_primary[i] = talloc_strdup(sysinfo, tmp);
883         }
884
885         if (read_u32(&pos, &len, &sysinfo->n_other))
886                 goto out;
887         sysinfo->platform_other = talloc_array(sysinfo, char *,
888                                                 sysinfo->n_other);
889         for (i = 0; i < sysinfo->n_other; i++) {
890                 if (read_string(sysinfo, &pos, &len, &tmp))
891                         goto out;
892                 sysinfo->platform_other[i] = talloc_strdup(sysinfo, tmp);
893         }
894
895         /* BMC version strings for openpower platforms */
896         if (read_u32(&pos, &len, &sysinfo->n_bmc_current))
897                 goto out;
898         sysinfo->bmc_current = talloc_array(sysinfo, char *,
899                                                 sysinfo->n_bmc_current);
900         for (i = 0; i < sysinfo->n_bmc_current; i++) {
901                 if (read_string(sysinfo, &pos, &len, &tmp))
902                         goto out;
903                 sysinfo->bmc_current[i] = talloc_strdup(sysinfo, tmp);
904         }
905
906         if (read_u32(&pos, &len, &sysinfo->n_bmc_golden))
907                 goto out;
908         sysinfo->bmc_golden = talloc_array(sysinfo, char *,
909                                                 sysinfo->n_bmc_golden);
910         for (i = 0; i < sysinfo->n_bmc_golden; i++) {
911                 if (read_string(sysinfo, &pos, &len, &tmp))
912                         goto out;
913                 sysinfo->bmc_golden[i] = talloc_strdup(sysinfo, tmp);
914         }
915
916         /* number of interfaces */
917         if (read_u32(&pos, &len, &sysinfo->n_interfaces))
918                 goto out;
919
920         sysinfo->interfaces = talloc_array(sysinfo, struct interface_info *,
921                         sysinfo->n_interfaces);
922
923         for (i = 0; i < sysinfo->n_interfaces; i++) {
924                 struct interface_info *if_info = talloc(sysinfo,
925                                                         struct interface_info);
926
927                 if (read_u32(&pos, &len, &if_info->hwaddr_size))
928                         goto out;
929
930                 if (len < if_info->hwaddr_size)
931                         goto out;
932
933                 if_info->hwaddr = talloc_memdup(if_info, pos,
934                                                 if_info->hwaddr_size);
935                 pos += if_info->hwaddr_size;
936                 len -= if_info->hwaddr_size;
937
938                 if (read_string(if_info, &pos, &len, &if_info->name))
939                         goto out;
940
941                 if_info->link = *(bool *)pos;
942                 pos += sizeof(if_info->link);
943
944                 sysinfo->interfaces[i] = if_info;
945         }
946
947         /* number of interfaces */
948         if (read_u32(&pos, &len, &sysinfo->n_blockdevs))
949                 goto out;
950
951         sysinfo->blockdevs = talloc_array(sysinfo, struct blockdev_info *,
952                         sysinfo->n_blockdevs);
953
954         for (i = 0; i < sysinfo->n_blockdevs; i++) {
955                 struct blockdev_info *bd_info = talloc(sysinfo,
956                                                         struct blockdev_info);
957
958                 if (read_string(bd_info, &pos, &len, &bd_info->name))
959                         goto out;
960
961                 if (read_string(bd_info, &pos, &len, &bd_info->uuid))
962                         goto out;
963
964                 if (read_string(bd_info, &pos, &len, &bd_info->mountpoint))
965                         goto out;
966
967                 sysinfo->blockdevs[i] = bd_info;
968         }
969
970         for (i = 0; i < HWADDR_SIZE; i++) {
971                 if (pos[i] != 0) {
972                         sysinfo->bmc_mac = talloc_memdup(sysinfo, pos, HWADDR_SIZE);
973                         break;
974                 }
975         }
976
977         pos += HWADDR_SIZE;
978         len -= HWADDR_SIZE;
979
980         rc = 0;
981 out:
982         return rc;
983 }
984
985 static int pb_protocol_deserialise_config_interface(const char **buf,
986                 unsigned int *len, struct interface_config *iface)
987 {
988         unsigned int tmp;
989
990         if (*len < sizeof(iface->hwaddr))
991                 return -1;
992
993         memcpy(iface->hwaddr, *buf, sizeof(iface->hwaddr));
994         *buf += sizeof(iface->hwaddr);
995         *len -= sizeof(iface->hwaddr);
996
997         if (read_u32(buf, len, &tmp))
998                 return -1;
999         iface->ignore = !!tmp;
1000
1001         if (iface->ignore)
1002                 return 0;
1003
1004         if (read_u32(buf, len, &iface->method))
1005                 return -1;
1006
1007         if (iface->method == CONFIG_METHOD_STATIC) {
1008                 if (read_string(iface, buf, len, &iface->static_config.address))
1009                         return -1;
1010
1011                 if (read_string(iface, buf, len, &iface->static_config.gateway))
1012                         return -1;
1013
1014                 if (read_string(iface, buf, len, &iface->static_config.url))
1015                         return -1;
1016         }
1017
1018         if (read_u32(buf, len, &tmp))
1019                 return -1;
1020         iface->override = !!tmp;
1021
1022         return 0;
1023 }
1024
1025 int pb_protocol_deserialise_config(struct config *config,
1026                 const struct pb_protocol_message *message)
1027 {
1028         unsigned int len, i, tmp;
1029         const char *pos;
1030         int rc = -1;
1031         char *str;
1032
1033         len = message->payload_len;
1034         pos = message->payload;
1035
1036         if (read_u32(&pos, &len, &tmp))
1037                 goto out;
1038         config->autoboot_enabled = !!tmp;
1039
1040         if (read_u32(&pos, &len, &config->autoboot_timeout_sec))
1041                 goto out;
1042
1043         if (read_u32(&pos, &len, &tmp))
1044                 goto out;
1045         config->safe_mode = !!tmp;
1046
1047         if (read_u32(&pos, &len, &config->network.n_interfaces))
1048                 goto out;
1049
1050         config->network.interfaces = talloc_array(config,
1051                         struct interface_config *, config->network.n_interfaces);
1052
1053         for (i = 0; i < config->network.n_interfaces; i++) {
1054                 struct interface_config *iface = talloc_zero(
1055                                 config->network.interfaces,
1056                                 struct interface_config);
1057                 if (pb_protocol_deserialise_config_interface(&pos, &len, iface))
1058                         goto out;
1059                 config->network.interfaces[i] = iface;
1060         }
1061
1062         if (read_u32(&pos, &len, &config->network.n_dns_servers))
1063                 goto out;
1064         config->network.dns_servers = talloc_array(config, const char *,
1065                         config->network.n_dns_servers);
1066
1067         for (i = 0; i < config->network.n_dns_servers; i++) {
1068                 if (read_string(config->network.dns_servers, &pos, &len, &str))
1069                         goto out;
1070                 config->network.dns_servers[i] = str;
1071         }
1072
1073         if (read_string(config, &pos, &len, &str))
1074                 goto out;
1075         config->http_proxy = str;
1076         if (read_string(config, &pos, &len, &str))
1077                 goto out;
1078         config->https_proxy = str;
1079
1080         if (read_u32(&pos, &len, &config->n_autoboot_opts))
1081                 goto out;
1082         config->autoboot_opts = talloc_array(config, struct autoboot_option,
1083                         config->n_autoboot_opts);
1084
1085         for (i = 0; i < config->n_autoboot_opts; i++) {
1086                 if (read_u32(&pos, &len, &tmp))
1087                         goto out;
1088                 config->autoboot_opts[i].boot_type = (int)tmp;
1089                 if (config->autoboot_opts[i].boot_type == BOOT_DEVICE_TYPE) {
1090                         if (read_u32(&pos, &len, &tmp))
1091                                 goto out;
1092                         config->autoboot_opts[i].type = tmp;
1093                 } else {
1094                         if (read_string(config, &pos, &len, &str))
1095                                 goto out;
1096                         config->autoboot_opts[i].uuid = str;
1097                 }
1098         }
1099
1100         if (read_u32(&pos, &len, &config->ipmi_bootdev))
1101                 goto out;
1102         if (read_u32(&pos, &len, &tmp))
1103                 goto out;
1104         config->ipmi_bootdev_persistent = !!tmp;
1105
1106         if (read_u32(&pos, &len, &tmp))
1107                 goto out;
1108         config->allow_writes = !!tmp;
1109
1110         if (read_u32(&pos, &len, &config->n_consoles))
1111                 goto out;
1112
1113         config->consoles = talloc_array(config, char *, config->n_consoles);
1114         for (i = 0; i < config->n_consoles; i++) {
1115                 if (read_string(config->consoles, &pos, &len, &str))
1116                         goto out;
1117                 config->consoles[i] = str;
1118         }
1119
1120         if (read_string(config, &pos, &len, &str))
1121                 goto out;
1122
1123         config->boot_console = str;
1124
1125         if (read_u32(&pos, &len, &tmp))
1126                 goto out;
1127         config->manual_console = !!tmp;
1128
1129         if (read_string(config, &pos, &len, &str))
1130                 goto out;
1131
1132         config->lang = str;
1133
1134         rc = 0;
1135
1136 out:
1137         return rc;
1138 }