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

Sources/firmware-utils/src/iptime-naspkg.c

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Copyright (c) 2020 Sungbo Eo <mans0n@gorani.run>
  4  *
  5  * This code is based on mkdhpimg.c and mkzcfw.c
  6  * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
  7  * Copyright (c) 2016 FUKAUMI Naoki <naobsd@gmail.com>
  8  *
  9  * Checksum algorithm is derived from EFM's mknas utility
 10  * found in GPL'ed T16000 source.
 11  */
 12 
 13 #include <byteswap.h>
 14 #include <endian.h>
 15 #include <err.h>
 16 #include <errno.h>
 17 #include <fcntl.h>
 18 #include <stdint.h>
 19 #include <stdio.h>
 20 #include <stdlib.h>
 21 #include <string.h>
 22 #include <sys/stat.h>
 23 #include <time.h>
 24 #include <unistd.h>
 25 
 26 #if !defined(__BYTE_ORDER)
 27 #error "Unknown byte order"
 28 #endif
 29 
 30 #if (__BYTE_ORDER == __BIG_ENDIAN)
 31 #define HOST_TO_LE32(x) bswap_32(x)
 32 #elif (__BYTE_ORDER == __LITTLE_ENDIAN)
 33 #define HOST_TO_LE32(x) (x)
 34 #else
 35 #error "Unsupported endianness"
 36 #endif
 37 
 38 #define FW_HEADER_SIZE  0x400
 39 #define FW_VERSION      "0.0.00"
 40 #define FW_MAGIC        "EFM_NAS_PKG"
 41 
 42 struct fw_header {
 43         uint8_t model[32];
 44         uint8_t version[32];
 45         uint8_t ctime[32];
 46         uint32_t size;
 47         uint32_t checksum;
 48         uint32_t offset_header;
 49         uint32_t offset_rootfs;
 50         uint32_t offset_app;
 51         uint32_t checksum_kr;
 52         uint8_t magic[16];
 53 
 54         uint32_t size_kra;
 55         uint32_t checksum_kra;
 56         uint32_t offset_ext;
 57 } __attribute__ ((packed));
 58 
 59 enum board_type {
 60         BOARD_KIRKWOOD,
 61         BOARD_ARMADA380,
 62 };
 63 
 64 struct board_type_info {
 65         int bootloader_size;
 66         int block_size;
 67 };
 68 
 69 struct board_info {
 70         const char *model;
 71         enum board_type type;
 72 };
 73 
 74 struct board_type_info board_types[] = {
 75         /* BOARD_KIRKWOOD */
 76         { .bootloader_size = 0x40000, .block_size = 0x0 },
 77         /* BOARD_ARMADA380 */
 78         { .bootloader_size = 0x100000, .block_size = 0x10000 },
 79 };
 80 
 81 struct board_info boards[] = {
 82         { .model = "nas1", .type = BOARD_KIRKWOOD },
 83         { .model = "nas1dual", .type = BOARD_ARMADA380 },
 84         { /* sentinel */ }
 85 };
 86 
 87 struct board_info *find_board(const char *model)
 88 {
 89         struct board_info *ret = NULL;
 90         struct board_info *board;
 91 
 92         for (board = boards; board->model != NULL; board++) {
 93                 if (strcmp(model, board->model) == 0) {
 94                         ret = board;
 95                         break;
 96                 }
 97         }
 98 
 99         return ret;
100 }
101 
102 /* (FW_HEADER_SIZE + size_in + padding) % block_size == 0 */
103 size_t calc_padding(enum board_type type, size_t size_in)
104 {
105         int block_size, remainder;
106 
107         block_size = board_types[type].block_size;
108         if (block_size == 0)
109                 return 0;
110         remainder = (FW_HEADER_SIZE + size_in) % block_size;
111         return remainder ? block_size - remainder : 0;
112 }
113 
114 char *get_ctime(void)
115 {
116         char *env = getenv("SOURCE_DATE_EPOCH");
117         char *endptr = env;
118         time_t timestamp = -1;
119 
120         if (env && *env) {
121                 errno = 0;
122                 timestamp = strtoull(env, &endptr, 10);
123 
124                 if (errno || (endptr && *endptr != '\0')) {
125                         fprintf(stderr, "Invalid SOURCE_DATE_EPOCH\n");
126                         timestamp = -1;
127                 }
128         }
129 
130         if (timestamp == -1)
131                 time(&timestamp);
132 
133         return asctime(gmtime(&timestamp));
134 }
135 
136 uint32_t make_checksum(const char *model_name, uint8_t *bytes, int length)
137 {
138         int i;
139         uint32_t sum = 0;
140         uint32_t magic = 0x19283745;
141 
142         for (i = 0; i < length; i++)
143                 sum += bytes[i];
144         return ((uint32_t)strlen(model_name) * magic + ~sum) ^ sum;
145 }
146 
147 void make_header(struct board_info *board, uint8_t *buffer, size_t img_size)
148 {
149         struct fw_header *header = (struct fw_header *)buffer;
150         char *time_created;
151         uint32_t checksum;
152         size_t bootloader_size, image_end_offset;
153 
154         time_created = get_ctime();
155         checksum = make_checksum(board->model, buffer + FW_HEADER_SIZE, img_size);
156         bootloader_size = board_types[board->type].bootloader_size;
157         image_end_offset = bootloader_size + FW_HEADER_SIZE + img_size;
158 
159         strncpy((char *)header->model, board->model, sizeof(header->model)-1);
160         strncpy((char *)header->version, FW_VERSION, sizeof(header->version)-1);
161         strncpy((char *)header->ctime, time_created, sizeof(header->ctime)-1);
162         header->size = HOST_TO_LE32(img_size);
163         header->checksum = HOST_TO_LE32(checksum);
164         header->offset_header = HOST_TO_LE32(bootloader_size);
165         header->offset_rootfs = HOST_TO_LE32(image_end_offset);
166         header->offset_app = HOST_TO_LE32(image_end_offset);
167         header->checksum_kr = HOST_TO_LE32(checksum);
168         strncpy((char *)header->magic, FW_MAGIC, sizeof(header->magic)-1);
169 
170         if (board->type == BOARD_ARMADA380) {
171                 header->size_kra = HOST_TO_LE32(img_size);
172                 header->checksum_kra = HOST_TO_LE32(checksum);
173                 header->offset_ext = HOST_TO_LE32(image_end_offset);
174         }
175 }
176 
177 int main(int argc, const char *argv[])
178 {
179         const char *model_name, *img_in, *img_out;
180         struct board_info *board;
181         int file_in, file_out;
182         struct stat stat_in;
183         size_t size_in, size_in_padded, size_out;
184         uint8_t *buffer;
185 
186         if (argc != 4) {
187                 fprintf(stderr, "Usage: %s <model> <input> <output>\n", argv[0]);
188                 return EXIT_FAILURE;
189         }
190         model_name = argv[1];
191         img_in = argv[2];
192         img_out = argv[3];
193 
194         board = find_board(model_name);
195         if (board == NULL) {
196                 fprintf(stderr, "%s: Not supported model\n", model_name);
197                 return EXIT_FAILURE;
198         }
199 
200         if ((file_in = open(img_in, O_RDONLY)) == -1)
201                 err(EXIT_FAILURE, "%s", img_in);
202 
203         if (fstat(file_in, &stat_in) == -1)
204                 err(EXIT_FAILURE, "%s", img_in);
205 
206         size_in = stat_in.st_size;
207         size_in_padded = size_in + calc_padding(board->type, size_in);
208         size_out = FW_HEADER_SIZE + size_in_padded;
209 
210         if ((buffer = malloc(size_out)) == NULL)
211                 err(EXIT_FAILURE, "malloc");
212 
213         read(file_in, buffer + FW_HEADER_SIZE, size_in);
214         close(file_in);
215 
216         memset(buffer, 0, FW_HEADER_SIZE);
217 
218         make_header(board, buffer, size_in_padded);
219 
220         if ((file_out = creat(img_out, 0644)) == -1)
221                 err(EXIT_FAILURE, "%s", img_out);
222         write(file_out, buffer, size_out);
223         close(file_out);
224 
225         free(buffer);
226 
227         return EXIT_SUCCESS;
228 }
229 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt