• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/firmware-utils/src/mkbossimg.c

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * mkbossimg - wrap a firmware image in a Bintec/Teldat BOSS header
  4  *
  5  * Copyright (C) 2009-2013 Sebastien Decourriere <sebtx452@gmail.com>
  6  * Copyright (C) 2026 Simon Wunderlich <sw@simonwunderlich.de>
  7  * Based on mkbrnimg.c
  8  *
  9  * The BOSS bootmonitor found on Bintec elmeg RS-series routers expects a
 10  * 52-byte big-endian header in front of a gzip-compressed image. The board
 11  * family is identified by a magic string, which the bootmonitor reports as
 12  * "Identification" under "Show System Information".
 13  *
 14  * The input file is expected to carry a 52-byte placeholder header, so that
 15  * the payload behind the real header stays aligned to the flash sector size.
 16  * The placeholder is skipped; length and CRC are computed over the remainder.
 17  */
 18 
 19 #include <arpa/inet.h>
 20 #include <errno.h>
 21 #include <fcntl.h>
 22 #include <inttypes.h>
 23 #include <stdio.h>
 24 #include <stdlib.h>
 25 #include <string.h>
 26 #include <sys/mman.h>
 27 #include <sys/stat.h>
 28 #include <unistd.h>
 29 #include <zlib.h>
 30 
 31 /* Image types */
 32 #define IMG_TYPE_BOSS           0x00 /* Compressed BOSS */
 33 #define IMG_TYPE_UBOSS          0x01 /* Uncompressed BOSS (uBoss) */
 34 #define IMG_TYPE_LOGIC          0x02 /* Logic aka first bootloader */
 35 #define IMG_TYPE_BOOTMON        0x03 /* Bootmonitor aka second bootloader */
 36 #define IMG_TYPE_FIRMWARE       0x04 /* Firmware (unknown) */
 37 
 38 #define IMG_VER         0x00000000
 39 
 40 /*
 41  * In vendor images the two fields called "unknown" here hold the length and
 42  * CRC of an uncompressed section. For gzip images the bootmonitor accepts the
 43  * values below, which is what the original tool always wrote.
 44  */
 45 #define UNKNOWN_1       0x00FA0524
 46 #define UNKNOWN_2       0x00000000
 47 #define UNKNOWN_3       0x00000000
 48 
 49 /* Version 42, high enough that the vendor web UI accepts the upgrade */
 50 #define FW_VERSION      0x002A0000
 51 
 52 #define MAGIC_CHAOSENDDRAGON    "BINTEC ChaosEndDragon"
 53 #define MAGIC_CLOSEDEYEVISUAL   "TELDAT ClosedEyeVisual"
 54 
 55 struct boss_header {
 56         char magic[23];
 57         uint32_t fw_version;
 58         uint8_t image_type;
 59         uint32_t image_version;
 60         uint32_t image_length;
 61         uint32_t unknown1;
 62         uint32_t unknown2;
 63         uint32_t crc32;
 64         uint32_t unknown3;
 65 } __attribute__((packed));
 66 
 67 static const struct board {
 68         const char *name;
 69         const char *magic;
 70 } boards[] = {
 71         /*
 72          * Verified on the device itself via the bootmonitor's
 73          * "Show System Information" -> "Identification:" field.
 74          */
 75         { "rs123", MAGIC_CLOSEDEYEVISUAL },
 76         { "rs230", MAGIC_CHAOSENDDRAGON  },
 77         { "rs353", MAGIC_CLOSEDEYEVISUAL },
 78 };
 79 
 80 static void usage(const char *mess)
 81 {
 82         size_t i;
 83 
 84         fprintf(stderr, "Error: %s\n", mess);
 85         fprintf(stderr, "Usage: mkbossimg <board> <input file> <output file>\n");
 86         fprintf(stderr, "Supported boards:");
 87         for (i = 0; i < sizeof(boards) / sizeof(boards[0]); i++)
 88                 fprintf(stderr, " %s", boards[i].name);
 89         fprintf(stderr, "\n");
 90         exit(1);
 91 }
 92 
 93 static ssize_t write_all(int fd, const void *buf, size_t len)
 94 {
 95         const char *p = buf;
 96         size_t done = 0;
 97 
 98         while (done < len) {
 99                 ssize_t n = write(fd, p + done, len - done);
100 
101                 if (n < 0) {
102                         if (errno == EINTR)
103                                 continue;
104                         return -1;
105                 }
106                 done += (size_t)n;
107         }
108         return (ssize_t)done;
109 }
110 
111 int main(int argc, char **argv)
112 {
113         const char *board_name, *in_path, *out_path;
114         const char *magic = NULL;
115         struct boss_header hdr;
116         struct stat st;
117         char *map, *payload;
118         size_t payload_len;
119         uint32_t crc;
120         size_t i;
121         int fd, outfd;
122 
123         if (argc != 4)
124                 usage("wrong number of arguments");
125 
126         board_name = argv[1];
127         in_path = argv[2];
128         out_path = argv[3];
129 
130         for (i = 0; i < sizeof(boards) / sizeof(boards[0]); i++) {
131                 if (strcmp(board_name, boards[i].name) == 0) {
132                         magic = boards[i].magic;
133                         break;
134                 }
135         }
136         if (!magic) {
137                 fprintf(stderr, "Invalid board type '%s'\n", board_name);
138                 usage("unknown board");
139         }
140 
141         fd = open(in_path, O_RDONLY);
142         if (fd < 0 || fstat(fd, &st) < 0) {
143                 fprintf(stderr, "Error opening '%s': %s\n", in_path, strerror(errno));
144                 exit(1);
145         }
146         if ((size_t)st.st_size <= sizeof(hdr)) {
147                 fprintf(stderr, "Input '%s' is too small (%ju bytes)\n",
148                         in_path, (uintmax_t)st.st_size);
149                 exit(1);
150         }
151 
152         map = mmap(NULL, (size_t)st.st_size, PROT_READ, MAP_SHARED, fd, 0);
153         if (map == MAP_FAILED) {
154                 fprintf(stderr, "Error mapping '%s': %s\n", in_path, strerror(errno));
155                 exit(1);
156         }
157         close(fd);
158 
159         /* Skip the placeholder header that pads the payload to a sector */
160         payload = map + sizeof(hdr);
161         payload_len = (size_t)st.st_size - sizeof(hdr);
162 
163         if (!((unsigned char)payload[0] == 0x1F && (unsigned char)payload[1] == 0x8B)) {
164                 fprintf(stderr, "Invalid image type: expected gzip magic, got %02X %02X\n",
165                         (unsigned char)payload[0], (unsigned char)payload[1]);
166                 exit(1);
167         }
168 
169         memset(&hdr, 0, sizeof(hdr));
170         strncpy(hdr.magic, magic, sizeof(hdr.magic) - 1);
171         hdr.fw_version = htonl(FW_VERSION);
172         hdr.image_type = IMG_TYPE_BOSS;
173         hdr.image_version = htonl(IMG_VER);
174         hdr.unknown1 = htonl(UNKNOWN_1);
175         hdr.unknown2 = htonl(UNKNOWN_2);
176         hdr.unknown3 = htonl(UNKNOWN_3);
177 
178         crc = crc32(0, (const unsigned char *)payload, payload_len);
179         hdr.image_length = htonl((uint32_t)payload_len);
180         hdr.crc32 = htonl(crc);
181 
182         fprintf(stderr, "Board '%s' magic '%s', crc32 %08x, length %08zx\n",
183                 board_name, magic, crc, payload_len);
184 
185         outfd = open(out_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
186         if (outfd < 0) {
187                 fprintf(stderr, "Error opening '%s' for writing: %s\n",
188                         out_path, strerror(errno));
189                 exit(1);
190         }
191         if (write_all(outfd, &hdr, sizeof(hdr)) < 0 ||
192             write_all(outfd, payload, payload_len) < 0) {
193                 fprintf(stderr, "Error writing '%s': %s\n", out_path, strerror(errno));
194                 exit(1);
195         }
196         close(outfd);
197         munmap(map, (size_t)st.st_size);
198 
199         return EXIT_SUCCESS;
200 }
201 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt