1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * zytrx - add header to images for ZyXEL NR7101 4 * 5 * Based on add_header.c - partially based on OpenWrt's 6 * motorola-bin.c 7 * 8 * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org> 9 * Gabor Juhos <juhosg@openwrt.org> 10 * Copyright (C) 2021 Bjørn Mork <bjorn@mork.no> 11 */ 12 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <stddef.h> 16 #include <unistd.h> 17 #include <errno.h> 18 #include <fcntl.h> 19 #include <sys/mman.h> 20 #include <sys/stat.h> 21 #include <string.h> 22 #include <netinet/in.h> 23 #include <inttypes.h> 24 25 #define BPB 8 /* bits/byte */ 26 27 static uint32_t crc32[1<<BPB]; 28 29 static void init_crc32(void) 30 { 31 const uint32_t poly = ntohl(0x2083b8ed); 32 int n; 33 34 for (n = 0; n < 1<<BPB; n++) { 35 uint32_t crc = n; 36 int bit; 37 38 for (bit = 0; bit < BPB; bit++) 39 crc = (crc & 1) ? (poly ^ (crc >> 1)) : (crc >> 1); 40 crc32[n] = crc; 41 } 42 } 43 44 static uint32_t crc32buf(const unsigned char *buf, size_t len) 45 { 46 uint32_t crc = 0xFFFFFFFF; 47 48 for (; len; len--, buf++) 49 crc = crc32[(uint8_t)crc ^ *buf] ^ (crc >> BPB); 50 return ~crc; 51 } 52 53 /* HDR0 reversed, to be stored as BE */ 54 #define MAGIC 0x30524448 /* HDR0 reversed, to be stored as BE */ 55 56 /* All numbers are stored as BE */ 57 struct zytrx_t { 58 uint32_t magic; 59 uint32_t len_h; /* Length of this header */ 60 uint32_t len_t; /* Total length of file */ 61 uint32_t crc32_p; /* Bit inverted 32-bit CRC of image payload */ 62 uint8_t verInt[32]; /* String "5.0.0.0\n" zero padded */ 63 uint8_t verExt[32]; /* String "\n" zero padded */ 64 uint32_t len_p; /* Length of image payload */ 65 uint8_t pad1[12]; /* zero padding(?) */ 66 uint8_t code[164]; /* string "3 6035 122 0\n" zero padded */ 67 uint8_t chipid[8]; /* string "MT7621A" zero padded */ 68 uint8_t boardid[16]; /* string "NR7101" zero padded */ 69 uint32_t modelid; /* modelid as 4 BCD digits: 0x07010001 */ 70 uint8_t pad2[8]; /* zero padding(?) */ 71 uint8_t swVersionInt[32]; /* ZyXEL version string: "1.00(ABUV.0)D0" zero padded */ 72 uint8_t swVersionExt[32]; /* identical to swVersionInt */ 73 uint8_t pad4[4]; /* zero padding(?) */ 74 uint32_t kernelChksum; /* no idea how this is computed - reported but not validated */ 75 uint8_t pad5[4]; /* zero padding(?) */ 76 uint32_t crc32_h; /* Bit inverted 32-bit CRC of this header payload */ 77 uint8_t pad6[4]; /* zero padding(?) */ 78 }; 79 80 /* static?() field values of unknown meaning - maybe ove to board 81 * table when we know the significance 82 */ 83 #define VER_INT "5.0.0.0\n" 84 #define VER_EXT "\n" 85 #define CODE "3 6035 122 0\n" 86 #define KERNELCHKSUM 0x12345678 87 88 /* table of supported devices using this header format */ 89 static struct board_t { 90 uint8_t chipid[8]; 91 uint8_t boardid[16]; 92 uint32_t modelid; 93 } boards[] = { 94 { "MT7621A", "NR7101", 0x07010001 }, 95 { "MT7621A", "LTE3301-PLUS", 0x03030001 }, 96 { "MT7621A", "LTE5398-M904", 0x05030908 }, 97 { "MT7621A", "LTE7490-M904", 0x07040900 }, 98 {} 99 }; 100 101 static int find_board(struct zytrx_t *h, char *board) 102 { 103 struct board_t *p; 104 105 for (p = boards; p->modelid; p++) { 106 if (strncmp((const char *)p->boardid, board, sizeof(p->boardid))) 107 continue; 108 memcpy(h->chipid, p->chipid, sizeof(h->chipid)); 109 memcpy(h->boardid, p->boardid, sizeof(h->boardid)); 110 h->modelid = htonl(p->modelid); 111 return 0; 112 } 113 return -1; 114 } 115 116 static void usage(const char *name) 117 { 118 struct board_t *p; 119 120 fprintf(stderr, "Usage:\n"); 121 fprintf(stderr, " %s -B <board> -v <versionstr> -i <file> [-o <outputfile>]\n\n", name); 122 fprintf(stderr, "Supported <board> values:\n"); 123 for (p = boards; p->modelid; p++) 124 fprintf(stderr, "\t%-12s\n", p->boardid); 125 fprintf(stderr, "\nExample:\n"); 126 fprintf(stderr, " %s -B %s -v foobar-1.0 -i my.img -o out.img\n\n", name, 127 boards[0].boardid); 128 exit(EXIT_FAILURE); 129 } 130 131 static void errexit(const char *msg) 132 { 133 fprintf(stderr, "ERR: %s: %s\n", msg, errno ? strerror(errno) : "unknown"); 134 exit(EXIT_FAILURE); 135 } 136 137 static void *map_input(const char *name, size_t *len) 138 { 139 struct stat stat; 140 void *mapped; 141 int fd; 142 143 fd = open(name, O_RDONLY); 144 if (fd < 0) 145 return NULL; 146 if (fstat(fd, &stat) < 0) { 147 close(fd); 148 return NULL; 149 } 150 *len = stat.st_size; 151 mapped = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd, 0); 152 if (close(fd) < 0) { 153 (void) munmap(mapped, stat.st_size); 154 return NULL; 155 } 156 return mapped; 157 } 158 159 int main(int argc, char **argv) 160 { 161 int c, fdout = STDOUT_FILENO; 162 void *input_file = NULL; 163 size_t file_len, len; 164 uint32_t crc; 165 struct zytrx_t h = { 166 .magic = htonl(MAGIC), 167 .len_h = htonl(sizeof(h)), 168 .verInt = VER_INT, 169 .verExt = VER_EXT, 170 .code = CODE, 171 .kernelChksum = htonl(KERNELCHKSUM), 172 }; 173 174 while ((c = getopt(argc, argv, "B:v:i:o:")) != -1) { 175 switch (c) { 176 case 'B': 177 if (find_board(&h, optarg) < 0) 178 errexit("unsupported board"); 179 break; 180 case 'v': 181 len = strlen(optarg); 182 if (len > sizeof(h.swVersionInt)) 183 errexit("version string too long"); 184 memcpy(h.swVersionInt, optarg, len); 185 memcpy(h.swVersionExt, optarg, len); 186 break; 187 case 'i': 188 input_file = map_input(optarg, &file_len); 189 if (!input_file) 190 errexit(optarg); 191 break; 192 case 'o': 193 fdout = open(optarg, O_WRONLY | O_CREAT, 0644); 194 if (fdout < 0) 195 errexit(optarg); 196 break; 197 default: 198 usage(argv[0]); 199 } 200 } 201 202 /* required paremeters */ 203 if (!input_file || !h.modelid || !h.swVersionInt[0]) 204 usage(argv[0]); 205 206 /* length fields */ 207 h.len_t = htonl(sizeof(h) + file_len); 208 h.len_p = htonl(file_len); 209 210 /* crc fields */ 211 init_crc32(); 212 crc = crc32buf(input_file, file_len); 213 h.crc32_p = htonl(~crc); 214 crc = crc32buf((unsigned char *)&h, sizeof(h)); 215 h.crc32_h = htonl(~crc); 216 217 /* dump new image */ 218 write(fdout, &h, sizeof(h)); 219 write(fdout, input_file, file_len); 220 221 /* close files */ 222 munmap(input_file, file_len); 223 if (fdout != STDOUT_FILENO) 224 close(fdout); 225 226 return EXIT_SUCCESS; 227 } 228
This page was automatically generated by LXR 0.3.1. • OpenWrt