├── .gitlab-ci.yml ├── src ├── utils.h ├── sha1.h ├── md5.h ├── fw.h ├── mkdhpimg.c ├── csysimg.h ├── mktplinkfw-lib.h ├── mkdlinkfw-lib.h ├── bcmalgo.h ├── nec-enc.c ├── bcm4908kernel.c ├── seama.h ├── add_header.c ├── mkdlinkfw-lib.c ├── imagetag.ggo ├── xorimage.c ├── encode_crc.c ├── zyimage.c ├── cyg_crc.h ├── buffalo-tftp.c ├── uimage_padhdr.c ├── nosimg-enc.c ├── buffalo-lib.h ├── mkbrncmdline.c ├── linksys-addfwhdr.c ├── bcm_tag.h ├── avm-wasp-checksum.c ├── iptime-crc32.c ├── uimage_sgehdr.c ├── mkdniimg.c ├── mkbrnimg.c ├── dgn3500sum.c ├── mkbuffaloimg.c ├── lzma2eva.c ├── mkheader_gemtek.c ├── cyg_crc16.c ├── sign_dlink_ru.c ├── mkwrgimg.c ├── myloader.h ├── mkdapimg2.c ├── mkplanexfw.c ├── mktplinkfw-lib.c ├── motorola-bin.c ├── nand_ecc.c ├── mkdapimg.c ├── iptime-naspkg.c ├── mkqdimg.c ├── zytrx.c ├── hcsmakeimage.c └── mksercommfw.c └── CMakeLists.txt /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | include: 2 | - remote: https://gitlab.com/ynezz/openwrt-ci/raw/master/openwrt-ci/gitlab/main.yml 3 | 4 | various native checks: 5 | extends: .openwrt-native-build 6 | -------------------------------------------------------------------------------- /src/utils.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | #include 3 | #include 4 | 5 | #pragma once 6 | 7 | #define FW_MEMCPY_STR(dst, src) \ 8 | do { \ 9 | size_t slen = strlen(src); \ 10 | size_t dlen = sizeof(dst); \ 11 | memcpy(dst, src, slen > dlen ? dlen : slen); \ 12 | } while (0); 13 | -------------------------------------------------------------------------------- /src/sha1.h: -------------------------------------------------------------------------------- 1 | #ifndef _SHA1_H 2 | #define _SHA1_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #ifndef _STD_TYPES 9 | #define _STD_TYPES 10 | 11 | #define uchar unsigned char 12 | #define uint unsigned int 13 | #define ulong unsigned long int 14 | 15 | #endif 16 | 17 | typedef struct 18 | { 19 | ulong total[2]; 20 | ulong state[5]; 21 | uchar buffer[64]; 22 | } 23 | sha1_context; 24 | 25 | /* 26 | * Core SHA-1 functions 27 | */ 28 | void sha1_starts( sha1_context *ctx ); 29 | void sha1_update( sha1_context *ctx, void *input, uint length ); 30 | void sha1_finish( sha1_context *ctx, uchar digest[20] ); 31 | 32 | /* 33 | * Output SHA-1(file contents), returns 0 if successful. 34 | */ 35 | int sha1_file( char *filename, uchar digest[20] ); 36 | 37 | /* 38 | * Output SHA-1(buf) 39 | */ 40 | void sha1_csum( uchar *buf, uint buflen, uchar digest[20] ); 41 | 42 | /* 43 | * Output HMAC-SHA-1(key,buf) 44 | */ 45 | void sha1_hmac( uchar *key, uint keylen, uchar *buf, uint buflen, 46 | uchar digest[20] ); 47 | 48 | /* 49 | * Checkup routine 50 | */ 51 | int sha1_self_test( void ); 52 | 53 | #ifdef __cplusplus 54 | } 55 | #endif 56 | 57 | #endif /* sha1.h */ 58 | -------------------------------------------------------------------------------- /src/md5.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. 3 | * MD5 Message-Digest Algorithm (RFC 1321). 4 | * 5 | * Homepage: 6 | * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 7 | * 8 | * Author: 9 | * Alexander Peslyak, better known as Solar Designer 10 | * 11 | * This software was written by Alexander Peslyak in 2001. No copyright is 12 | * claimed, and the software is hereby placed in the public domain. 13 | * In case this attempt to disclaim copyright and place the software in the 14 | * public domain is deemed null and void, then the software is 15 | * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the 16 | * general public under the following terms: 17 | * 18 | * Redistribution and use in source and binary forms, with or without 19 | * modification, are permitted. 20 | * 21 | * There's ABSOLUTELY NO WARRANTY, express or implied. 22 | * 23 | * See md5.c for more information. 24 | */ 25 | 26 | #ifdef HAVE_OPENSSL 27 | #include 28 | #elif !defined(_MD5_H) 29 | #define _MD5_H 30 | 31 | /* Any 32-bit or wider unsigned integer data type will do */ 32 | typedef unsigned int MD5_u32plus; 33 | 34 | typedef struct { 35 | MD5_u32plus lo, hi; 36 | MD5_u32plus a, b, c, d; 37 | unsigned char buffer[64]; 38 | MD5_u32plus block[16]; 39 | } MD5_CTX; 40 | 41 | extern void MD5_Init(MD5_CTX *ctx); 42 | extern void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size); 43 | extern void MD5_Final(unsigned char *result, MD5_CTX *ctx); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/fw.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * * Copyright (C) 2007 Ubiquiti Networks, Inc. 4 | */ 5 | 6 | #ifndef FW_INCLUDED 7 | #define FW_INCLUDED 8 | 9 | #include 10 | #include 11 | 12 | #define MAGIC_HEADER "OPEN" 13 | #define MAGIC_PART "PART" 14 | #define MAGIC_END "END." 15 | #define MAGIC_ENDS "ENDS" 16 | 17 | #define MAGIC_LENGTH 4 18 | #define PART_NAME_LENGTH 16 19 | 20 | typedef struct header { 21 | char magic[MAGIC_LENGTH]; 22 | char version[256]; 23 | u_int32_t crc; 24 | u_int32_t pad; 25 | } __attribute__ ((packed)) header_t; 26 | 27 | typedef struct part { 28 | char magic[MAGIC_LENGTH]; 29 | char name[PART_NAME_LENGTH]; 30 | uint8_t pad[12]; 31 | u_int32_t memaddr; 32 | u_int32_t index; 33 | u_int32_t baseaddr; 34 | u_int32_t entryaddr; 35 | u_int32_t data_size; 36 | u_int32_t part_size; 37 | } __attribute__ ((packed)) part_t; 38 | 39 | typedef struct part_crc { 40 | u_int32_t crc; 41 | u_int32_t pad; 42 | } __attribute__ ((packed)) part_crc_t; 43 | 44 | typedef struct signature { 45 | uint8_t magic[MAGIC_LENGTH]; 46 | u_int32_t crc; 47 | u_int32_t pad; 48 | } __attribute__ ((packed)) signature_t; 49 | 50 | typedef struct signature_rsa { 51 | uint8_t magic[MAGIC_LENGTH]; 52 | // u_int32_t crc; 53 | unsigned char rsa_signature[256]; 54 | u_int32_t pad; 55 | } __attribute__ ((packed)) signature_rsa_t; 56 | 57 | #define VERSION "1.2" 58 | 59 | #define INFO(...) fprintf(stdout, __VA_ARGS__) 60 | #define ERROR(...) fprintf(stderr, "ERROR: "__VA_ARGS__) 61 | #define WARN(...) fprintf(stderr, "WARN: "__VA_ARGS__) 62 | #define DEBUG(...) do {\ 63 | if (debug) \ 64 | fprintf(stdout, "DEBUG: "__VA_ARGS__); \ 65 | } while (0); 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /src/mkdhpimg.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright (c) 2016 FUKAUMI Naoki 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "buffalo-lib.h" 16 | 17 | #define DHP_HEADER_SIZE 20 18 | 19 | static char *progname; 20 | 21 | static void 22 | usage(void) 23 | { 24 | 25 | fprintf(stderr, "usage: %s \n", progname); 26 | exit(EXIT_FAILURE); 27 | } 28 | 29 | int 30 | main(int argc, char *argv[]) 31 | { 32 | struct stat in_st; 33 | size_t size; 34 | uint32_t crc; 35 | int in, out; 36 | uint8_t *buf; 37 | 38 | progname = argv[0]; 39 | 40 | if (argc != 3) 41 | usage(); 42 | 43 | if ((in = open(argv[1], O_RDONLY)) == -1) 44 | err(EXIT_FAILURE, "%s", argv[1]); 45 | 46 | if (fstat(in, &in_st) == -1) 47 | err(EXIT_FAILURE, "%s", argv[1]); 48 | 49 | size = DHP_HEADER_SIZE + in_st.st_size; 50 | 51 | if ((buf = malloc(size)) == NULL) 52 | err(EXIT_FAILURE, "malloc"); 53 | 54 | memset(buf, 0, DHP_HEADER_SIZE); 55 | buf[0x0] = 0x62; 56 | buf[0x1] = 0x67; 57 | buf[0x2] = 0x6e; 58 | buf[0xb] = 0xb1; 59 | buf[0xc] = (size >> 24) & 0xff; 60 | buf[0xd] = (size >> 16) & 0xff; 61 | buf[0xe] = (size >> 8) & 0xff; 62 | buf[0xf] = size & 0xff; 63 | 64 | read(in, &buf[DHP_HEADER_SIZE], in_st.st_size); 65 | close(in); 66 | 67 | crc = buffalo_crc(buf, size); 68 | buf[0x10] = (crc >> 24) & 0xff; 69 | buf[0x11] = (crc >> 16) & 0xff; 70 | buf[0x12] = (crc >> 8) & 0xff; 71 | buf[0x13] = crc & 0xff; 72 | 73 | if ((out = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1) 74 | err(EXIT_FAILURE, "%s", argv[2]); 75 | write(out, buf, size); 76 | close(out); 77 | 78 | free(buf); 79 | 80 | return EXIT_SUCCESS; 81 | } 82 | -------------------------------------------------------------------------------- /src/csysimg.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * 4 | * Copyright (C) 2007,2009 Gabor Juhos 5 | * 6 | * This program was based on the code found in various Linux 7 | * source tarballs released by Edimax for it's devices. 8 | * Original author: David Hsu 9 | */ 10 | 11 | #define SIG_LEN 4 12 | 13 | #define ADM_CODE_ADDR 0x80500000 14 | #define ADM_WEBP_ADDR 0x10000 15 | #define ADM_WEBP_SIZE 0x10000 16 | #define ADM_BOOT_SIZE 0x8000 17 | #define ADM_CONF_SIZE 0x8000 18 | #define ADM_BOOT_SIG "\x00\x60\x1A\x40" 19 | 20 | 21 | /* 22 | * Generic signatures 23 | */ 24 | #define SIG_CSYS "CSYS" 25 | #define SIG_CONF "HS\x00\x00" 26 | #define SIG_BOOT_RTL "\x00\x00\x40\x21" 27 | 28 | /* 29 | * Web page signatures 30 | */ 31 | #define SIG_BR6104K "WB4K" 32 | #define SIG_BR6104KP "WBKP" 33 | #define SIG_BR6104Wg "WBGW" 34 | #define SIG_BR6104IPC "WBIP" 35 | #define SIG_BR6114WG SIG_BR6104IPC 36 | #define SIG_BR6524K "2-K-" 37 | #define SIG_BR6524KP "2-KP" /* FIXME: valid? */ 38 | #define SIG_BR6524N "WNRA" 39 | #define SIG_BR6524WG "2-WG" /* FIXME: valid? */ 40 | #define SIG_BR6524WP "2-WP" /* FIXME: valid? */ 41 | #define SIG_BR6541K "4--K" 42 | #define SIG_BR6541KP "4-KP" /* FIXME: valid? */ 43 | #define SIG_BR6541WP "4-WP" /* FIXME: valid? */ 44 | #define SIG_C54BSR4 SIG_BR6104IPC 45 | #define SIG_EW7207APg "EWAS" 46 | #define SIG_PS1205UWg "4000" 47 | #define SIG_PS3205U "5010" 48 | #define SIG_PS3205UWg "5011" 49 | #define SIG_RALINK "RNRA" 50 | #define SIG_5GXI "5GXI" /* fake signature */ 51 | 52 | #define SIG_H2BR4 SIG_BR6524K 53 | #define SIG_H2WR54G SIG_BR6524WG 54 | 55 | #define SIG_XRT401D SIG_BR6104K 56 | #define SIG_XRT402D SIG_BR6524K 57 | 58 | /* 59 | * CSYS image file header 60 | */ 61 | struct csys_header { 62 | unsigned char sig[SIG_LEN]; 63 | uint32_t addr; 64 | uint32_t size; 65 | }; 66 | -------------------------------------------------------------------------------- /src/mktplinkfw-lib.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright (C) 2009 Gabor Juhos 4 | * 5 | * This tool was based on: 6 | * TP-Link WR941 V2 firmware checksum fixing tool. 7 | * Copyright (C) 2008,2009 Wang Jian 8 | */ 9 | 10 | 11 | #ifndef mktplinkfw_lib_h 12 | #define mktplinkfw_lib_h 13 | 14 | #define ALIGN(x,a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); }) 15 | #define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0])) 16 | 17 | #define MD5SUM_LEN 16 18 | 19 | /* 20 | * Message macros 21 | */ 22 | #define ERR(fmt, ...) do { \ 23 | fflush(0); \ 24 | fprintf(stderr, "[%s] *** error: " fmt "\n", \ 25 | progname, ## __VA_ARGS__ ); \ 26 | } while (0) 27 | 28 | #define ERRS(fmt, ...) do { \ 29 | int save = errno; \ 30 | fflush(0); \ 31 | fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \ 32 | progname, ## __VA_ARGS__, strerror(save)); \ 33 | } while (0) 34 | 35 | #define DBG(fmt, ...) do { \ 36 | fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \ 37 | } while (0) 38 | 39 | 40 | struct file_info { 41 | char *file_name; /* name of the file */ 42 | uint32_t file_size; /* length of the file */ 43 | }; 44 | 45 | struct flash_layout { 46 | char *id; 47 | uint32_t fw_max_len; 48 | uint32_t kernel_la; 49 | uint32_t kernel_ep; 50 | uint32_t rootfs_ofs; 51 | }; 52 | 53 | struct flash_layout *find_layout(struct flash_layout *layouts, const char *id); 54 | void get_md5(const char *data, int size, uint8_t *md5); 55 | int get_file_stat(struct file_info *fdata); 56 | int read_to_buf(const struct file_info *fdata, char *buf); 57 | int write_fw(const char *ofname, const char *data, int len); 58 | inline void inspect_fw_pstr(const char *label, const char *str); 59 | inline void inspect_fw_phex(const char *label, uint32_t val); 60 | inline void inspect_fw_phexdec(const char *label, uint32_t val); 61 | inline void inspect_fw_pmd5sum(const char *label, const uint8_t *val, const char *text); 62 | int build_fw(size_t header_size); 63 | 64 | #endif /* mktplinkfw_lib_h */ 65 | -------------------------------------------------------------------------------- /src/mkdlinkfw-lib.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * mkdlinkfw 4 | * 5 | * Copyright (C) 2018 Paweł Dembicki 6 | * 7 | * This tool is based on mktplinkfw. 8 | * Copyright (C) 2009 Gabor Juhos 9 | * Copyright (C) 2008,2009 Wang Jian 10 | */ 11 | 12 | #ifndef mkdlinkfw_lib_h 13 | #define mkdlinkfw_lib_h 14 | 15 | #define AUH_MAGIC "DLK" 16 | #define AUH_SIZE 80 17 | #define AUH_LVPS 0x01 18 | #define AUH_HDR_ID 0x4842 19 | #define AUH_HDR_VER 0x02 20 | #define AUH_SEC_ID 0x04 21 | #define AUH_INFO_TYPE 0x04 22 | 23 | #define STAG_SIZE 16 24 | #define STAG_ID 0x04 25 | #define STAG_MAGIC 0x2B24 26 | #define STAG_CMARK_FACTORY 0xFF 27 | 28 | #define SCH2_SIZE 40 29 | #define SCH2_MAGIC 0x2124 30 | #define SCH2_VER 0x02 31 | 32 | /* 33 | * compression type values in the header 34 | * so far onlysupport for LZMA is added 35 | */ 36 | #define FLAT 0 37 | #define JZ 1 38 | #define GZIP 2 39 | #define LZMA 3 40 | 41 | #define RAM_ENTRY_ADDR 0x80000000 42 | #define RAM_LOAD_ADDR 0x80000000 43 | #define JBOOT_SIZE 0x10000 44 | 45 | #define ALL_HEADERS_SIZE (AUH_SIZE + STAG_SIZE + SCH2_SIZE) 46 | #define MAX_HEADER_COUNTER 10 47 | #define TIMESTAMP_MAGIC 0x35016f00L 48 | 49 | #define FACTORY 0 50 | #define SYSUPGRADE 1 51 | 52 | #define ERR(fmt, ...) do { \ 53 | fflush(0); \ 54 | fprintf(stderr, "[%s] *** error: " fmt "\n", \ 55 | progname, ## __VA_ARGS__); \ 56 | } while (0) 57 | 58 | #define ERRS(fmt, ...) do { \ 59 | int save = errno; \ 60 | fflush(0); \ 61 | fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \ 62 | progname, ## __VA_ARGS__, strerror(save)); \ 63 | } while (0) 64 | 65 | #define DBG(fmt, ...) do { \ 66 | fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__); \ 67 | } while (0) 68 | 69 | struct file_info { 70 | char *file_name; /* name of the file */ 71 | uint32_t file_size; /* length of the file */ 72 | }; 73 | 74 | uint32_t jboot_timestamp(void); 75 | uint16_t jboot_checksum(uint16_t start_val, uint16_t *data, int size); 76 | int get_file_stat(struct file_info *fdata); 77 | int read_to_buf(const struct file_info *fdata, char *buf); 78 | int write_fw(const char *ofname, const char *data, int len); 79 | 80 | #endif /* mkdlinkfw_lib_h */ 81 | -------------------------------------------------------------------------------- /src/bcmalgo.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | #ifndef bcmutils_H 3 | #define bcmutils_H 4 | 5 | typedef struct 6 | { 7 | uint16_t magic; 8 | uint16_t control; 9 | uint16_t rev_maj; 10 | uint16_t rev_min; 11 | uint32_t build_date; 12 | uint32_t filelen; 13 | uint32_t ldaddress; 14 | char filename[64]; 15 | uint16_t hcs; 16 | uint16_t her_znaet_chto; //v dushe ne ebu 17 | uint32_t crc; 18 | } ldr_header_t; 19 | 20 | 21 | /** 22 | * Reverses endianess of a 32bit int, if the ENDIAN_REVERSE_NEEDED defined at compile-time 23 | * @param data 24 | * @return 25 | */ 26 | uint32_t reverse_endian32 ( uint32_t data ); 27 | 28 | /** 29 | * Reverses endianess of a 16bit int, if the ENDIAN_REVERSE_NEEDED defined at compile-time 30 | * @param data 31 | * @return 32 | */ 33 | uint16_t reverse_endian16 ( uint16_t data ); 34 | /** 35 | * Calculates the strange crc (used by bcm modems) of the file. Thnx fly out to Vector for the algorithm. 36 | * @param filename 37 | * @return 38 | */ 39 | uint32_t get_file_crc ( char* filename ); 40 | 41 | /** 42 | * Calculates HCS of the header. 43 | * @param hd 44 | * @return 45 | */ 46 | uint16_t get_hcs ( ldr_header_t* hd ); 47 | 48 | /** 49 | * Constructs the header of the image with the information given It also automagically calculates HCS and writes it there. 50 | * @param magic - magic device bytes 51 | * @param rev_maj - major revision 52 | * @param rev_min - minor revision 53 | * @param build_date - build date (seconds from EPOCH UTC) 54 | * @param filelen - file length in bytes 55 | * @param ldaddress - Load adress 56 | * @param filename - filename 57 | * @param crc_data - the crc of the data 58 | * @return 59 | */ 60 | ldr_header_t* construct_header ( uint32_t magic, uint16_t rev_maj,uint16_t rev_min, uint32_t build_date, uint32_t filelen, uint32_t ldaddress, const char* filename, uint32_t crc_data ); 61 | 62 | /** 63 | * Dumps header information to stdout. 64 | * @param hd 65 | */ 66 | int dump_header ( ldr_header_t* hd ); 67 | 68 | 69 | /** 70 | * Returns a null terminated string describing what the control number meens 71 | * DO NOT FREE IT!!! 72 | * @param control 73 | * @return 74 | */ 75 | char* get_control_info ( uint16_t control ); 76 | #endif 77 | 78 | /** 79 | * Calculates bcmCRC of a data buffer. 80 | * @param filebuffer - pointer to buffer 81 | * @param size - buffer size 82 | * @return 83 | */ 84 | uint32_t get_buffer_crc ( char* filebuffer, size_t size ); 85 | -------------------------------------------------------------------------------- /src/nec-enc.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * nec-enc.c - encode/decode nec firmware with key 4 | * 5 | * based on xorimage.c in OpenWrt 6 | * 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define KEY_LEN 16 16 | #define PATTERN_LEN 251 17 | 18 | static int 19 | xor_pattern(uint8_t *data, size_t len, const char *key, int k_len, int k_off) 20 | { 21 | int offset = k_off; 22 | 23 | while (len--) { 24 | *data ^= key[offset]; 25 | data++; 26 | offset = (offset + 1) % k_len; 27 | } 28 | 29 | return offset; 30 | } 31 | 32 | static void xor_data(uint8_t *data, size_t len, const uint8_t *pattern) 33 | { 34 | for (int i = 0; i < len; i++) { 35 | *data ^= pattern[i]; 36 | data++; 37 | } 38 | } 39 | 40 | static void __attribute__((noreturn)) usage(void) 41 | { 42 | fprintf(stderr, "Usage: nec-enc -i infile -o outfile -k \n"); 43 | exit(EXIT_FAILURE); 44 | } 45 | 46 | static unsigned char buf_pattern[4096], buf[4096]; 47 | 48 | int main(int argc, char **argv) 49 | { 50 | int k_off = 0, ptn = 1, c, ret = EXIT_SUCCESS; 51 | char *ifn = NULL, *ofn = NULL, *key = NULL; 52 | size_t n, k_len; 53 | FILE *out, *in; 54 | 55 | while ((c = getopt(argc, argv, "i:o:k:h")) != -1) { 56 | switch (c) { 57 | case 'i': 58 | ifn = optarg; 59 | break; 60 | case 'o': 61 | ofn = optarg; 62 | break; 63 | case 'k': 64 | key = optarg; 65 | break; 66 | case 'h': 67 | default: 68 | usage(); 69 | } 70 | } 71 | 72 | if (optind != argc || optind == 1) { 73 | fprintf(stderr, "illegal arg \"%s\"\n", argv[optind]); 74 | usage(); 75 | } 76 | 77 | in = fopen(ifn, "r"); 78 | if (!in) { 79 | perror("can not open input file"); 80 | usage(); 81 | } 82 | 83 | out = fopen(ofn, "w"); 84 | if (!out) { 85 | perror("can not open output file"); 86 | usage(); 87 | } 88 | 89 | if (!key) { 90 | fprintf(stderr, "key is not specified\n"); 91 | usage(); 92 | } 93 | 94 | k_len = strnlen(key, KEY_LEN + 1); 95 | if (k_len == 0 || k_len > KEY_LEN) { 96 | fprintf(stderr, "key length is not in range (0,%d)\n", KEY_LEN); 97 | usage(); 98 | } 99 | 100 | while ((n = fread(buf, 1, sizeof(buf), in)) > 0) { 101 | for (int i = 0; i < n; i++) { 102 | buf_pattern[i] = ptn; 103 | ptn++; 104 | 105 | if (ptn > PATTERN_LEN) 106 | ptn = 1; 107 | } 108 | 109 | k_off = xor_pattern(buf_pattern, n, key, k_len, k_off); 110 | xor_data(buf, n, buf_pattern); 111 | 112 | if (fwrite(buf, 1, n, out) != n) { 113 | perror("failed to write"); 114 | ret = EXIT_FAILURE; 115 | goto out; 116 | } 117 | } 118 | 119 | if (ferror(in)) { 120 | perror("failed to read"); 121 | ret = EXIT_FAILURE; 122 | goto out; 123 | } 124 | 125 | out: 126 | fclose(in); 127 | fclose(out); 128 | return ret; 129 | } 130 | -------------------------------------------------------------------------------- /src/bcm4908kernel.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * Copyright (C) 2021 Rafał Miłecki 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #if !defined(__BYTE_ORDER) 16 | #error "Unknown byte order" 17 | #endif 18 | 19 | #if __BYTE_ORDER == __BIG_ENDIAN 20 | #define cpu_to_le32(x) bswap_32(x) 21 | #define le32_to_cpu(x) bswap_32(x) 22 | #elif __BYTE_ORDER == __LITTLE_ENDIAN 23 | #define cpu_to_le32(x) (x) 24 | #define le32_to_cpu(x) (x) 25 | #else 26 | #error "Unsupported endianness" 27 | #endif 28 | 29 | struct bcm4908kernel_header { 30 | uint32_t boot_load_addr; /* AKA la_address */ 31 | uint32_t boot_addr; /* AKA la_entrypt */ 32 | uint32_t data_len; 33 | uint8_t magic[4]; 34 | uint32_t uncomplen; /* Empty for LZMA, used for LZ4 */ 35 | }; 36 | 37 | static void usage() { 38 | printf("Usage:\n"); 39 | printf("\n"); 40 | printf("\t-i pathname\t\t\tinput kernel filepath\n"); 41 | printf("\t-o pathname\t\t\toutput kernel filepath\n"); 42 | } 43 | 44 | int main(int argc, char **argv) { 45 | struct bcm4908kernel_header header; 46 | uint8_t buf[1024]; 47 | FILE *out = NULL; 48 | FILE *in = NULL; 49 | size_t length; 50 | size_t bytes; 51 | int err = 0; 52 | char c; 53 | 54 | if (argc >= 2 && !strcmp(argv[1], "-h")) { 55 | usage(); 56 | return 0; 57 | } 58 | 59 | while ((c = getopt(argc, argv, "i:o:")) != -1) { 60 | switch (c) { 61 | case 'i': 62 | in = fopen(optarg, "r"); 63 | break; 64 | case 'o': 65 | out = fopen(optarg, "w+"); 66 | break; 67 | } 68 | } 69 | 70 | if (!in || !out) { 71 | fprintf(stderr, "Failed to open input and/or output file\n"); 72 | usage(); 73 | return -EINVAL; 74 | } 75 | 76 | if (fread(&header, 1, sizeof(header), in) != sizeof(header)) { 77 | fprintf(stderr, "Failed to read %zu bytes from input file\n", sizeof(header)); 78 | err = -EIO; 79 | goto err_close; 80 | } 81 | 82 | if (!memcmp(header.magic, "BRCM", 4)) { 83 | fprintf(stderr, "Input file already contains BCM4908 kernel header\n"); 84 | err = -EIO; 85 | goto err_close; 86 | } 87 | 88 | err = fseek(out, sizeof(header), SEEK_SET); 89 | if (err) { 90 | err = -errno; 91 | fprintf(stderr, "Failed to fseek(): %d\n", err); 92 | goto err_close; 93 | } 94 | 95 | length = 0; 96 | rewind(in); 97 | while ((bytes = fread(buf, 1, sizeof(buf), in)) > 0) { 98 | if (fwrite(buf, 1, bytes, out) != bytes) { 99 | fprintf(stderr, "Failed to write %zu B to the output file\n", bytes); 100 | err = -EIO; 101 | goto err_close; 102 | } 103 | length += bytes; 104 | } 105 | 106 | header.boot_load_addr = cpu_to_le32(0x00080000); 107 | header.boot_addr = cpu_to_le32(0x00080000); 108 | header.data_len = cpu_to_le32(length); 109 | header.magic[0] = 'B'; 110 | header.magic[1] = 'R'; 111 | header.magic[2] = 'C'; 112 | header.magic[3] = 'M'; 113 | header.uncomplen = 0; 114 | 115 | fseek(out, 0, SEEK_SET); 116 | 117 | if (fwrite(&header, 1, sizeof(header), out) != sizeof(header)) { 118 | fprintf(stderr, "Failed to write header to the output file\n"); 119 | err = -EIO; 120 | goto err_close; 121 | } 122 | 123 | err_close: 124 | fclose(out); 125 | fclose(in); 126 | return err; 127 | } 128 | -------------------------------------------------------------------------------- /src/seama.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-2.1-or-later 2 | /* vi: set sw=4 ts=4: */ 3 | /* 4 | * (SEA)ttle i(MA)ge is the image which used in project seattle. 5 | * 6 | * Created by David Hsieh 7 | * Copyright (C) 2008-2009 Alpha Networks, Inc. 8 | */ 9 | 10 | #ifndef __SEAMA_HEADER_FILE__ 11 | #define __SEAMA_HEADER_FILE__ 12 | 13 | #include 14 | 15 | #define SEAMA_MAGIC 0x5EA3A417 16 | 17 | /* 18 | * SEAMA looks like the following map. 19 | * All the data of the header should be in network byte order. 20 | * 21 | * +-------------+-------------+------------ 22 | * | SEAMA magic | ^ 23 | * +-------------+-------------+ | 24 | * | reserved | meta size | | 25 | * +-------------+-------------+ header 26 | * | image size (0 bytes) | | 27 | * +-------------+-------------+ | 28 | * ~ Meta data ~ v 29 | * +-------------+-------------+------------ 30 | * | SEAMA magic | ^ ^ 31 | * +-------------+-------------+ | | 32 | * | reserved | meta size | | | 33 | * +-------------+-------------+ | | 34 | * | image size | | | 35 | * +-------------+-------------+ header | 36 | * | | | | 37 | * | 16 bytes of MD5 digest | | | 38 | * | | | | 39 | * | | | | 40 | * +-------------+-------------+ | | 41 | * ~ Meta data ~ v | 42 | * +-------------+-------------+------- | 43 | * | | | 44 | * | Image of the 1st entity | | 45 | * ~ ~ 1st entity 46 | * | | | 47 | * | | v 48 | * +-------------+-------------+------------- 49 | * | SEAMA magic | ^ ^ 50 | * +-------------+-------------+ | | 51 | * | reserved | meta size | | | 52 | * +-------------+-------------+ | | 53 | * | image size | | | 54 | * +-------------+-------------+ header | 55 | * | | | | 56 | * | 16 bytes of MD5 digest | | | 57 | * | | | | 58 | * | | | | 59 | * +-------------+-------------+ | | 60 | * ~ Meta data ~ v | 61 | * +-------------+-------------+------- | 62 | * | | | 63 | * | Image of the 2nd entity | | 64 | * ~ ~ 2nd entity 65 | * | | | 66 | * | | v 67 | * +-------------+-------------+------------- 68 | */ 69 | 70 | 71 | /* 72 | * SEAMA header 73 | * 74 | * |<-------- 32 bits -------->| 75 | * +-------------+-------------+ 76 | * | SEAMA magic | 77 | * +-------------+-------------+ 78 | * | reserved | meta size | 79 | * +-------------+-------------+ 80 | * | image size | 81 | * +-------------+-------------+ 82 | */ 83 | /* seama header */ 84 | typedef struct seama_hdr seamahdr_t; 85 | struct seama_hdr 86 | { 87 | uint32_t magic; /* should always be SEAMA_MAGIC. */ 88 | uint16_t reserved; /* reserved for */ 89 | uint16_t metasize; /* size of the META data */ 90 | uint32_t size; /* size of the image */ 91 | } __attribute__ ((packed)); 92 | 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /src/add_header.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * add_header.c - partially based on OpenWrt's motorola-bin.c 4 | * 5 | * Copyright (C) 2008 Imre Kaloz 6 | * Gabor Juhos 7 | */ 8 | 9 | /* 10 | * The add_header utility used by various vendors preprends the buf 11 | * image with a header containing a CRC32 value which is generated for the 12 | * model id + reserved space for CRC32 + buf, then replaces the reserved 13 | * area with the actual CRC32. This replacement tool mimics this behavior. 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #define BPB 8 /* bits/byte */ 28 | 29 | static uint32_t crc32[1<> 1)) : (crc >> 1); 42 | crc32[n] = crc; 43 | } 44 | } 45 | 46 | static uint32_t crc32buf(unsigned char *buf, size_t len) 47 | { 48 | uint32_t crc = 0xFFFFFFFF; 49 | 50 | for (; len; len--, buf++) 51 | crc = crc32[(uint8_t)crc ^ *buf] ^ (crc >> BPB); 52 | return ~crc; 53 | } 54 | 55 | struct header { 56 | char model[16]; 57 | uint32_t crc; 58 | }; 59 | 60 | static void usage(const char *) __attribute__ (( __noreturn__ )); 61 | 62 | static void usage(const char *mess) 63 | { 64 | fprintf(stderr, "Error: %s\n", mess); 65 | fprintf(stderr, "Usage: add_header model_id input_file output_file\n"); 66 | fprintf(stderr, "\n"); 67 | exit(1); 68 | } 69 | 70 | int main(int argc, char **argv) 71 | { 72 | off_t len; // of original buf 73 | off_t buflen; // of the output file 74 | int fd; 75 | void *input_file; // pointer to the input file (mmmapped) 76 | struct header header; 77 | unsigned char *buf; // pointer to prefix + copy of original buf 78 | 79 | // verify parameters 80 | 81 | if (argc != 4) 82 | usage("wrong number of arguments"); 83 | 84 | // mmap input_file 85 | if ((fd = open(argv[2], O_RDONLY)) < 0 86 | || (len = lseek(fd, 0, SEEK_END)) < 0 87 | || (input_file = mmap(0, len, PROT_READ, MAP_SHARED, fd, 0)) == (void *) (-1) 88 | || close(fd) < 0) 89 | { 90 | fprintf(stderr, "Error loading file %s: %s\n", argv[2], strerror(errno)); 91 | exit(1); 92 | } 93 | 94 | buflen = len + sizeof(header); 95 | 96 | init_crc32(); 97 | 98 | // copy model name into header 99 | strncpy(header.model, argv[1], sizeof(header.model)); 100 | header.crc = 0; 101 | 102 | // create a firmware image in memory and copy the input_file to it 103 | buf = malloc(buflen); 104 | memcpy(buf, &header, sizeof(header)); 105 | memcpy(&buf[sizeof(header)], input_file, len); 106 | 107 | // CRC of temporary header + buf 108 | header.crc = htonl(crc32buf(buf, buflen)); 109 | 110 | memcpy(buf, &header, sizeof(header)); 111 | 112 | // write the buf 113 | if ((fd = open(argv[3], O_CREAT|O_WRONLY|O_TRUNC,0644)) < 0 114 | || write(fd, buf, buflen) != buflen 115 | || close(fd) < 0) 116 | { 117 | fprintf(stderr, "Error storing file %s: %s\n", argv[3], strerror(errno)); 118 | exit(2); 119 | } 120 | 121 | free(buf); 122 | 123 | munmap(input_file,len); 124 | 125 | return 0; 126 | } 127 | -------------------------------------------------------------------------------- /src/mkdlinkfw-lib.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * mkdlinkfw 4 | * 5 | * Copyright (C) 2018 Paweł Dembicki 6 | * 7 | * This tool is based on mktplinkfw. 8 | * Copyright (C) 2009 Gabor Juhos 9 | * Copyright (C) 2008,2009 Wang Jian 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include /* for unlink() */ 17 | #include 18 | #include /* for getopt() */ 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include /*for crc32 */ 26 | 27 | #include "mkdlinkfw-lib.h" 28 | 29 | extern char *progname; 30 | 31 | uint32_t jboot_timestamp(void) 32 | { 33 | char *env = getenv("SOURCE_DATE_EPOCH"); 34 | char *endptr = env; 35 | time_t fixed_timestamp = -1; 36 | errno = 0; 37 | 38 | if (env && *env) { 39 | fixed_timestamp = strtoull(env, &endptr, 10); 40 | 41 | if (errno || (endptr && *endptr != '\0')) { 42 | fprintf(stderr, "Invalid SOURCE_DATE_EPOCH"); 43 | fixed_timestamp = -1; 44 | } 45 | } 46 | 47 | if (fixed_timestamp == -1) 48 | time(&fixed_timestamp); 49 | 50 | return (((uint32_t) fixed_timestamp) - TIMESTAMP_MAGIC) >> 2; 51 | } 52 | 53 | uint16_t jboot_checksum(uint16_t start_val, uint16_t *data, int size) 54 | { 55 | uint32_t counter = start_val; 56 | uint16_t *ptr = data; 57 | 58 | while (size > 1) { 59 | counter += *ptr; 60 | ++ptr; 61 | while (counter >> 16) 62 | counter = (uint16_t) counter + (counter >> 16); 63 | size -= 2; 64 | } 65 | if (size > 0) { 66 | counter += *(uint8_t *) ptr; 67 | counter -= 0xFF; 68 | } 69 | while (counter >> 16) 70 | counter = (uint16_t) counter + (counter >> 16); 71 | return counter; 72 | } 73 | 74 | int get_file_stat(struct file_info *fdata) 75 | { 76 | struct stat st; 77 | int res; 78 | 79 | if (fdata->file_name == NULL) 80 | return 0; 81 | 82 | res = stat(fdata->file_name, &st); 83 | if (res) { 84 | ERRS("stat failed on %s", fdata->file_name); 85 | return res; 86 | } 87 | 88 | fdata->file_size = st.st_size; 89 | return 0; 90 | } 91 | 92 | int read_to_buf(const struct file_info *fdata, char *buf) 93 | { 94 | FILE *f; 95 | int ret = EXIT_FAILURE; 96 | size_t read; 97 | 98 | f = fopen(fdata->file_name, "r"); 99 | if (f == NULL) { 100 | ERRS("could not open \"%s\" for reading", fdata->file_name); 101 | goto out; 102 | } 103 | 104 | read = fread(buf, fdata->file_size, 1, f); 105 | if (ferror(f) || read != 1) { 106 | ERRS("unable to read from file \"%s\"", fdata->file_name); 107 | goto out_close; 108 | } 109 | 110 | ret = EXIT_SUCCESS; 111 | 112 | out_close: 113 | fclose(f); 114 | out: 115 | return ret; 116 | } 117 | 118 | int write_fw(const char *ofname, const char *data, int len) 119 | { 120 | FILE *f; 121 | int ret = EXIT_FAILURE; 122 | 123 | f = fopen(ofname, "w"); 124 | if (f == NULL) { 125 | ERRS("could not open \"%s\" for writing", ofname); 126 | goto out; 127 | } 128 | 129 | errno = 0; 130 | fwrite(data, len, 1, f); 131 | if (errno) { 132 | ERRS("unable to write output file"); 133 | goto out_flush; 134 | } 135 | 136 | DBG("firmware file \"%s\" completed", ofname); 137 | 138 | ret = EXIT_SUCCESS; 139 | 140 | out_flush: 141 | fflush(f); 142 | fclose(f); 143 | if (ret != EXIT_SUCCESS) 144 | unlink(ofname); 145 | out: 146 | return ret; 147 | } 148 | -------------------------------------------------------------------------------- /src/imagetag.ggo: -------------------------------------------------------------------------------- 1 | # Command line option parsing generator file for imagetag 2 | # Supplied-To: gengetopt 3 | # 4 | # Copyright 2010 Daniel Dickinson 5 | # 6 | # This file is subject to the terms and conditions of the GNU General Public 7 | # License. See the file "COPYING" in the main directory of this archive 8 | # for more details. 9 | # 10 | 11 | package "imagetag" 12 | version "2.0.0" 13 | purpose "Generate image with CFE imagetag for Broadcom 63xx routers." 14 | description "Copyright (C) 2008 Axel Gembe 15 | Copyright (C) 2009-2010 Daniel Dickinson 16 | Licensed unter the terms of the Gnu General Public License. 17 | 18 | Given a root filesystem, a linux kernel, and an optional CFE, generates an image with an imagetag for a Broadcom 63xx-based router. Additional parameters to be specified depend on the specfic brand and model of router." 19 | args "--file-name=imagetag_cmdline" 20 | 21 | option "kernel" i "File with LZMA compressed kernel to include in the image." string typestr="filename" required 22 | option "rootfs" f "File with RootFS to include in the image." string typestr="filename" required 23 | option "output" o "Name of output file." string typestr="filename" required 24 | option "cfe" - "File with CFE to include in the image." string typestr="filename" optional 25 | option "boardid" b "Board ID to set in the image (must match what router expects, e.g. \"96345GW2\")." string required 26 | option "chipid" c "Chip ID to set in the image (must match the actual hardware, e.g. \"6345\")." string required 27 | option "flash-start" s "Flash start address." string typestr="address" optional default="0xBFC00000" 28 | option "image-offset" n "Offset from start address for the first byte after the CFE (in memory)." string typestr="offset" default="0x10000" optional 29 | option "tag-version" v "Version number for imagetag format." string default="6" optional 30 | option "signature" a "Magic string (signature), for boards that need it." string default="Broadcom Corporatio" optional 31 | option "signature2" m "Second magic string (signature2)." string default="ver. 2.0" optional 32 | option "block-size" k "Flash erase block size." string optional default="0x10000" 33 | option "load-addr" l "Kernel load address." string typestr="address" required 34 | option "entry" e "Address where the kernel entry point will be for booting." string typestr="address" required 35 | option "layoutver" y "Flash layout version (version 2.2x of the Broadcom code requires this)." string optional 36 | option "info1" 1 "String for first vendor information section." string optional 37 | option "altinfo" - "String for vendor information section (alternate/pirelli)." string optional 38 | option "info2" 2 "String for second vendor information section." string optional 39 | option "root-first" - "Put the rootfs before the kernel (only for stock images, e.g. captured from the router's flash memory)." flag off 40 | option "rsa-signature" r "String for RSA Signature section." string optional 41 | option "second-image-flag" - "Dual Image Flag (2=not-specified)." values="0", "1", "2" default="2" typestr="flag-value" optional 42 | option "inactive" - "Inactive Flag (2=not-specified)." values="0", "1", "2" default="2" typestr="flag-value" optional 43 | option "reserved2" - "String for second reserved section." string optional 44 | option "kernel-file-has-header" - "Indicates that the kernel file includes the kernel header with correct load address and entry point, so no changes are needed" flag off 45 | option "pad" p "Pad the image to this size if smaller (in MiB)" int typestr="size (in MiB)" optional 46 | option "align-rootfs" - "Align the rootfs start to erase block size" flag off 47 | -------------------------------------------------------------------------------- /src/xorimage.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * xorimage.c - partially based on OpenWrt's addpattern.c 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | static char default_pattern[] = "12345678"; 16 | static int is_hex_pattern; 17 | 18 | 19 | int xor_data(void *data, size_t len, const void *pattern, int p_len, int p_off) 20 | { 21 | const uint8_t *key = pattern; 22 | uint8_t *d = data; 23 | 24 | while (len--) { 25 | *d ^= key[p_off]; 26 | d++; 27 | p_off = (p_off + 1) % p_len; 28 | } 29 | return p_off; 30 | } 31 | 32 | 33 | void usage(void) __attribute__ (( __noreturn__ )); 34 | 35 | void usage(void) 36 | { 37 | fprintf(stderr, "Usage: xorimage [-i infile] [-o outfile] [-p ] [-x]\n"); 38 | exit(EXIT_FAILURE); 39 | } 40 | 41 | 42 | int main(int argc, char **argv) 43 | { 44 | char buf[1024]; /* keep this at 1k or adjust garbage calc below */ 45 | FILE *in = stdin; 46 | FILE *out = stdout; 47 | char *ifn = NULL; 48 | char *ofn = NULL; 49 | const char *pattern = default_pattern; 50 | char hex_pattern[128]; 51 | unsigned int hex_buf; 52 | int c; 53 | size_t n; 54 | int p_len, p_off = 0; 55 | 56 | while ((c = getopt(argc, argv, "i:o:p:xh")) != -1) { 57 | switch (c) { 58 | case 'i': 59 | ifn = optarg; 60 | break; 61 | case 'o': 62 | ofn = optarg; 63 | break; 64 | case 'p': 65 | pattern = optarg; 66 | break; 67 | case 'x': 68 | is_hex_pattern = true; 69 | break; 70 | case 'h': 71 | default: 72 | usage(); 73 | } 74 | } 75 | 76 | if (optind != argc || optind == 1) { 77 | fprintf(stderr, "illegal arg \"%s\"\n", argv[optind]); 78 | usage(); 79 | } 80 | 81 | if (ifn && !(in = fopen(ifn, "r"))) { 82 | fprintf(stderr, "can not open \"%s\" for reading\n", ifn); 83 | usage(); 84 | } 85 | 86 | if (ofn && !(out = fopen(ofn, "w"))) { 87 | fprintf(stderr, "can not open \"%s\" for writing\n", ofn); 88 | usage(); 89 | } 90 | 91 | p_len = strlen(pattern); 92 | 93 | if (p_len == 0) { 94 | fprintf(stderr, "pattern cannot be empty\n"); 95 | usage(); 96 | } 97 | 98 | if (is_hex_pattern) { 99 | int i; 100 | 101 | if ((p_len / 2) > sizeof(hex_pattern)) { 102 | fprintf(stderr, "provided hex pattern is too long\n"); 103 | usage(); 104 | } 105 | 106 | if (p_len % 2 != 0) { 107 | fprintf(stderr, "the number of characters (hex) is incorrect\n"); 108 | usage(); 109 | } 110 | 111 | for (i = 0; i < (p_len / 2); i++) { 112 | if (sscanf(pattern + (i * 2), "%2x", &hex_buf) < 0) { 113 | fprintf(stderr, "invalid hex digit around %d\n", i * 2); 114 | usage(); 115 | } 116 | hex_pattern[i] = (char)hex_buf; 117 | } 118 | } 119 | 120 | while ((n = fread(buf, 1, sizeof(buf), in)) > 0) { 121 | if (n < sizeof(buf)) { 122 | if (ferror(in)) { 123 | FREAD_ERROR: 124 | fprintf(stderr, "fread error\n"); 125 | return EXIT_FAILURE; 126 | } 127 | } 128 | 129 | if (is_hex_pattern) { 130 | p_off = xor_data(buf, n, hex_pattern, (p_len / 2), 131 | p_off); 132 | } else { 133 | p_off = xor_data(buf, n, pattern, p_len, p_off); 134 | } 135 | 136 | if (!fwrite(buf, n, 1, out)) { 137 | FWRITE_ERROR: 138 | fprintf(stderr, "fwrite error\n"); 139 | return EXIT_FAILURE; 140 | } 141 | } 142 | 143 | if (ferror(in)) { 144 | goto FREAD_ERROR; 145 | } 146 | 147 | if (fflush(out)) { 148 | goto FWRITE_ERROR; 149 | } 150 | 151 | fclose(in); 152 | fclose(out); 153 | 154 | return EXIT_SUCCESS; 155 | } 156 | -------------------------------------------------------------------------------- /src/encode_crc.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* ************************************************************************** 3 | 4 | This program creates a CRC checksum and encodes the file that is named 5 | in the command line. 6 | 7 | Compile with: gcc encode_crc.c -Wall -o encode_crc 8 | 9 | Author: Michael Margraf (michael.margraf@freecom.com) 10 | Copyright: Freecom Technology GmbH, Berlin, 2004 11 | www.freecom.com 12 | 13 | ************************************************************************* */ 14 | 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | // ******************************************************************* 22 | // CCITT polynom G(x)=x^16+x^12+x^5+1 23 | #define POLYNOM 0x1021 24 | 25 | // CRC algorithm with MSB first 26 | int make_crc16(int crc, char new) 27 | { 28 | int i; 29 | crc = crc ^ (((int)new) << 8); 30 | 31 | for(i=0; i<8; i++) { // work on 8 bits in "new" 32 | crc <<= 1; // MSBs first 33 | if(crc & 0x10000) crc ^= POLYNOM; 34 | } 35 | return crc & 0xFFFF; 36 | } 37 | 38 | // ******************************************************************* 39 | // Reads the file "filename" into memory and returns pointer to the buffer. 40 | static char *readfile(char *filename, int *size) 41 | { 42 | FILE *fp; 43 | char *buffer; 44 | struct stat info; 45 | 46 | if (stat(filename,&info)!=0) 47 | return NULL; 48 | 49 | if ((fp=fopen(filename,"r"))==NULL) 50 | return NULL; 51 | 52 | buffer=NULL; 53 | for (;;) 54 | { 55 | if ((buffer=(char *)malloc(info.st_size+1))==NULL) 56 | break; 57 | 58 | if (fread(buffer,1,info.st_size,fp)!=info.st_size) 59 | { 60 | free(buffer); 61 | buffer=NULL; 62 | break; 63 | } 64 | 65 | buffer[info.st_size]='\0'; 66 | if(size) *size = info.st_size; 67 | 68 | break; 69 | } 70 | 71 | (void)fclose(fp); 72 | 73 | return buffer; 74 | } 75 | 76 | 77 | // ******************************************************************* 78 | int main(int argc, char** argv) 79 | { 80 | if(argc < 3) { 81 | printf("ERROR: Argument missing!\n\n"); 82 | return 1; 83 | } 84 | 85 | int count; // size of file in bytes 86 | char *p, *master = readfile(argv[1], &count); 87 | if(!master) { 88 | printf("ERROR: File not found!\n"); 89 | return 1; 90 | } 91 | 92 | int crc = 0xFFFF, z; 93 | 94 | p = master; 95 | for(z=0; z 2) { // with flag for device recognition ? 101 | p = argv[2]; 102 | for(z=strlen(p); z>0; z--) { 103 | crc ^= (int)(*p); 104 | *(p++) = (char)crc; // encode device flag 105 | } 106 | } 107 | */ 108 | 109 | p = master; 110 | for(z=0; z 3) { // add flag for device recognition ? 124 | fwrite(argv[3], strlen(argv[3]), sizeof(char), fp); 125 | } 126 | else { 127 | // Device is an FSG, so byte swap (IXP4xx is big endian) 128 | crc16 = ((crc16 >> 8) & 0xFF) | ((crc16 << 8) & 0xFF00); 129 | } 130 | 131 | fwrite(&crc16, 1, sizeof(short), fp); // first write CRC 132 | 133 | fwrite(master, count, sizeof(char), fp); // write content 134 | fclose(fp); 135 | 136 | free(master); 137 | return 0; 138 | } 139 | -------------------------------------------------------------------------------- /src/zyimage.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright (C) 2014 Soul Trace 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define szbuf 32768 13 | 14 | u_int32_t crc_tab[256]; 15 | 16 | u_int32_t chksum_crc32 (FILE *f) 17 | { 18 | register unsigned long crc; 19 | unsigned long i, j; 20 | char *buffer = malloc(szbuf); 21 | char *buf; 22 | 23 | crc = 0xFFFFFFFF; 24 | while (!feof(f)) 25 | { 26 | j = fread(buffer, 1, szbuf, f); 27 | buf = buffer; 28 | for (i = 0; i < j; i++) 29 | crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_tab[(crc ^ *buf++) & 0xFF]; 30 | } 31 | free(buffer); 32 | return crc; 33 | } 34 | 35 | void chksum_crc32gentab () 36 | { 37 | unsigned long crc, poly; 38 | int i, j; 39 | 40 | poly = 0xEDB88320L; 41 | for (i = 0; i < 256; i++) 42 | { 43 | crc = i; 44 | for (j = 8; j > 0; j--) 45 | { 46 | if (crc & 1) 47 | crc = (crc >> 1) ^ poly; 48 | else 49 | crc >>= 1; 50 | } 51 | crc_tab[i] = crc; 52 | } 53 | } 54 | 55 | void usage(char *progname) 56 | { 57 | printf("Usage: %s [ -v Version ] [ -d Device_ID ] \n", progname); 58 | exit(1); 59 | } 60 | 61 | int main(int argc, char *argv[]) { 62 | struct signature 63 | { 64 | const char magic[4]; 65 | unsigned int device_id; 66 | char firmware_version[48]; 67 | unsigned int crc32; 68 | } 69 | sign = 70 | { 71 | { 'Z', 'N', 'B', 'G' }, 72 | 1, 73 | { "V.1.0.0(1.0.0)" }, 74 | 0 75 | }; 76 | FILE *f; 77 | struct signature oldsign; 78 | char *filename; 79 | static const char *optString; 80 | int opt; 81 | 82 | if (argc < 1) 83 | usage(argv[0]); 84 | 85 | optString = "v:d:h"; 86 | opt = getopt( argc, argv, optString ); 87 | while( opt != -1 ) { 88 | switch( opt ) { 89 | case 'v': 90 | if (optarg == NULL) 91 | usage(argv[0]); 92 | strncpy(sign.firmware_version, optarg, sizeof(sign.firmware_version)-1); 93 | sign.firmware_version[sizeof(sign.firmware_version)-1]='\0'; /* Make sure that string is terminated correctly */ 94 | break; 95 | 96 | case 'd': 97 | sign.device_id = atoi(optarg); 98 | if (sign.device_id == 0) 99 | sign.device_id = (int)strtol(optarg, NULL, 16); 100 | break; 101 | 102 | case '?': 103 | case 'h': 104 | usage(argv[0]); 105 | break; 106 | 107 | default: 108 | break; 109 | } 110 | 111 | opt = getopt( argc, argv, optString ); 112 | } 113 | 114 | chksum_crc32gentab(); 115 | 116 | filename=argv[optind]; 117 | if (access(filename, W_OK) || access(filename, R_OK)) 118 | { 119 | printf("Not open input file %s\n", filename); 120 | exit(1); 121 | } 122 | f = fopen(argv[optind], "r+"); 123 | if (f != NULL) 124 | { 125 | fseek(f, sizeof(sign)*-1, SEEK_END); 126 | fread(&oldsign, sizeof(oldsign), 1, f); 127 | 128 | if (strncmp(oldsign.magic,"ZNBG", sizeof(oldsign.magic)) == 0 ) 129 | { 130 | printf("Image is already signed as:\nDevice ID: 0x%08x\nFirmware version: %s\nImage CRC32: 0x%x\n", oldsign.device_id, oldsign.firmware_version, oldsign.crc32); 131 | exit(0); 132 | } 133 | 134 | fseek(f, 0, SEEK_SET); 135 | sign.crc32 = chksum_crc32(f); 136 | fwrite(&sign, sizeof(sign), 1, f); 137 | fclose(f); 138 | 139 | printf("Image signed as:\nDevice ID: 0x%08x\nFirmware version: %s\nImage CRC32: 0x%x\n", sign.device_id, sign.firmware_version, sign.crc32); 140 | } 141 | return 0; 142 | } 143 | -------------------------------------------------------------------------------- /src/cyg_crc.h: -------------------------------------------------------------------------------- 1 | //========================================================================== 2 | // 3 | // crc.h 4 | // 5 | // Interface for the CRC algorithms. 6 | // 7 | //========================================================================== 8 | //####ECOSGPLCOPYRIGHTBEGIN#### 9 | // ------------------------------------------- 10 | // This file is part of eCos, the Embedded Configurable Operating System. 11 | // Copyright (C) 2002 Andrew Lunn 12 | // 13 | // eCos is free software; you can redistribute it and/or modify it under 14 | // the terms of the GNU General Public License as published by the Free 15 | // Software Foundation; either version 2 or (at your option) any later version. 16 | // 17 | // eCos is distributed in the hope that it will be useful, but WITHOUT ANY 18 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or 19 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 20 | // for more details. 21 | // 22 | // You should have received a copy of the GNU General Public License along 23 | // with eCos; if not, write to the Free Software Foundation, Inc., 24 | // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 25 | // 26 | // As a special exception, if other files instantiate templates or use macros 27 | // or inline functions from this file, or you compile this file and link it 28 | // with other works to produce a work based on this file, this file does not 29 | // by itself cause the resulting work to be covered by the GNU General Public 30 | // License. However the source code for this file must still be made available 31 | // in accordance with section (3) of the GNU General Public License. 32 | // 33 | // This exception does not invalidate any other reasons why a work based on 34 | // this file might be covered by the GNU General Public License. 35 | // 36 | // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. 37 | // at http://sources.redhat.com/ecos/ecos-license/ 38 | // ------------------------------------------- 39 | //####ECOSGPLCOPYRIGHTEND#### 40 | //========================================================================== 41 | //#####DESCRIPTIONBEGIN#### 42 | // 43 | // Author(s): Andrew Lunn 44 | // Contributors: Andrew Lunn 45 | // Date: 2002-08-06 46 | // Purpose: 47 | // Description: 48 | // 49 | // This code is part of eCos (tm). 50 | // 51 | //####DESCRIPTIONEND#### 52 | // 53 | //========================================================================== 54 | 55 | #ifndef _SERVICES_CRC_CRC_H_ 56 | #define _SERVICES_CRC_CRC_H_ 57 | 58 | #if 0 59 | #include 60 | #else 61 | #include 62 | typedef uint32_t cyg_uint32; 63 | typedef uint16_t cyg_uint16; 64 | #endif 65 | 66 | #ifndef __externC 67 | # ifdef __cplusplus 68 | # define __externC extern "C" 69 | # else 70 | # define __externC extern 71 | # endif 72 | #endif 73 | 74 | // Compute a CRC, using the POSIX 1003 definition 75 | 76 | __externC cyg_uint32 77 | cyg_posix_crc32(void *s, int len); 78 | 79 | // Gary S. Brown's 32 bit CRC 80 | 81 | __externC cyg_uint32 82 | cyg_crc32(void *s, int len); 83 | 84 | // Gary S. Brown's 32 bit CRC, but accumulate the result from a 85 | // previous CRC calculation 86 | 87 | __externC cyg_uint32 88 | cyg_crc32_accumulate(cyg_uint32 crc, void *s, int len); 89 | 90 | // Ethernet FCS Algorithm 91 | 92 | __externC cyg_uint32 93 | cyg_ether_crc32(void *s, int len); 94 | 95 | // Ethernet FCS algorithm, but accumulate the result from a previous 96 | // CRC calculation. 97 | 98 | __externC cyg_uint32 99 | cyg_ether_crc32_accumulate(cyg_uint32 crc, void *s, int len); 100 | 101 | // 16 bit CRC with polynomial x^16+x^12+x^5+1 102 | 103 | __externC cyg_uint16 104 | cyg_crc16(void *s, int len); 105 | 106 | #endif // _SERVICES_CRC_CRC_H_ 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /src/buffalo-tftp.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright (C) 2009-2011 Gabor Juhos 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include /* for getopt() */ 12 | #include 13 | 14 | #include "buffalo-lib.h" 15 | 16 | #define ERR(fmt, args...) do { \ 17 | fflush(0); \ 18 | fprintf(stderr, "[%s] *** error: " fmt "\n", \ 19 | progname, ## args ); \ 20 | } while (0) 21 | 22 | static char *progname; 23 | static char *ifname; 24 | static char *ofname; 25 | static int do_decrypt; 26 | 27 | void usage(int status) 28 | { 29 | FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; 30 | 31 | fprintf(stream, "Usage: %s [OPTIONS...]\n", progname); 32 | fprintf(stream, 33 | "\n" 34 | "Options:\n" 35 | " -d decrypt instead of encrypt\n" 36 | " -i read input from the file \n" 37 | " -o write output to the file \n" 38 | " -h show this screen\n" 39 | ); 40 | 41 | exit(status); 42 | } 43 | 44 | static const unsigned char *crypt_key1 = (unsigned char *) 45 | "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; 46 | static const unsigned char *crypt_key2 = (unsigned char *) 47 | "XYZ0123hijklmnopqABCDEFGHrstuvabcdefgwxyzIJKLMSTUVW456789NOPQR"; 48 | 49 | static void crypt_header(unsigned char *buf, ssize_t len, 50 | const unsigned char *key1, const unsigned char *key2) 51 | { 52 | ssize_t i; 53 | 54 | for (i = 0; i < len; i++) { 55 | unsigned int j; 56 | 57 | for (j = 0; key1[j]; j++) 58 | if (buf[i] == key1[j]) { 59 | buf[i] = key2[j]; 60 | break; 61 | } 62 | } 63 | } 64 | 65 | static int crypt_file(void) 66 | { 67 | unsigned char *buf = NULL; 68 | ssize_t src_len; 69 | int err; 70 | int ret = -1; 71 | 72 | src_len = get_file_size(ifname); 73 | if (src_len < 0) { 74 | ERR("unable to get size of '%s'", ifname); 75 | goto out; 76 | } 77 | 78 | buf = malloc(src_len); 79 | if (buf == NULL) { 80 | ERR("no memory for the buffer"); 81 | goto out; 82 | } 83 | 84 | err = read_file_to_buf(ifname, buf, src_len); 85 | if (err) { 86 | ERR("unable to read from file '%s'", ifname); 87 | goto out; 88 | } 89 | 90 | if (do_decrypt) 91 | crypt_header(buf, 512, crypt_key2, crypt_key1); 92 | else 93 | crypt_header(buf, 512, crypt_key1, crypt_key2); 94 | 95 | err = write_buf_to_file(ofname, buf, src_len); 96 | if (err) { 97 | ERR("unable to write to file '%s'", ofname); 98 | goto out; 99 | } 100 | 101 | ret = 0; 102 | 103 | out: 104 | free(buf); 105 | return ret; 106 | } 107 | 108 | static int check_params(void) 109 | { 110 | int ret = -1; 111 | 112 | if (ifname == NULL) { 113 | ERR("no input file specified"); 114 | goto out; 115 | } 116 | 117 | if (ofname == NULL) { 118 | ERR("no output file specified"); 119 | goto out; 120 | } 121 | 122 | ret = 0; 123 | 124 | out: 125 | return ret; 126 | } 127 | 128 | int main(int argc, char *argv[]) 129 | { 130 | int res = EXIT_FAILURE; 131 | int err; 132 | 133 | progname = basename(argv[0]); 134 | 135 | while ( 1 ) { 136 | int c; 137 | 138 | c = getopt(argc, argv, "di:o:h"); 139 | if (c == -1) 140 | break; 141 | 142 | switch (c) { 143 | case 'd': 144 | do_decrypt = 1; 145 | break; 146 | case 'i': 147 | ifname = optarg; 148 | break; 149 | case 'o': 150 | ofname = optarg; 151 | break; 152 | case 'h': 153 | usage(EXIT_SUCCESS); 154 | break; 155 | default: 156 | usage(EXIT_FAILURE); 157 | break; 158 | } 159 | } 160 | 161 | err = check_params(); 162 | if (err) 163 | goto out; 164 | 165 | err = crypt_file(); 166 | if (err) 167 | goto out; 168 | 169 | res = EXIT_SUCCESS; 170 | 171 | out: 172 | return res; 173 | } 174 | -------------------------------------------------------------------------------- /src/uimage_padhdr.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * uimage_padhdr.c : add zero paddings after the tail of uimage header 4 | * 5 | * Copyright (C) 2019 NOGUCHI Hiroshi 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | 19 | /* from u-boot/include/image.h */ 20 | #define IH_MAGIC 0x27051956 /* Image Magic Number */ 21 | #define IH_NMLEN 32 /* Image Name Length */ 22 | 23 | /* 24 | * Legacy format image header, 25 | * all data in network byte order (aka natural aka bigendian). 26 | */ 27 | typedef struct image_header { 28 | uint32_t ih_magic; /* Image Header Magic Number */ 29 | uint32_t ih_hcrc; /* Image Header CRC Checksum */ 30 | uint32_t ih_time; /* Image Creation Timestamp */ 31 | uint32_t ih_size; /* Image Data Size */ 32 | uint32_t ih_load; /* Data Load Address */ 33 | uint32_t ih_ep; /* Entry Point Address */ 34 | uint32_t ih_dcrc; /* Image Data CRC Checksum */ 35 | uint8_t ih_os; /* Operating System */ 36 | uint8_t ih_arch; /* CPU architecture */ 37 | uint8_t ih_type; /* Image Type */ 38 | uint8_t ih_comp; /* Compression Type */ 39 | uint8_t ih_name[IH_NMLEN]; /* Image Name */ 40 | } image_header_t; 41 | 42 | 43 | /* default padding size */ 44 | #define IH_PAD_BYTES (32) 45 | 46 | 47 | static void usage(char *prog) 48 | { 49 | fprintf(stderr, 50 | "%s -i -o [-l ]\n", 51 | prog); 52 | } 53 | 54 | int main(int argc, char *argv[]) 55 | { 56 | struct stat statbuf; 57 | u_int8_t *filebuf; 58 | int ifd; 59 | int ofd; 60 | ssize_t rsz; 61 | u_int32_t crc_recalc; 62 | image_header_t *imgh; 63 | int opt; 64 | char *infname = NULL; 65 | char *outfname = NULL; 66 | int padsz = IH_PAD_BYTES; 67 | int ltmp; 68 | 69 | while ((opt = getopt(argc, argv, "i:o:l:")) != -1) { 70 | switch (opt) { 71 | case 'i': 72 | infname = optarg; 73 | break; 74 | case 'o': 75 | outfname = optarg; 76 | break; 77 | case 'l': 78 | ltmp = strtol(optarg, NULL, 0); 79 | if (ltmp > 0) 80 | padsz = ltmp; 81 | break; 82 | default: 83 | break; 84 | } 85 | } 86 | 87 | if (!infname || !outfname) { 88 | usage(argv[0]); 89 | exit(1); 90 | } 91 | 92 | ifd = open(infname, O_RDONLY); 93 | if (ifd < 0) { 94 | fprintf(stderr, 95 | "could not open input file. (errno = %d)\n", errno); 96 | exit(1); 97 | } 98 | 99 | ofd = open(outfname, O_WRONLY | O_CREAT, 0644); 100 | if (ofd < 0) { 101 | fprintf(stderr, 102 | "could not open output file. (errno = %d)\n", errno); 103 | exit(1); 104 | } 105 | 106 | if (fstat(ifd, &statbuf) < 0) { 107 | fprintf(stderr, 108 | "could not fstat input file. (errno = %d)\n", errno); 109 | exit(1); 110 | } 111 | 112 | filebuf = malloc(statbuf.st_size + padsz); 113 | if (!filebuf) { 114 | fprintf(stderr, "buffer allocation failed\n"); 115 | exit(1); 116 | } 117 | 118 | rsz = read(ifd, filebuf, sizeof(*imgh)); 119 | if (rsz != sizeof(*imgh)) { 120 | fprintf(stderr, 121 | "could not read input file (errno = %d).\n", errno); 122 | exit(1); 123 | } 124 | 125 | memset(&(filebuf[sizeof(*imgh)]), 0, padsz); 126 | 127 | rsz = read(ifd, &(filebuf[sizeof(*imgh) + padsz]), 128 | statbuf.st_size - sizeof(*imgh)); 129 | if (rsz != (int32_t)(statbuf.st_size - sizeof(*imgh))) { 130 | fprintf(stderr, 131 | "could not read input file (errno = %d).\n", errno); 132 | exit(1); 133 | } 134 | 135 | imgh = (image_header_t *)filebuf; 136 | 137 | imgh->ih_hcrc = 0; 138 | crc_recalc = crc32(0, filebuf, sizeof(*imgh) + padsz); 139 | imgh->ih_hcrc = htonl(crc_recalc); 140 | 141 | rsz = write(ofd, filebuf, statbuf.st_size + padsz); 142 | if (rsz != (int32_t)statbuf.st_size + padsz) { 143 | fprintf(stderr, 144 | "could not write output file (errnor = %d).\n", errno); 145 | exit(1); 146 | } 147 | 148 | return 0; 149 | } 150 | -------------------------------------------------------------------------------- /src/nosimg-enc.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * nosimg-enc.c - encode/decode "nos.img" image for XikeStor SKS8300 series 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define ENCODE_BLKLEN 0x100 14 | #define ENCODE_BLOCKS 2 15 | 16 | static const uint8_t key[ENCODE_BLKLEN] = { 17 | 0xee, 0xdd, 0xcc, 0x21, 0x53, 0x55, 0xee, 0xcc, 18 | 0xdd, 0x55, 0x80, 0x7e, 0x00, 0x00, 0x00, 0x00, 19 | 0xcd, 0xbd, 0xdf, 0xae, 0xbb, 0x9b, 0x89, 0x01, 20 | 0x70, 0xe5, 0xcc, 0xdd, 0xf6, 0xfc, 0x83, 0x64, 21 | 0xec, 0xdd, 0xce, 0xf1, 0xe3, 0x54, 0xfe, 0xd0, 22 | 0xbd, 0xab, 0xdd, 0xe1, 0xe4, 0xb4, 0xd5, 0x83, 23 | 0xed, 0xfe, 0xd0, 0xcd, 0xb6, 0x55, 0xcc, 0xa3, 24 | 0xed, 0xd5, 0xc6, 0x7e, 0xdd, 0xcc, 0x21, 0x53, 25 | 0xec, 0x4d, 0xdc, 0x00, 0x53, 0x55, 0xcd, 0xc3, 26 | 0x22, 0x01, 0x80, 0x7e, 0xef, 0xbc, 0x75, 0x66, 27 | 0xa6, 0xc0, 0xcc, 0x2f, 0xfe, 0xd0, 0xee, 0xcc, 28 | 0xdd, 0x55, 0x01, 0x01, 0x01, 0x01, 0xc5, 0x64, 29 | 0x99, 0x45, 0xab, 0x32, 0x55, 0x80, 0x7e, 0xef, 30 | 0x55, 0x80, 0x7e, 0xef, 0xbc, 0x75, 0x66, 0x89, 31 | 0xe3, 0x1d, 0x83, 0xdd, 0xfe, 0x55, 0x8e, 0xab, 32 | 0x7d, 0x55, 0x80, 0x7e, 0xff, 0x01, 0xac, 0x66, 33 | 0x0e, 0xc9, 0x92, 0xd9, 0x73, 0xe5, 0x01, 0x01, 34 | 0xbd, 0xe5, 0x10, 0xce, 0x01, 0x01, 0xba, 0xe8, 35 | 0x3e, 0xdd, 0x81, 0xa1, 0x53, 0x33, 0x01, 0x01, 36 | 0x9a, 0xc5, 0x10, 0xaa, 0x01, 0xce, 0x8a, 0xe1, 37 | 0xb1, 0xfb, 0x00, 0x80, 0x53, 0x77, 0x00, 0x00, 38 | 0x70, 0xdc, 0x00, 0x01, 0x00, 0x00, 0xcb, 0xb1, 39 | 0xa0, 0x30, 0x00, 0x00, 0x55, 0xa6, 0x00, 0x00, 40 | 0xca, 0xbd, 0x01, 0x01, 0x00, 0x00, 0xc9, 0xb2, 41 | 0x81, 0x90, 0x01, 0x00, 0x5a, 0x21, 0x00, 0x01, 42 | 0x79, 0xbc, 0x01, 0x00, 0x78, 0x00, 0x7b, 0xb3, 43 | 0xd4, 0x97, 0x01, 0x00, 0x53, 0x55, 0xa9, 0xfc, 44 | 0xdd, 0xa5, 0x01, 0xbe, 0xaf, 0xc1, 0x75, 0xc5, 45 | 0x8e, 0xd7, 0x77, 0x00, 0x55, 0xd0, 0x0d, 0xac, 46 | 0x01, 0x55, 0x80, 0x7e, 0xef, 0xbc, 0x7e, 0xe6, 47 | 0xf1, 0x6c, 0x52, 0x00, 0x33, 0x16, 0x98, 0xcc, 48 | 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x79, 0x88, 49 | }; 50 | 51 | static void __attribute__((noreturn)) usage(void) 52 | { 53 | fprintf(stderr, "Usage: nosimg-enc -i infile -o outfile [-d]\n"); 54 | exit(EXIT_FAILURE); 55 | } 56 | 57 | static void encode_block(uint8_t *data, bool decode) 58 | { 59 | int i; 60 | 61 | for (i = 0; i < ENCODE_BLKLEN; i++) 62 | data[i] -= key[i] * (decode ? -1 : 1); 63 | } 64 | 65 | int main(int argc, char **argv) 66 | { 67 | int i, c, n, ret = EXIT_SUCCESS; 68 | char *ifn = NULL, *ofn = NULL; 69 | bool decode = false; 70 | uint8_t buf[0x1000]; 71 | FILE *out, *in; 72 | 73 | while ((c = getopt(argc, argv, "i:o:dh")) != -1) { 74 | switch (c) { 75 | case 'i': 76 | ifn = optarg; 77 | break; 78 | case 'o': 79 | ofn = optarg; 80 | break; 81 | case 'd': 82 | decode = true; 83 | break; 84 | case 'h': 85 | default: 86 | usage(); 87 | } 88 | } 89 | 90 | if (optind != argc || optind == 1) { 91 | fprintf(stderr, "illegal arg \"%s\"\n", argv[optind]); 92 | usage(); 93 | } 94 | 95 | in = fopen(ifn, "r"); 96 | if (!in) { 97 | perror("can not open input file"); 98 | usage(); 99 | } 100 | 101 | out = fopen(ofn, "w"); 102 | if (!out) { 103 | perror("can not open output file"); 104 | usage(); 105 | } 106 | 107 | /* encode/decode the first 512 bytes (0x100 x2) */ 108 | for (i = 0; i < ENCODE_BLOCKS; i++) { 109 | n = fread(buf, 1, ENCODE_BLKLEN, in); 110 | if (n < ENCODE_BLKLEN) { 111 | fprintf(stderr, 112 | "failed to read data for encoding/decoding\n"); 113 | ret = EXIT_FAILURE; 114 | goto out; 115 | } 116 | 117 | encode_block(buf, decode); 118 | fwrite(buf, 1, ENCODE_BLKLEN, out); 119 | } 120 | 121 | /* copy the remaining data */ 122 | while ((n = fread(buf, 1, sizeof(buf), in)) > 0) { 123 | if (fwrite(buf, 1, n, out) != n) { 124 | fprintf(stderr, "failed to write"); 125 | ret = EXIT_FAILURE; 126 | goto out; 127 | } 128 | } 129 | 130 | if (ferror(in)) { 131 | perror("failed to read"); 132 | ret = EXIT_FAILURE; 133 | } 134 | 135 | out: 136 | fclose(in); 137 | fclose(out); 138 | return ret; 139 | } 140 | -------------------------------------------------------------------------------- /src/buffalo-lib.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright (C) 2009-2011 Gabor Juhos 4 | */ 5 | 6 | #ifndef _BUFFALO_LIB_H 7 | #define _BUFFALO_LIB_H 8 | 9 | #include 10 | 11 | #define ARRAY_SIZE(_a) (sizeof((_a)) / sizeof((_a)[0])) 12 | #define BIT(_x) (1UL << (_x)) 13 | 14 | #define TAG_BRAND_LEN 32 15 | #define TAG_PRODUCT_LEN 32 16 | #define TAG_VERSION_LEN 8 17 | #define TAG_REGION_LEN 2 18 | #define TAG_LANGUAGE_LEN 8 19 | #define TAG_PLATFORM_LEN 8 20 | #define TAG_HWVER_LEN 4 21 | #define TAG_HWVER_VAL_LEN 4 22 | 23 | struct buffalo_tag { 24 | unsigned char product[TAG_PRODUCT_LEN]; 25 | unsigned char brand[TAG_BRAND_LEN]; 26 | unsigned char ver_major[TAG_VERSION_LEN]; 27 | unsigned char ver_minor[TAG_VERSION_LEN]; 28 | unsigned char region_code[2]; 29 | uint32_t region_mask; 30 | unsigned char unknown0[2]; 31 | unsigned char language[TAG_LANGUAGE_LEN]; 32 | unsigned char platform[TAG_PLATFORM_LEN]; 33 | unsigned char hwv[TAG_HWVER_LEN]; 34 | unsigned char hwv_val[TAG_HWVER_VAL_LEN]; 35 | uint8_t unknown1[24]; 36 | 37 | uint32_t len; 38 | uint32_t crc; 39 | uint32_t base1; 40 | uint32_t base2; 41 | uint32_t data_len; 42 | uint8_t flag; 43 | uint8_t unknown2[3]; 44 | } __attribute ((packed)); 45 | 46 | struct buffalo_tag2 { 47 | unsigned char product[TAG_PRODUCT_LEN]; 48 | unsigned char brand[TAG_BRAND_LEN]; 49 | unsigned char ver_major[TAG_VERSION_LEN]; 50 | unsigned char ver_minor[TAG_VERSION_LEN]; 51 | unsigned char region_code[2]; 52 | uint32_t region_mask; 53 | unsigned char unknown0[2]; 54 | unsigned char language[TAG_LANGUAGE_LEN]; 55 | unsigned char platform[TAG_PLATFORM_LEN]; 56 | unsigned char hwv[TAG_HWVER_LEN]; 57 | unsigned char hwv_val[TAG_HWVER_VAL_LEN]; 58 | uint8_t unknown1[24]; 59 | 60 | uint32_t total_len; 61 | uint32_t crc; 62 | uint32_t len1; 63 | uint32_t len2; 64 | uint8_t flag; 65 | uint8_t unknown2[3]; 66 | } __attribute ((packed)); 67 | 68 | struct buffalo_tag3 { 69 | unsigned char product[TAG_PRODUCT_LEN]; 70 | unsigned char brand[TAG_BRAND_LEN]; 71 | unsigned char ver_major[TAG_VERSION_LEN]; 72 | unsigned char ver_minor[TAG_VERSION_LEN]; 73 | unsigned char region_code[2]; 74 | uint32_t region_mask; 75 | unsigned char unknown0[2]; 76 | unsigned char language[TAG_LANGUAGE_LEN]; 77 | unsigned char platform[TAG_PLATFORM_LEN]; 78 | unsigned char hwv[TAG_HWVER_LEN]; 79 | unsigned char hwv_val[TAG_HWVER_VAL_LEN]; 80 | uint8_t unknown1[24]; 81 | 82 | uint32_t total_len; 83 | uint32_t crc; 84 | uint32_t len1; 85 | uint32_t base2; 86 | } __attribute ((packed)); 87 | 88 | #define ENC_PRODUCT_LEN 32 89 | #define ENC_VERSION_LEN 8 90 | #define ENC_MAGIC_LEN 6 91 | 92 | unsigned long enc_compute_header_len(char *product, char *version); 93 | unsigned long enc_compute_buf_len(char *product, char *version, 94 | unsigned long datalen); 95 | 96 | struct enc_param { 97 | unsigned char *key; 98 | unsigned char magic[ENC_MAGIC_LEN]; 99 | unsigned char product[ENC_PRODUCT_LEN]; 100 | unsigned char version[ENC_VERSION_LEN]; 101 | unsigned char seed; 102 | int longstate; 103 | unsigned datalen; 104 | uint32_t csum; 105 | }; 106 | 107 | int encrypt_buf(struct enc_param *ep, unsigned char *hdr, 108 | unsigned char *data); 109 | int decrypt_buf(struct enc_param *ep, unsigned char *data, 110 | unsigned long datalen); 111 | 112 | #define BCRYPT_DEFAULT_STATE_LEN 256 113 | #define BCRYPT_MAX_KEYLEN 254 114 | 115 | struct bcrypt_ctx { 116 | unsigned long i; 117 | unsigned long j; 118 | unsigned char *state; 119 | unsigned long state_len; 120 | }; 121 | 122 | int bcrypt_init(struct bcrypt_ctx *ctx, void *key, int keylen, 123 | unsigned long state_len); 124 | int bcrypt_process(struct bcrypt_ctx *ctx, unsigned char *src, 125 | unsigned char *dst, unsigned long len); 126 | void bcrypt_finish(struct bcrypt_ctx *ctx); 127 | int bcrypt_buf(unsigned char seed, unsigned char *key, unsigned char *src, 128 | unsigned char *dst, unsigned long len, int longstate); 129 | 130 | uint32_t buffalo_csum(uint32_t csum, void *buf, unsigned long len); 131 | uint32_t buffalo_crc(void *buf, unsigned long len); 132 | 133 | ssize_t get_file_size(char *name); 134 | int read_file_to_buf(char *name, void *buf, ssize_t buflen); 135 | int write_buf_to_file(char *name, void *buf, ssize_t buflen); 136 | 137 | #endif /* _BUFFALO_LIB_H */ 138 | -------------------------------------------------------------------------------- /src/mkbrncmdline.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * mkbrncmdline.c - partially based on OpenWrt's wndr3700.c 4 | * 5 | * Copyright (C) 2011 Tobias Diedrich 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | static void usage(const char *) __attribute__ (( __noreturn__ )); 20 | 21 | static void usage(const char *mess) 22 | { 23 | fprintf(stderr, "Error: %s\n", mess); 24 | fprintf(stderr, "Usage: mkbrncmdline -i input_file -o output_file [-a loadaddress] arg1 [argx ...]\n"); 25 | fprintf(stderr, "\n"); 26 | exit(1); 27 | } 28 | 29 | static char *input_file = NULL; 30 | static char *output_file = NULL; 31 | static unsigned loadaddr = 0x80002000; 32 | 33 | static void parseopts(int *argc, char ***argv) 34 | { 35 | char *endptr; 36 | int res; 37 | 38 | while ((res = getopt(*argc, *argv, "a:i:o:")) != -1) { 39 | switch (res) { 40 | default: 41 | usage("Unknown option"); 42 | break; 43 | case 'a': 44 | loadaddr = strtoul(optarg, &endptr, 0); 45 | if (endptr == optarg || *endptr != 0) 46 | usage("loadaddress must be a decimal or hexadecimal 32-bit value"); 47 | break; 48 | case 'i': 49 | input_file = optarg; 50 | break; 51 | case 'o': 52 | output_file = optarg; 53 | break; 54 | } 55 | } 56 | *argc -= optind; 57 | *argv += optind; 58 | } 59 | 60 | static void emitload(int outfd, int reg, unsigned value) 61 | { 62 | char buf[8] = { 63 | 0x3c, 0x04 + reg, 64 | value >> 24, value >> 16, 65 | 0x34, 0x84 + reg + (reg << 5), 66 | value >> 8, value, 67 | }; 68 | if (write(outfd, buf, sizeof(buf)) != sizeof(buf)) { 69 | fprintf(stderr, "write: %s\n", strerror(errno)); 70 | exit(1); 71 | } 72 | } 73 | 74 | int main(int argc, char **argv) 75 | { 76 | int outfd; 77 | int i; 78 | int fd; 79 | size_t len, skip, buf_len; 80 | unsigned cmdline_addr; 81 | unsigned s_ofs; 82 | char *buf; 83 | 84 | parseopts(&argc, &argv); 85 | 86 | if (argc < 1) 87 | usage("must specify at least one kernel cmdline argument"); 88 | 89 | if (input_file == NULL || output_file == NULL) 90 | usage("must specify input and output file"); 91 | 92 | if ((outfd = open(output_file, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) 93 | { 94 | fprintf(stderr, "Error opening '%s' for writing: %s\n", output_file, strerror(errno)); 95 | exit(1); 96 | } 97 | 98 | // mmap input_file 99 | if ((fd = open(input_file, O_RDONLY)) < 0 100 | || (len = lseek(fd, 0, SEEK_END)) < 0 101 | || (input_file = mmap(0, len, PROT_READ, MAP_SHARED, fd, 0)) == (void *) (-1) 102 | || close(fd) < 0) 103 | { 104 | fprintf(stderr, "Error mapping file '%s': %s\n", input_file, strerror(errno)); 105 | exit(1); 106 | } 107 | 108 | cmdline_addr = loadaddr + len; 109 | 110 | // Kernel args are passed in registers a0,a1,a2 and a3 111 | emitload(outfd, 0, 0); /* a0 = 0 */ 112 | emitload(outfd, 1, 0); /* a1 = 0 */ 113 | emitload(outfd, 2, cmdline_addr); /* a2 = &cmdline */ 114 | emitload(outfd, 3, 0); /* a3 = 0 */ 115 | skip = lseek(outfd, 0, SEEK_END); 116 | 117 | // write the kernel 118 | if (write(outfd, input_file + skip, len - skip) != len -skip) { 119 | fprintf(stderr, "write: %s\n", strerror(errno)); 120 | exit(1); 121 | } 122 | 123 | // write cmdline structure 124 | buf_len = (argc + 1) * 4; 125 | for (i=0; i> 24; 139 | buf[i * 4 + 1] = s_ptr >> 16; 140 | buf[i * 4 + 2] = s_ptr >> 8; 141 | buf[i * 4 + 3] = s_ptr >> 0; 142 | memcpy(&buf[s_ofs], argv[i], strlen(argv[i])); 143 | s_ofs += strlen(argv[i]) + 1; 144 | } 145 | if (write(outfd, buf, buf_len) != buf_len) { 146 | fprintf(stderr, "write: %s\n", strerror(errno)); 147 | exit(1); 148 | } 149 | 150 | 151 | munmap(input_file, len); 152 | close(outfd); 153 | free(buf); 154 | 155 | return 0; 156 | } 157 | -------------------------------------------------------------------------------- /src/linksys-addfwhdr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Linksys e8350 v1 firmware header generator 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "cyg_crc.h" 17 | 18 | #define AC2350 20 19 | #define CYBERTAN_VERSION "v1.0.03" 20 | #define SERIAL_NUMBER "003" 21 | #define MINOR_VERSION "" 22 | #define BUILD_KEYWORD " B" 23 | #define BUILD_NUMBER SERIAL_NUMBER 24 | #define BETA_VERSION " " 25 | #define CYBERTAN_UBOOT_VERSION "v1.0" 26 | 27 | /* add for AC2350 F/W header */ 28 | #define FWHDR_MAGIC_STR "CHDR" 29 | #define FWHDR_MAGIC 0X52444843 30 | 31 | struct cbt_fw_header { 32 | unsigned int magic; /* "CHDR" */ 33 | unsigned int len; /* Length of file including header */ 34 | unsigned int crc32; /* 32-bit CRC */ 35 | unsigned int res; 36 | }; 37 | 38 | #define MAX_BUF 1024 39 | /* Initial CRC32 checksum value */ 40 | #define CRC32_INIT_VALUE 0xffffffff 41 | 42 | int fd, fd_w; 43 | 44 | void die(const char * str, ...) 45 | { 46 | va_list args; 47 | va_start(args, str); 48 | vfprintf(stderr, str, args); 49 | fputc('\n', stderr); 50 | exit(1); 51 | } 52 | 53 | int fill_null0(int size) 54 | { 55 | unsigned char buf[1]; 56 | int i; 57 | 58 | fprintf(stderr,"Fill null\n"); 59 | 60 | buf[0] = 0xff; 61 | for (i = 0 ; i < size; i++) 62 | if (write(fd_w, buf, 1) != 1) 63 | return 0; 64 | 65 | return 1; 66 | } 67 | 68 | long file_open(const char *name) 69 | { 70 | struct stat sb; 71 | if ((fd = open(name, O_RDONLY, 0)) < 0) 72 | die("Unable to open `%s' : %m", name); 73 | 74 | if (fstat (fd, &sb)) 75 | die("Unable to stat `%s' : %m", name); 76 | 77 | return sb.st_size; 78 | } 79 | 80 | void usage(void) 81 | { 82 | die("Usage: addfwhdr [-i|--input] sysupgrade.o [-o|--output] code.bin\n"); 83 | } 84 | 85 | int main(int argc, char ** argv) 86 | { 87 | char *input_file = NULL, *output_file = NULL; 88 | extern int optind, opterr, optopt; 89 | unsigned int input_size,c; 90 | int option_index = 0; 91 | extern char *optarg; 92 | char *buf = NULL; 93 | int garbage = 0; 94 | int opt; 95 | 96 | struct cbt_fw_header *fwhdr; 97 | unsigned int crc; 98 | 99 | static struct option long_options[] = { 100 | {"input", 1, 0, 'i'}, 101 | {"output", 1, 0, 'o'}, 102 | {"garbage", 0, 0, 'g'}, 103 | {0, 0, 0, 0} 104 | }; 105 | 106 | while(true) { 107 | opt = getopt_long(argc, argv, "i:o:g",long_options, &option_index); 108 | if (opt == -1) 109 | break; 110 | switch(opt){ 111 | case 'h' : 112 | usage(); 113 | break; 114 | case 'i' : 115 | input_file = optarg; 116 | printf("input file is [%s]\n", input_file); 117 | break; 118 | case 'o' : 119 | output_file = optarg; 120 | printf("output file is [%s]\n", output_file); 121 | break; 122 | case 'g' : 123 | garbage = 1; 124 | break; 125 | default : 126 | usage(); 127 | } 128 | } 129 | 130 | if (!input_file || !output_file) { 131 | printf("You must specify the input and output file!\n"); 132 | usage(); 133 | } 134 | 135 | unlink(output_file); 136 | if ((fd_w = open(output_file, O_RDWR|O_CREAT, S_IREAD | S_IWRITE)) < 0) 137 | die("Unable to open `%s' : %m", output_file); 138 | 139 | printf("\n---------- add fw header --------\n"); 140 | 141 | fwhdr = calloc(1, sizeof(struct cbt_fw_header)); 142 | memcpy((char *)&fwhdr->magic, FWHDR_MAGIC_STR, sizeof(fwhdr->magic)); 143 | 144 | input_size = file_open(input_file); 145 | if (!(buf = malloc(input_size))){ 146 | perror("malloc"); 147 | goto fail; 148 | } 149 | c = read(fd, buf, input_size); 150 | fwhdr->len = input_size + sizeof(struct cbt_fw_header); 151 | fwhdr->res = fwhdr->res | 0x1; 152 | 153 | crc = cyg_crc32_accumulate(CRC32_INIT_VALUE, (uint8_t *)&fwhdr->res, 4); 154 | crc = cyg_crc32_accumulate(crc, (uint8_t *)&buf[0], input_size); 155 | 156 | fwhdr->crc32 = crc; 157 | 158 | /* write code pattern header */ 159 | write(fd_w, fwhdr, sizeof(struct cbt_fw_header)); 160 | 161 | if (write(fd_w, buf, c) != c) 162 | die("Write call failed!\n"); 163 | 164 | fail: 165 | free(fwhdr); 166 | if (buf) 167 | free(buf); 168 | close(fd); 169 | close(fd_w); 170 | 171 | return 0; 172 | } 173 | -------------------------------------------------------------------------------- /src/bcm_tag.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | #ifndef __BCM63XX_TAG_H 3 | #define __BCM63XX_TAG_H 4 | 5 | #define TAGVER_LEN 4 /* Length of Tag Version */ 6 | #define TAGLAYOUT_LEN 4 /* Length of FlashLayoutVer */ 7 | #define SIG1_LEN 20 /* Company Signature 1 Length */ 8 | #define SIG2_LEN 14 /* Company Signature 2 Lenght */ 9 | #define BOARDID_LEN 16 /* Length of BoardId */ 10 | #define ENDIANFLAG_LEN 2 /* Endian Flag Length */ 11 | #define CHIPID_LEN 6 /* Chip Id Length */ 12 | #define IMAGE_LEN 10 /* Length of Length Field */ 13 | #define ADDRESS_LEN 12 /* Length of Address field */ 14 | #define DUALFLAG_LEN 2 /* Dual Image flag Length */ 15 | #define INACTIVEFLAG_LEN 2 /* Inactie Flag Length */ 16 | #define RSASIG_LEN 20 /* Length of RSA Signature in tag */ 17 | #define TAGINFO1_LEN 30 /* Length of vendor information field1 in tag */ 18 | #define FLASHLAYOUTVER_LEN 4 /* Length of Flash Layout Version String tag */ 19 | #define TAGINFO2_LEN 16 /* Length of vendor information field2 in tag */ 20 | #define CRC_LEN 4 /* Length of CRC in bytes */ 21 | #define ALTTAGINFO_LEN 54 /* Alternate length for vendor information; Pirelli */ 22 | 23 | #define NUM_PIRELLI 2 24 | #define IMAGETAG_CRC_START 0xFFFFFFFF 25 | 26 | #define PIRELLI_BOARDS { \ 27 | "AGPF-S0", \ 28 | "DWV-S0", \ 29 | } 30 | 31 | /* 32 | * The broadcom firmware assumes the rootfs starts the image, 33 | * therefore uses the rootfs start (flashImageAddress) 34 | * to determine where to flash the image. Since we have the kernel first 35 | * we have to give it the kernel address, but the crc uses the length 36 | * associated with this address (rootLength), which is added to the kernel 37 | * length (kernelLength) to determine the length of image to flash and thus 38 | * needs to be rootfs + deadcode (jffs2 EOF marker) 39 | */ 40 | 41 | struct bcm_tag { 42 | char tagVersion[TAGVER_LEN]; // 0-3: Version of the image tag 43 | char sig_1[SIG1_LEN]; // 4-23: Company Line 1 44 | char sig_2[SIG2_LEN]; // 24-37: Company Line 2 45 | char chipid[CHIPID_LEN]; // 38-43: Chip this image is for 46 | char boardid[BOARDID_LEN]; // 44-59: Board name 47 | char big_endian[ENDIANFLAG_LEN]; // 60-61: Map endianness -- 1 BE 0 LE 48 | char totalLength[IMAGE_LEN]; // 62-71: Total length of image 49 | char cfeAddress[ADDRESS_LEN]; // 72-83: Address in memory of CFE 50 | char cfeLength[IMAGE_LEN]; // 84-93: Size of CFE 51 | char flashImageStart[ADDRESS_LEN]; // 94-105: Address in memory of image start (kernel for OpenWRT, rootfs for stock firmware) 52 | char flashRootLength[IMAGE_LEN]; // 106-115: Size of rootfs for flashing 53 | char kernelAddress[ADDRESS_LEN]; // 116-127: Address in memory of kernel 54 | char kernelLength[IMAGE_LEN]; // 128-137: Size of kernel 55 | char dualImage[DUALFLAG_LEN]; // 138-139: Unused at present 56 | char inactiveFlag[INACTIVEFLAG_LEN]; // 140-141: Unused at present 57 | char rsa_signature[RSASIG_LEN]; // 142-161: RSA Signature (unused at present; some vendors may use this) 58 | char information1[TAGINFO1_LEN]; // 162-191: Compilation and related information (not generated/used by OpenWRT) 59 | char flashLayoutVer[FLASHLAYOUTVER_LEN];// 192-195: Version flash layout 60 | char fskernelCRC[CRC_LEN]; // 196-199: kernel+rootfs CRC32 61 | char information2[TAGINFO2_LEN]; // 200-215: Unused at present except Alice Gate where is is information 62 | char imageCRC[CRC_LEN]; // 216-219: CRC32 of image less imagetag (kernel for Alice Gate) 63 | char rootfsCRC[CRC_LEN]; // 220-223: CRC32 of rootfs partition 64 | char kernelCRC[CRC_LEN]; // 224-227: CRC32 of kernel partition 65 | char imageSequence[4]; // 228-231: Image sequence number 66 | char rootLength[4]; // 232-235: steal from reserved1 to keep the real root length so we can use in the flash map even after we have change the rootLength to 0 to satisfy devices that check CRC on every boot 67 | char headerCRC[CRC_LEN]; // 236-239: CRC32 of header excluding tagVersion 68 | char reserved2[16]; // 240-255: Unused at present 69 | }; 70 | 71 | #endif /* __BCM63XX_TAG_H */ 72 | -------------------------------------------------------------------------------- /src/avm-wasp-checksum.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * Copyright (C) 2020 Andreas Boehler 4 | * 5 | * This tool was based on: 6 | * firmware-crc.pl by Atheros Communications 7 | * 8 | * This program is free software; you can redistribute it and/or modify it 9 | * under the terms of the GNU General Public License version 2 as published 10 | * by the Free Software Foundation. 11 | * 12 | */ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include /* for getopt() */ 19 | #include 20 | 21 | char *infile; 22 | char *outfile; 23 | char *progname; 24 | enum { 25 | MODEL_3390, 26 | MODEL_X490 27 | } model; 28 | 29 | #define CHUNK_SIZE 256 30 | 31 | uint32_t crc32_for_byte(uint32_t r) 32 | { 33 | for (int j = 0; j < 8; ++j) 34 | r = (r & 1 ? 0 : (uint32_t)0xEDB88320L) ^ r >> 1; 35 | return r ^ (uint32_t)0xFF000000L; 36 | } 37 | 38 | void crc32(const void *data, size_t n_bytes, uint32_t *crc) 39 | { 40 | static uint32_t table[0x100]; 41 | 42 | if (!*table) 43 | for (size_t i = 0; i < 0x100; ++i) 44 | table[i] = crc32_for_byte(i); 45 | for (size_t i = 0; i < n_bytes; ++i) 46 | *crc = table[(uint8_t)*crc ^ ((uint8_t *)data)[i]] ^ *crc >> 8; 47 | } 48 | 49 | static void usage(int status) 50 | { 51 | fprintf(stderr, "Usage: %s [OPTIONS...]\n", progname); 52 | fprintf(stderr, 53 | "\n" 54 | "Options:\n" 55 | " -i input file name\n" 56 | " -o output file name\n" 57 | " -m model (3390, x490 for 3490/5490/7490)\n" 58 | " -h show this screen\n" 59 | ); 60 | 61 | exit(status); 62 | } 63 | 64 | int main(int argc, char *argv[]) 65 | { 66 | uint32_t crc = 0; 67 | FILE *in_fp; 68 | FILE *out_fp; 69 | uint32_t buf[CHUNK_SIZE]; 70 | size_t read; 71 | 72 | progname = argv[0]; 73 | 74 | while (1) { 75 | int c; 76 | 77 | c = getopt(argc, argv, "i:o:m:h"); 78 | if (c == -1) 79 | break; 80 | 81 | switch (c) { 82 | case 'i': 83 | infile = optarg; 84 | break; 85 | case 'o': 86 | outfile = optarg; 87 | break; 88 | case 'm': 89 | if (strcmp(optarg, "3390") == 0) 90 | model = MODEL_3390; 91 | else if (strcmp(optarg, "x490") == 0) 92 | model = MODEL_X490; 93 | else 94 | usage(EXIT_FAILURE); 95 | break; 96 | case 'h': 97 | usage(EXIT_SUCCESS); 98 | default: 99 | usage(EXIT_FAILURE); 100 | break; 101 | } 102 | } 103 | 104 | if (!infile || !outfile) 105 | usage(EXIT_FAILURE); 106 | 107 | in_fp = fopen(infile, "r"); 108 | if (!in_fp) { 109 | fprintf(stderr, "Error opening input file: %s\n", infile); 110 | return EXIT_FAILURE; 111 | } 112 | out_fp = fopen(outfile, "w"); 113 | if (!out_fp) { 114 | fprintf(stderr, "Error opening output file: %s\n", outfile); 115 | fclose(in_fp); 116 | return EXIT_FAILURE; 117 | } 118 | 119 | while (!feof(in_fp)) { 120 | switch (model) { 121 | case MODEL_3390: 122 | read = fread(buf, sizeof(uint32_t), CHUNK_SIZE, in_fp); 123 | if (ferror(in_fp)) { 124 | fprintf(stderr, "Error reading input file: %s\n", infile); 125 | fclose(in_fp); 126 | fclose(out_fp); 127 | return EXIT_FAILURE; 128 | } 129 | for (int i = 0; i < read; i++) 130 | crc = crc ^ buf[i]; 131 | fwrite(buf, sizeof(uint32_t), read, out_fp); 132 | if (ferror(out_fp)) { 133 | fprintf(stderr, "Error writing output file: %s\n", outfile); 134 | fclose(in_fp); 135 | fclose(out_fp); 136 | return EXIT_FAILURE; 137 | } 138 | break; 139 | case MODEL_X490: 140 | read = fread(buf, 1, sizeof(uint32_t) * CHUNK_SIZE, in_fp); 141 | if (ferror(in_fp)) { 142 | fprintf(stderr, "Error reading input file: %s\n", infile); 143 | fclose(in_fp); 144 | fclose(out_fp); 145 | return EXIT_FAILURE; 146 | } 147 | crc32(buf, read, &crc); 148 | fwrite(buf, 1, read, out_fp); 149 | if (ferror(out_fp)) { 150 | fprintf(stderr, "Error writing output file: %s\n", outfile); 151 | fclose(in_fp); 152 | fclose(out_fp); 153 | return EXIT_FAILURE; 154 | } 155 | break; 156 | } 157 | } 158 | if (model == MODEL_X490) 159 | crc = bswap_32(crc); 160 | fwrite(&crc, sizeof(uint32_t), 1, out_fp); 161 | if (ferror(out_fp)) { 162 | fprintf(stderr, "Error writing checksum to output file: %s\n", outfile); 163 | fclose(in_fp); 164 | fclose(out_fp); 165 | return EXIT_FAILURE; 166 | } 167 | fclose(in_fp); 168 | fclose(out_fp); 169 | printf("Done.\n"); 170 | return EXIT_SUCCESS; 171 | } 172 | -------------------------------------------------------------------------------- /src/iptime-crc32.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright (c) 2021 Sungbo Eo 4 | * 5 | * This code is based on mkdhpimg.c and mkzcfw.c 6 | * Copyright (C) 2010 Gabor Juhos 7 | * Copyright (c) 2016 FUKAUMI Naoki 8 | * 9 | * Checksum algorithm is derived from add_iptime_fw_header.c 10 | * Copyright (C) 2020 Jaehoon You 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "cyg_crc.h" 26 | 27 | #if !defined(__BYTE_ORDER) 28 | #error "Unknown byte order" 29 | #endif 30 | 31 | #if (__BYTE_ORDER == __BIG_ENDIAN) 32 | #define HOST_TO_LE32(x) bswap_32(x) 33 | #elif (__BYTE_ORDER == __LITTLE_ENDIAN) 34 | #define HOST_TO_LE32(x) (x) 35 | #else 36 | #error "Unsupported endianness" 37 | #endif 38 | 39 | #define FW_VERSION "00_000" 40 | 41 | struct fw_header { 42 | uint8_t model[8]; 43 | uint8_t version[8]; 44 | uint8_t reserved[32]; 45 | uint32_t size; 46 | uint32_t checksum; 47 | } __attribute__ ((packed)); 48 | 49 | struct board_info { 50 | const char *model; 51 | size_t payload_offset; 52 | }; 53 | 54 | struct board_info boards[] = { 55 | { .model = "a6004mx", .payload_offset = 0x800 }, 56 | { .model = "ax2002m", .payload_offset = 0x38 }, 57 | { .model = "ax2004m", .payload_offset = 0x38 }, 58 | { .model = "ax3000m", .payload_offset = 0x38 }, 59 | { .model = "ax3000q", .payload_offset = 0x38 }, 60 | { .model = "ax6000m", .payload_offset = 0x38 }, 61 | { .model = "ax7800m", .payload_offset = 0x38 }, 62 | { .model = "ax8004m", .payload_offset = 0x38 }, 63 | { .model = "ax3kse", .payload_offset = 0x38 }, 64 | { .model = "ax3ksm", .payload_offset = 0x38 }, 65 | { /* sentinel */ } 66 | }; 67 | 68 | struct board_info *find_board(const char *model) 69 | { 70 | struct board_info *ret = NULL; 71 | struct board_info *board; 72 | 73 | for (board = boards; board->model != NULL; board++) { 74 | if (strcmp(model, board->model) == 0) { 75 | ret = board; 76 | break; 77 | } 78 | } 79 | 80 | return ret; 81 | } 82 | 83 | uint32_t make_checksum(struct fw_header *header, uint8_t *payload, int size) 84 | { 85 | cyg_uint32 checksum; 86 | 87 | /* get CRC of header */ 88 | checksum = cyg_crc32_accumulate(~0L, header, sizeof(*header)); 89 | 90 | /* get CRC of payload buffer with header CRC as initial value */ 91 | return (uint32_t)cyg_crc32_accumulate(checksum, payload, size); 92 | } 93 | 94 | void make_header(struct board_info *board, uint8_t *buffer, size_t img_size) 95 | { 96 | struct fw_header *header = (struct fw_header *)buffer; 97 | uint32_t checksum; 98 | 99 | strncpy((char *)header->model, board->model, sizeof(header->model)-1); 100 | strncpy((char *)header->version, FW_VERSION, sizeof(header->version)-1); 101 | header->size = HOST_TO_LE32(img_size); 102 | checksum = make_checksum(header, buffer + board->payload_offset, img_size); 103 | header->checksum = HOST_TO_LE32(checksum); 104 | } 105 | 106 | int main(int argc, const char *argv[]) 107 | { 108 | const char *model_name, *img_in, *img_out; 109 | struct board_info *board; 110 | int file_in, file_out; 111 | struct stat stat_in; 112 | size_t size_in, size_out; 113 | uint8_t *buffer; 114 | 115 | if (argc != 4) { 116 | fprintf(stderr, "Usage: %s \n", argv[0]); 117 | return EXIT_FAILURE; 118 | } 119 | model_name = argv[1]; 120 | img_in = argv[2]; 121 | img_out = argv[3]; 122 | 123 | board = find_board(model_name); 124 | if (board == NULL) { 125 | fprintf(stderr, "%s: Not supported model\n", model_name); 126 | return EXIT_FAILURE; 127 | } 128 | 129 | if ((file_in = open(img_in, O_RDONLY)) == -1) 130 | err(EXIT_FAILURE, "%s", img_in); 131 | 132 | if (fstat(file_in, &stat_in) == -1) 133 | err(EXIT_FAILURE, "%s", img_in); 134 | 135 | size_in = stat_in.st_size; 136 | size_out = board->payload_offset + size_in; 137 | 138 | if ((buffer = malloc(size_out)) == NULL) 139 | err(EXIT_FAILURE, "malloc"); 140 | 141 | read(file_in, buffer + board->payload_offset, size_in); 142 | close(file_in); 143 | 144 | memset(buffer, 0, board->payload_offset); 145 | 146 | make_header(board, buffer, size_in); 147 | 148 | if ((file_out = creat(img_out, 0644)) == -1) 149 | err(EXIT_FAILURE, "%s", img_out); 150 | write(file_out, buffer, size_out); 151 | close(file_out); 152 | 153 | free(buffer); 154 | 155 | return EXIT_SUCCESS; 156 | } 157 | -------------------------------------------------------------------------------- /src/uimage_sgehdr.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * uimage_sgehdr.c : add 96 bytes of extra header information after the normal tail of uimage header 4 | * this is an edited version of uimage_padhdr.c 5 | * 6 | * Copyright (C) 2019 NOGUCHI Hiroshi 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | 20 | /* from u-boot/include/image.h */ 21 | #define IH_NMLEN 32 /* Image Name Length */ 22 | #define SGE_PRODUCTLEN 64 /* sge_Product Length */ 23 | #define SGE_VERSIONLEN 16 /* sge Version Length */ 24 | #define OrignalHL 64 /* Original Header Length */ 25 | 26 | /* 27 | * SGE format image header, 28 | * all data in network byte order (aka natural aka bigendian). 29 | */ 30 | struct image_header { 31 | uint32_t ih_magic; /* Image Header Magic Number */ 32 | uint32_t ih_hcrc; /* Image Header CRC Checksum */ 33 | uint32_t ih_time; /* Image Creation Timestamp */ 34 | uint32_t ih_size; /* Image Data Size */ 35 | uint32_t ih_load; /* Data Load Address */ 36 | uint32_t ih_ep; /* Entry Point Address */ 37 | uint32_t ih_dcrc; /* Image Data CRC Checksum */ 38 | uint8_t ih_os; /* Operating System */ 39 | uint8_t ih_arch; /* CPU architecture */ 40 | uint8_t ih_type; /* Image Type */ 41 | uint8_t ih_comp; /* Compression Type */ 42 | uint8_t ih_name[IH_NMLEN]; /* Image Name */ 43 | char sgeih_p[SGE_PRODUCTLEN]; /* sge_Product */ 44 | char sgeih_sv[SGE_VERSIONLEN]; /* sge Software Version */ 45 | char sgeih_hv[SGE_VERSIONLEN]; /* sge Hardware Version */ 46 | }; 47 | 48 | 49 | /* default padding size */ 50 | #define IH_PAD_BYTES (96) 51 | 52 | 53 | static void usage(char *prog) 54 | { 55 | fprintf(stderr, 56 | "%s -i -o -m -h -s \n", 57 | prog); 58 | } 59 | 60 | int main(int argc, char *argv[]) 61 | { 62 | struct stat statbuf; 63 | u_int8_t *filebuf; 64 | int ifd; 65 | int ofd; 66 | ssize_t rsz; 67 | u_int32_t crc_recalc; 68 | struct image_header *imgh; 69 | int opt; 70 | char *infname = NULL; 71 | char *outfname = NULL; 72 | char *model = NULL; 73 | char *hversion = NULL; 74 | char *sversion = NULL; 75 | int padsz = IH_PAD_BYTES; 76 | 77 | while ((opt = getopt(argc, argv, "i:o:m:h:s:")) != -1) { 78 | switch (opt) { 79 | case 'i': 80 | infname = optarg; 81 | break; 82 | case 'o': 83 | outfname = optarg; 84 | break; 85 | case 'm': 86 | model = optarg; 87 | break; 88 | case 'h': 89 | hversion = optarg; 90 | break; 91 | case 's': 92 | sversion = optarg; 93 | break; 94 | default: 95 | break; 96 | } 97 | } 98 | 99 | if (!infname || !outfname) { 100 | usage(argv[0]); 101 | exit(1); 102 | } 103 | 104 | ifd = open(infname, O_RDONLY); 105 | if (ifd < 0) { 106 | fprintf(stderr, 107 | "could not open input file. (errno = %d)\n", errno); 108 | exit(1); 109 | } 110 | 111 | ofd = open(outfname, O_WRONLY | O_CREAT, 0644); 112 | if (ofd < 0) { 113 | fprintf(stderr, 114 | "could not open output file. (errno = %d)\n", errno); 115 | exit(1); 116 | } 117 | 118 | if (fstat(ifd, &statbuf) < 0) { 119 | fprintf(stderr, 120 | "could not fstat input file. (errno = %d)\n", errno); 121 | exit(1); 122 | } 123 | 124 | filebuf = malloc(statbuf.st_size + padsz); 125 | if (!filebuf) { 126 | fprintf(stderr, "buffer allocation failed\n"); 127 | exit(1); 128 | } 129 | 130 | rsz = read(ifd, filebuf, OrignalHL); 131 | if (rsz != OrignalHL) { 132 | fprintf(stderr, 133 | "could not read input file (errno = %d).\n", errno); 134 | exit(1); 135 | } 136 | 137 | memset(&(filebuf[OrignalHL]), 0, padsz); 138 | 139 | rsz = read(ifd, &(filebuf[sizeof(*imgh)]), 140 | statbuf.st_size - OrignalHL); 141 | if (rsz != (int32_t)(statbuf.st_size - OrignalHL)) { 142 | fprintf(stderr, 143 | "could not read input file (errno = %d).\n", errno); 144 | exit(1); 145 | } 146 | 147 | imgh = (struct image_header *)filebuf; 148 | 149 | imgh->ih_hcrc = 0; 150 | 151 | strncpy(imgh->sgeih_p, model, sizeof(imgh->sgeih_p)); 152 | strncpy(imgh->sgeih_sv, sversion, sizeof(imgh->sgeih_sv)); 153 | strncpy(imgh->sgeih_hv, hversion, sizeof(imgh->sgeih_hv)); 154 | 155 | crc_recalc = crc32(0, filebuf, sizeof(*imgh)); 156 | imgh->ih_hcrc = htonl(crc_recalc); 157 | 158 | rsz = write(ofd, filebuf, statbuf.st_size + padsz); 159 | if (rsz != (int32_t)statbuf.st_size + padsz) { 160 | fprintf(stderr, 161 | "could not write output file (errnor = %d).\n", errno); 162 | exit(1); 163 | } 164 | 165 | return 0; 166 | } 167 | -------------------------------------------------------------------------------- /src/mkdniimg.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright (C) 2009 Gabor Juhos 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include /* for unlink() */ 11 | #include 12 | #include /* for getopt() */ 13 | #include 14 | #include 15 | #include 16 | 17 | #define DNI_HDR_LEN 128 18 | 19 | /* 20 | * Globals 21 | */ 22 | static char *ifname; 23 | static char *progname; 24 | static char *ofname; 25 | static char *version = "1.00.00"; 26 | static char *region = ""; 27 | static char *hd_id; 28 | 29 | static char *board_id; 30 | /* 31 | * Message macros 32 | */ 33 | #define ERR(fmt, ...) do { \ 34 | fflush(0); \ 35 | fprintf(stderr, "[%s] *** error: " fmt "\n", \ 36 | progname, ## __VA_ARGS__ ); \ 37 | } while (0) 38 | 39 | #define ERRS(fmt, ...) do { \ 40 | int save = errno; \ 41 | fflush(0); \ 42 | fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \ 43 | progname, ## __VA_ARGS__, strerror(save)); \ 44 | } while (0) 45 | 46 | void usage(int status) 47 | { 48 | FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; 49 | 50 | fprintf(stream, "Usage: %s [OPTIONS...]\n", progname); 51 | fprintf(stream, 52 | "\n" 53 | "Options:\n" 54 | " -B create image for the board specified with \n" 55 | " -i read input from the file \n" 56 | " -o write output to the file \n" 57 | " -v set image version to \n" 58 | " -r set image region to \n" 59 | " -H set image hardware id to \n" 60 | " -h show this screen\n" 61 | ); 62 | 63 | exit(status); 64 | } 65 | 66 | int main(int argc, char *argv[]) 67 | { 68 | int res = EXIT_FAILURE; 69 | int buflen; 70 | int err; 71 | struct stat st; 72 | char *buf; 73 | int pos, rem, i; 74 | uint8_t csum; 75 | 76 | FILE *outfile, *infile; 77 | 78 | progname = basename(argv[0]); 79 | 80 | while ( 1 ) { 81 | int c; 82 | 83 | c = getopt(argc, argv, "B:i:o:v:r:H:h"); 84 | if (c == -1) 85 | break; 86 | 87 | switch (c) { 88 | case 'B': 89 | board_id = optarg; 90 | break; 91 | case 'i': 92 | ifname = optarg; 93 | break; 94 | case 'o': 95 | ofname = optarg; 96 | break; 97 | case 'v': 98 | version = optarg; 99 | break; 100 | case 'r': 101 | region = optarg; 102 | break; 103 | case 'H': 104 | hd_id = optarg; 105 | break; 106 | case 'h': 107 | usage(EXIT_SUCCESS); 108 | break; 109 | default: 110 | usage(EXIT_FAILURE); 111 | break; 112 | } 113 | } 114 | 115 | if (board_id == NULL) { 116 | ERR("no board specified"); 117 | goto err; 118 | } 119 | 120 | if (ifname == NULL) { 121 | ERR("no input file specified"); 122 | goto err; 123 | } 124 | 125 | if (ofname == NULL) { 126 | ERR("no output file specified"); 127 | goto err; 128 | } 129 | 130 | err = stat(ifname, &st); 131 | if (err){ 132 | ERRS("stat failed on %s", ifname); 133 | goto err; 134 | } 135 | 136 | buflen = st.st_size + DNI_HDR_LEN + 1; 137 | buf = malloc(buflen); 138 | if (!buf) { 139 | ERR("no memory for buffer\n"); 140 | goto err; 141 | } 142 | 143 | memset(buf, 0, DNI_HDR_LEN); 144 | pos = snprintf(buf, DNI_HDR_LEN, "device:%s\nversion:V%s\nregion:%s\n", 145 | board_id, version, region); 146 | rem = DNI_HDR_LEN - pos; 147 | if (pos >= 0 && rem > 1 && hd_id) { 148 | snprintf(buf + pos, rem, "hd_id:%s\n", hd_id); 149 | } 150 | 151 | infile = fopen(ifname, "r"); 152 | if (infile == NULL) { 153 | ERRS("could not open \"%s\" for reading", ifname); 154 | goto err_free; 155 | } 156 | 157 | errno = 0; 158 | fread(buf + DNI_HDR_LEN, st.st_size, 1, infile); 159 | if (errno != 0) { 160 | ERRS("unable to read from file %s", ifname); 161 | goto err_close_in; 162 | } 163 | 164 | csum = 0; 165 | for (i = 0; i < (st.st_size + DNI_HDR_LEN); i++) 166 | csum += buf[i]; 167 | 168 | csum = 0xff - csum; 169 | buf[st.st_size + DNI_HDR_LEN] = csum; 170 | 171 | outfile = fopen(ofname, "w"); 172 | if (outfile == NULL) { 173 | ERRS("could not open \"%s\" for writing", ofname); 174 | goto err_close_in; 175 | } 176 | 177 | errno = 0; 178 | fwrite(buf, buflen, 1, outfile); 179 | if (errno) { 180 | ERRS("unable to write to file %s", ofname); 181 | goto err_close_out; 182 | } 183 | 184 | res = EXIT_SUCCESS; 185 | 186 | fflush(outfile); 187 | 188 | err_close_out: 189 | fclose(outfile); 190 | if (res != EXIT_SUCCESS) { 191 | unlink(ofname); 192 | } 193 | 194 | err_close_in: 195 | fclose(infile); 196 | 197 | err_free: 198 | free(buf); 199 | 200 | err: 201 | return res; 202 | } 203 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 3.5) 2 | 3 | PROJECT(firmware-utils C) 4 | INCLUDE(GNUInstallDirs) 5 | INCLUDE(FindZLIB) 6 | INCLUDE(FindOpenSSL) 7 | 8 | IF(NOT ZLIB_FOUND) 9 | MESSAGE(FATAL_ERROR "Unable to find zlib library.") 10 | ENDIF() 11 | 12 | IF(NOT OPENSSL_FOUND) 13 | MESSAGE(FATAL_ERROR "Unable to find OpenSSL library.") 14 | ENDIF() 15 | 16 | ADD_DEFINITIONS(-Wall -Wno-unused-parameter) 17 | 18 | MACRO(FW_UTIL util deps extra_cflags libs) 19 | ADD_EXECUTABLE(${util} src/${util}.c ${deps}) 20 | INSTALL(TARGETS ${util} RUNTIME) 21 | IF(NOT "${extra_cflags}" STREQUAL "") 22 | SET_TARGET_PROPERTIES(${util} PROPERTIES COMPILE_FLAGS ${extra_cflags}) 23 | ENDIF() 24 | IF(NOT "${libs}" STREQUAL "") 25 | TARGET_LINK_LIBRARIES(${util} ${libs}) 26 | ENDIF() 27 | ENDMACRO(FW_UTIL) 28 | 29 | FW_UTIL(add_header "" "" "") 30 | FW_UTIL(addpattern "" "" "") 31 | FW_UTIL(asustrx "" "" "") 32 | FW_UTIL(asusuimage "" "" "${ZLIB_LIBRARIES}") 33 | FW_UTIL(avm-wasp-checksum "" --std=gnu99 "") 34 | FW_UTIL(bcm4908asus "" "" "") 35 | FW_UTIL(bcm4908kernel "" "" "") 36 | FW_UTIL(bcmblob "" "" "") 37 | FW_UTIL(bcmclm "" "" "") 38 | FW_UTIL(buffalo-enc src/buffalo-lib.c "" "") 39 | FW_UTIL(buffalo-tag src/buffalo-lib.c "" "") 40 | FW_UTIL(buffalo-tftp src/buffalo-lib.c "" "") 41 | FW_UTIL(cros-vbutil "" "" "${OPENSSL_CRYPTO_LIBRARIES}") 42 | FW_UTIL(dgfirmware "" "" "") 43 | FW_UTIL(dgn3500sum "" "" "") 44 | FW_UTIL(dlink-sge-image "" "" "${OPENSSL_CRYPTO_LIBRARIES}") 45 | FW_UTIL(dns313-header "" "" "") 46 | FW_UTIL(edimax_fw_header "" "" "") 47 | FW_UTIL(encode_crc "" "" "") 48 | FW_UTIL(fix-u-media-header src/cyg_crc32.c "" "") 49 | FW_UTIL(hcsmakeimage src/bcmalgo.c "" "") 50 | FW_UTIL(imagetag "src/imagetag_cmdline.c;src/cyg_crc32.c" "" "") 51 | FW_UTIL(iptime-crc32 src/cyg_crc32.c "" "") 52 | FW_UTIL(iptime-naspkg "" "" "") 53 | FW_UTIL(jcgimage "" "" "${ZLIB_LIBRARIES}") 54 | FW_UTIL(linksys-addfwhdr src/cyg_crc32.c "" "") 55 | FW_UTIL(lxlfw "" "" "") 56 | FW_UTIL(lzma2eva "" "" "${ZLIB_LIBRARIES}") 57 | FW_UTIL(makeamitbin "" "" "") 58 | FW_UTIL(mkbrncmdline "" "" "") 59 | FW_UTIL(mkbrnimg "" "" "") 60 | FW_UTIL(mkbuffaloimg "" "" "") 61 | FW_UTIL(mkcameofw "" "" "") 62 | FW_UTIL(mkcasfw "" "" "") 63 | FW_UTIL(mkchkimg "" "" "") 64 | FW_UTIL(mkcsysimg "" "" "") 65 | FW_UTIL(mkdapimg "" "" "") 66 | FW_UTIL(mkdapimg2 "" "" "") 67 | FW_UTIL(mkdhpimg src/buffalo-lib.c "" "") 68 | FW_UTIL(mkdlinkfw src/mkdlinkfw-lib.c --std=c99 "${ZLIB_LIBRARIES}") 69 | FW_UTIL(mkdniimg "" "" "") 70 | FW_UTIL(mkedimaximg "" "" "") 71 | FW_UTIL(mkfwimage "" "-Wextra -D_FILE_OFFSET_BITS=64" "${ZLIB_LIBRARIES}") 72 | FW_UTIL(mkfwimage2 "" "" "${ZLIB_LIBRARIES}") 73 | FW_UTIL(mkh3cimg "" "" "") 74 | FW_UTIL(mkh3cvfs "" "" "") 75 | FW_UTIL(mkheader_gemtek "" "" "${ZLIB_LIBRARIES}") 76 | FW_UTIL(mkhilinkfw "" "" "${OPENSSL_CRYPTO_LIBRARIES}") 77 | FW_UTIL(mkmerakifw src/sha1.c "" "") 78 | FW_UTIL(mkmerakifw-old "" "" "") 79 | FW_UTIL(mkmylofw "" "" "") 80 | FW_UTIL(mkplanexfw src/sha1.c "" "") 81 | FW_UTIL(mkporayfw "" "" "") 82 | FW_UTIL(mkqdimg src/sha1.c "" "") 83 | FW_UTIL(mkrasimage "" --std=gnu99 "") 84 | FW_UTIL(mkrtn56uimg "" "" "${ZLIB_LIBRARIES}") 85 | FW_UTIL(mksenaofw src/md5.c --std=gnu99 "") 86 | FW_UTIL(mksercommfw "" "" "") 87 | FW_UTIL(mktitanimg "" "" "") 88 | FW_UTIL(mktplinkfw "src/mktplinkfw-lib.c;src/md5.c" -fgnu89-inline "") 89 | FW_UTIL(mktplinkfw2 "src/mktplinkfw-lib.c;src/md5.c" -fgnu89-inline "") 90 | FW_UTIL(mkwrggimg src/md5.c "" "") 91 | FW_UTIL(mkwrgimg src/md5.c "" "") 92 | FW_UTIL(mkzcfw src/cyg_crc32.c "" "") 93 | FW_UTIL(mkzynfw "" "" "") 94 | FW_UTIL(mkzyxelzldfw src/md5.c "" "") 95 | FW_UTIL(motorola-bin "" "" "") 96 | FW_UTIL(nand_ecc "" "" "") 97 | FW_UTIL(nec-enc "" --std=gnu99 "") 98 | FW_UTIL(nec-usbatermfw "" -D_DEFAULT_SOURCE "") 99 | FW_UTIL(nosimg-enc "" --std=gnu99 "") 100 | FW_UTIL(npk_pack_kernel "" "" "${ZLIB_LIBRARIES}") 101 | FW_UTIL(osbridge-crc "" "" "") 102 | FW_UTIL(oseama src/md5.c "" "") 103 | FW_UTIL(otrx "" "" "") 104 | FW_UTIL(pc1crypt "" "" "") 105 | FW_UTIL(ptgen src/cyg_crc32.c "" "") 106 | FW_UTIL(seama src/md5.c "" "") 107 | FW_UTIL(sign_dlink_ru src/md5.c "" "") 108 | FW_UTIL(spw303v "" "" "") 109 | FW_UTIL(srec2bin "" "" "") 110 | FW_UTIL(tplink-safeloader src/md5.c --std=gnu99 "") 111 | FW_UTIL(trx "" "" "") 112 | FW_UTIL(trx2edips "" "" "") 113 | FW_UTIL(trx2usr "" "" "") 114 | FW_UTIL(uimage_padhdr "" "" "${ZLIB_LIBRARIES}") 115 | FW_UTIL(uimage_sgehdr "" "" "${ZLIB_LIBRARIES}") 116 | FW_UTIL(wrt400n src/cyg_crc32.c "" "") 117 | FW_UTIL(xiaomifw "" "" "") 118 | FW_UTIL(xorimage "" "" "") 119 | if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") 120 | FW_UTIL(zycast "" "" "") 121 | endif() 122 | FW_UTIL(zyimage "" "" "") 123 | FW_UTIL(zynsig "" "" "") 124 | FW_UTIL(zytrx "" "" "") 125 | FW_UTIL(zyxbcm "" "" "") 126 | -------------------------------------------------------------------------------- /src/mkbrnimg.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * mkbrnimg.c - partially based on OpenWrt's wndr3700.c 4 | * 5 | * Copyright (C) 2011 Tobias Diedrich 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #define BPB 8 /* bits/byte */ 20 | 21 | static uint32_t crc32[1<> 1)) : (crc >> 1); 39 | crc32[n] = crc; 40 | } 41 | } 42 | 43 | static uint32_t crc32buf(const void *buf, size_t len) 44 | { 45 | uint32_t crc = 0xFFFFFFFF; 46 | const uint8_t *in = buf; 47 | 48 | for (; len; len--, in++) 49 | crc = crc32[(uint8_t)crc ^ *in] ^ (crc >> BPB); 50 | return ~crc; 51 | } 52 | 53 | static void usage(const char *) __attribute__ (( __noreturn__ )); 54 | 55 | static void usage(const char *mess) 56 | { 57 | fprintf(stderr, "Error: %s\n", mess); 58 | fprintf(stderr, "Usage: mkbrnimg [-o output_file] [-m magic] [-s signature] [-p crc32 poly] kernel_file [additional files]\n"); 59 | fprintf(stderr, "\n"); 60 | exit(1); 61 | } 62 | 63 | static void parseopts(int *argc, char ***argv) 64 | { 65 | char *endptr; 66 | int res; 67 | 68 | while ((res = getopt(*argc, *argv, "o:m:s:p:")) != -1) { 69 | switch (res) { 70 | default: 71 | usage("Unknown option"); 72 | break; 73 | case 'o': 74 | output_file = optarg; 75 | break; 76 | case 'm': 77 | magic = strtoul(optarg, &endptr, 0); 78 | if (endptr == optarg || *endptr != 0) 79 | usage("magic must be a decimal or hexadecimal 32-bit value"); 80 | break; 81 | case 's': 82 | signature = optarg; 83 | break; 84 | case 'p': 85 | crc32_poly = strtoul(optarg, &endptr, 0); 86 | if (endptr == optarg || *endptr != 0) 87 | usage("'crc32 poly' must be a decimal or hexadecimal 32-bit value"); 88 | break; 89 | } 90 | } 91 | *argc -= optind; 92 | *argv += optind; 93 | } 94 | 95 | static void appendfile(int outfd, char *path, int kernel) { 96 | int fd; 97 | size_t len, padded_len; 98 | char *input_file; 99 | uint32_t crc; 100 | char padding[0x400]; 101 | char footer[12]; 102 | 103 | memset(padding, 0xff, sizeof(padding)); 104 | 105 | // mmap input_file 106 | if ((fd = open(path, O_RDONLY)) < 0 107 | || (len = lseek(fd, 0, SEEK_END)) < 0 108 | || (input_file = mmap(0, len, PROT_READ, MAP_SHARED, fd, 0)) == (void *) (-1) 109 | || close(fd) < 0) 110 | { 111 | fprintf(stderr, "Error mapping file '%s': %s\n", path, strerror(errno)); 112 | exit(1); 113 | } 114 | 115 | // kernel should be lzma compressed image, not uImage 116 | if (kernel && 117 | (input_file[0] != (char)0x5d || 118 | input_file[1] != (char)0x00 || 119 | input_file[2] != (char)0x00 || 120 | input_file[3] != (char)0x80)) { 121 | fprintf(stderr, "lzma signature not found on kernel image.\n"); 122 | exit(1); 123 | } 124 | 125 | init_crc32(); 126 | crc = crc32buf(input_file, len); 127 | fprintf(stderr, "crc32 for '%s' is %08x.\n", path, crc); 128 | 129 | // write the file 130 | write(outfd, input_file, len); 131 | 132 | // write padding 133 | padded_len = ((len + sizeof(footer) + sizeof(padding) - 1) & ~(sizeof(padding) - 1)) - sizeof(footer); 134 | fprintf(stderr, "len=%08zx padded_len=%08zx\n", len, padded_len); 135 | write(outfd, padding, padded_len - len); 136 | 137 | // write footer 138 | footer[0] = (len >> 0) & 0xff; 139 | footer[1] = (len >> 8) & 0xff; 140 | footer[2] = (len >> 16) & 0xff; 141 | footer[3] = (len >> 24) & 0xff; 142 | footer[4] = (magic >> 0) & 0xff; 143 | footer[5] = (magic >> 8) & 0xff; 144 | footer[6] = (magic >> 16) & 0xff; 145 | footer[7] = (magic >> 24) & 0xff; 146 | footer[8] = (crc >> 0) & 0xff; 147 | footer[9] = (crc >> 8) & 0xff; 148 | footer[10] = (crc >> 16) & 0xff; 149 | footer[11] = (crc >> 24) & 0xff; 150 | write(outfd, footer, sizeof(footer)); 151 | 152 | munmap(input_file, len); 153 | } 154 | 155 | int main(int argc, char **argv) 156 | { 157 | int outfd; 158 | int i; 159 | 160 | parseopts(&argc, &argv); 161 | 162 | if (argc < 1) 163 | usage("wrong number of arguments"); 164 | 165 | if ((outfd = open(output_file, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) 166 | { 167 | fprintf(stderr, "Error opening '%s' for writing: %s\n", output_file, strerror(errno)); 168 | exit(1); 169 | } 170 | 171 | for (i=0; i 10 | 11 | Based on previous unattributed work. 12 | 13 | ************************************************************************* */ 14 | 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | unsigned char PidDataWW[70] = 22 | { 23 | 0x73, 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x59, 0x50, 0x35, 0x37, 0x32, 24 | 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 25 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x37, 26 | 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 27 | 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D, 28 | } ; 29 | 30 | unsigned char PidDataDE[70] = 31 | { 32 | 0x73, 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x59, 0x50, 0x35, 0x37, 0x32, 33 | 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 34 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x37, 35 | 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 36 | 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D, 37 | } ; 38 | 39 | unsigned char PidDataNA[70] = 40 | { 41 | 0x73, 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x59, 0x50, 0x35, 0x37, 0x32, 42 | 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 43 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x37, 44 | 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 45 | 0x45, 0x72, 0x43, 0x6F, 0x4D, 0x6D, 46 | } ; 47 | 48 | /* ******************************************************************* 49 | Reads the file into memory and returns pointer to the buffer. */ 50 | static char *readfile(char *filename, int *size) 51 | { 52 | FILE *fp; 53 | char *buffer; 54 | struct stat info; 55 | 56 | if (stat(filename,&info)!=0) 57 | return NULL; 58 | 59 | if ((fp=fopen(filename,"r"))==NULL) 60 | return NULL; 61 | 62 | buffer=NULL; 63 | for (;;) 64 | { 65 | if ((buffer=(char *)malloc(info.st_size+1))==NULL) 66 | break; 67 | 68 | if (fread(buffer,1,info.st_size,fp)!=info.st_size) 69 | { 70 | free(buffer); 71 | buffer=NULL; 72 | break; 73 | } 74 | 75 | buffer[info.st_size]='\0'; 76 | if(size) *size = info.st_size; 77 | 78 | break; 79 | } 80 | 81 | (void)fclose(fp); 82 | 83 | return buffer; 84 | } 85 | 86 | 87 | /* ******************************************************************* */ 88 | int main(int argc, char** argv) 89 | { 90 | unsigned long start, i; 91 | char *endptr, *buffer, *p; 92 | int count; // size of file in bytes 93 | unsigned short sum = 0, sum1 = 0; 94 | char sumbuf[8 + 8 + 1]; 95 | 96 | if(argc < 3) { 97 | printf("ERROR: Argument missing!\n\nUsage %s filename starting offset in hex [PID code]\n\n", argv[0]); 98 | return 1; 99 | } 100 | 101 | 102 | FILE *fp = fopen(argv[1], "a"); 103 | if(!fp) { 104 | printf("ERROR: File not writeable!\n"); 105 | return 1; 106 | } 107 | if(argc == 4) 108 | { 109 | printf("%s: PID type: %s\n", argv[0], argv[3]); 110 | if(strcmp(argv[3], "DE")==0) 111 | fwrite(PidDataDE, sizeof(PidDataDE), sizeof(char), fp); /* write DE pid */ 112 | else if(strcmp(argv[3], "NA")==0) 113 | fwrite(PidDataNA, sizeof(PidDataNA), sizeof(char), fp); /* write NA pid */ 114 | else /* if(strcmp(argv[3], "WW")) */ 115 | fwrite(PidDataWW, sizeof(PidDataWW), sizeof(char), fp); /* write WW pid */ 116 | } 117 | else 118 | fwrite(PidDataWW, sizeof(PidDataWW), sizeof(char), fp); /* write WW pid if unspecified */ 119 | 120 | fclose(fp); 121 | 122 | /* Read the file to calculate the checksums */ 123 | buffer = readfile(argv[1], &count); 124 | if(!buffer) { 125 | printf("ERROR: File %s not found!\n", argv[1]); 126 | return 1; 127 | } 128 | 129 | p = buffer; 130 | for(i = 0; i < count; i++) 131 | { 132 | sum += p[i]; 133 | } 134 | 135 | start = strtol(argv[2], &endptr, 16); 136 | p = buffer+start; 137 | for(i = 0; i < count - start; i++) 138 | { 139 | sum1 += p[i]; 140 | } 141 | 142 | sprintf(sumbuf,"%04X%04X",sum1,sum); 143 | /* Append the 2 checksums to end of file */ 144 | fp = fopen(argv[1], "a"); 145 | if(!fp) { 146 | printf("ERROR: File not writeable!\n"); 147 | return 1; 148 | } 149 | fwrite(sumbuf, 8, sizeof(char), fp); 150 | fclose(fp); 151 | free(buffer); 152 | return 0; 153 | } 154 | -------------------------------------------------------------------------------- /src/mkbuffaloimg.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright (C) 2009 Gabor Juhos 4 | * Copyright (C) 2016 FUKAUMI Naoki 5 | * 6 | * Based on mkdniimg.c 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include /* for unlink() */ 14 | #include 15 | #include /* for getopt() */ 16 | #include 17 | #include 18 | #include 19 | 20 | #define DNI_HDR_LEN 128 21 | 22 | /* 23 | * Globals 24 | */ 25 | static char *ifname; 26 | static char *progname; 27 | static char *ofname; 28 | static char *version = "0.00_0.00"; 29 | static char *region = "JP"; 30 | static char *rootfs_size; 31 | static char *kernel_size; 32 | 33 | static char *board_id; 34 | /* 35 | * Message macros 36 | */ 37 | #define ERR(fmt, ...) do { \ 38 | fflush(0); \ 39 | fprintf(stderr, "[%s] *** error: " fmt "\n", \ 40 | progname, ## __VA_ARGS__ ); \ 41 | } while (0) 42 | 43 | #define ERRS(fmt, ...) do { \ 44 | int save = errno; \ 45 | fflush(0); \ 46 | fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \ 47 | progname, ## __VA_ARGS__, strerror(save)); \ 48 | } while (0) 49 | 50 | void usage(int status) 51 | { 52 | FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; 53 | 54 | fprintf(stream, "Usage: %s [OPTIONS...]\n", progname); 55 | fprintf(stream, 56 | "\n" 57 | "Options:\n" 58 | " -B create image for the board specified with \n" 59 | " -i read input from the file \n" 60 | " -o write output to the file \n" 61 | " -v set image version to \n" 62 | " -r set image region to \n" 63 | " -R set RootfsSize to \n" 64 | " -K set KernelSize to \n" 65 | " -h show this screen\n" 66 | ); 67 | 68 | exit(status); 69 | } 70 | 71 | int main(int argc, char *argv[]) 72 | { 73 | int res = EXIT_FAILURE; 74 | int buflen; 75 | int err; 76 | struct stat st; 77 | char *buf; 78 | int i; 79 | uint8_t csum; 80 | 81 | FILE *outfile, *infile; 82 | 83 | progname = basename(argv[0]); 84 | 85 | while ( 1 ) { 86 | int c; 87 | 88 | c = getopt(argc, argv, "B:i:o:v:r:R:K:h"); 89 | if (c == -1) 90 | break; 91 | 92 | switch (c) { 93 | case 'B': 94 | board_id = optarg; 95 | break; 96 | case 'i': 97 | ifname = optarg; 98 | break; 99 | case 'o': 100 | ofname = optarg; 101 | break; 102 | case 'v': 103 | version = optarg; 104 | break; 105 | case 'r': 106 | region = optarg; 107 | break; 108 | case 'R': 109 | rootfs_size = optarg; 110 | break; 111 | case 'K': 112 | kernel_size = optarg; 113 | break; 114 | case 'h': 115 | usage(EXIT_SUCCESS); 116 | break; 117 | default: 118 | usage(EXIT_FAILURE); 119 | break; 120 | } 121 | } 122 | 123 | if (board_id == NULL) { 124 | ERR("no board specified"); 125 | goto err; 126 | } 127 | 128 | if (rootfs_size == NULL) { 129 | ERR("no rootfs_size specified"); 130 | goto err; 131 | } 132 | 133 | if (kernel_size == NULL) { 134 | ERR("no kernel_size specified"); 135 | goto err; 136 | } 137 | 138 | if (ifname == NULL) { 139 | ERR("no input file specified"); 140 | goto err; 141 | } 142 | 143 | if (ofname == NULL) { 144 | ERR("no output file specified"); 145 | goto err; 146 | } 147 | 148 | err = stat(ifname, &st); 149 | if (err){ 150 | ERRS("stat failed on %s", ifname); 151 | goto err; 152 | } 153 | 154 | buflen = st.st_size + DNI_HDR_LEN + 1; 155 | buf = malloc(buflen); 156 | if (!buf) { 157 | ERR("no memory for buffer\n"); 158 | goto err; 159 | } 160 | 161 | memset(buf, 0, DNI_HDR_LEN); 162 | snprintf(buf, DNI_HDR_LEN, "device:%s\nversion:%s\nregion:%s\n" 163 | "RootfsSize:%s\nKernelSize:%s\nInfoHeadSize:128\n", 164 | board_id, version, region, rootfs_size, kernel_size); 165 | buf[DNI_HDR_LEN - 2] = 0x12; 166 | buf[DNI_HDR_LEN - 1] = 0x32; 167 | 168 | infile = fopen(ifname, "r"); 169 | if (infile == NULL) { 170 | ERRS("could not open \"%s\" for reading", ifname); 171 | goto err_free; 172 | } 173 | 174 | errno = 0; 175 | fread(buf + DNI_HDR_LEN, st.st_size, 1, infile); 176 | if (errno != 0) { 177 | ERRS("unable to read from file %s", ifname); 178 | goto err_close_in; 179 | } 180 | 181 | csum = 0; 182 | for (i = 0; i < (st.st_size + DNI_HDR_LEN); i++) 183 | csum += buf[i]; 184 | 185 | csum = 0xff - csum; 186 | buf[st.st_size + DNI_HDR_LEN] = csum; 187 | 188 | outfile = fopen(ofname, "w"); 189 | if (outfile == NULL) { 190 | ERRS("could not open \"%s\" for writing", ofname); 191 | goto err_close_in; 192 | } 193 | 194 | errno = 0; 195 | fwrite(buf, buflen, 1, outfile); 196 | if (errno) { 197 | ERRS("unable to write to file %s", ofname); 198 | goto err_close_out; 199 | } 200 | 201 | res = EXIT_SUCCESS; 202 | 203 | fflush(outfile); 204 | 205 | err_close_out: 206 | fclose(outfile); 207 | if (res != EXIT_SUCCESS) { 208 | unlink(ofname); 209 | } 210 | 211 | err_close_in: 212 | fclose(infile); 213 | 214 | err_free: 215 | free(buf); 216 | 217 | err: 218 | return res; 219 | } 220 | -------------------------------------------------------------------------------- /src/lzma2eva.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | lzma2eva - convert lzma-compressed file to AVM EVA bootloader format 4 | Copyright (C) 2007 Enrik Berkhan 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include /* crc32 */ 11 | 12 | #define checksum_add32(csum, data) \ 13 | csum += ((uint8_t *)&data)[0]; \ 14 | csum += ((uint8_t *)&data)[1]; \ 15 | csum += ((uint8_t *)&data)[2]; \ 16 | csum += ((uint8_t *)&data)[3]; 17 | 18 | void 19 | usage(void) 20 | { 21 | fprintf(stderr, "usage: lzma2eva \n"); 22 | exit(1); 23 | } 24 | 25 | void 26 | pexit(const char *msg) 27 | { 28 | perror(msg); 29 | exit(1); 30 | } 31 | 32 | int 33 | main(int argc, char *argv[]) 34 | { 35 | 36 | const char *infile, *outfile; 37 | FILE *in, *out; 38 | static uint8_t buf[4096]; 39 | size_t elems; 40 | 41 | uint8_t properties; 42 | uint32_t dictsize; 43 | uint64_t datasize; 44 | 45 | uint32_t magic = 0xfeed1281L; 46 | uint32_t reclength = 0; 47 | fpos_t reclengthpos; 48 | uint32_t loadaddress = 0; 49 | uint32_t type = 0x075a0201L; /* might be 7Z 2.1? */ 50 | uint32_t checksum = 0; 51 | 52 | uint32_t compsize = 0; 53 | fpos_t compsizepos; 54 | uint32_t datasize32 = 0; 55 | uint32_t datacrc32 = crc32(0, 0, 0); 56 | 57 | uint32_t zero = 0; 58 | uint32_t entry = 0; 59 | 60 | if (argc != 5) 61 | usage(); 62 | 63 | /* "parse" command line */ 64 | loadaddress = strtoul(argv[1], 0, 0); 65 | entry = strtoul(argv[2], 0, 0); 66 | infile = argv[3]; 67 | outfile = argv[4]; 68 | 69 | in = fopen(infile, "rb"); 70 | if (!in) 71 | pexit("fopen"); 72 | out = fopen(outfile, "w+b"); 73 | if (!out) 74 | pexit("fopen"); 75 | 76 | /* read LZMA header */ 77 | if (1 != fread(&properties, sizeof properties, 1, in)) 78 | pexit("fread"); 79 | if (1 != fread(&dictsize, sizeof dictsize, 1, in)) 80 | pexit("fread"); 81 | if (1 != fread(&datasize, sizeof datasize, 1, in)) 82 | pexit("fread"); 83 | 84 | /* write EVA header */ 85 | if (1 != fwrite(&magic, sizeof magic, 1, out)) 86 | pexit("fwrite"); 87 | if (fgetpos(out, &reclengthpos)) 88 | pexit("fgetpos"); 89 | if (1 != fwrite(&reclength, sizeof reclength, 1, out)) 90 | pexit("fwrite"); 91 | if (1 != fwrite(&loadaddress, sizeof loadaddress, 1, out)) 92 | pexit("fwrite"); 93 | if (1 != fwrite(&type, sizeof type, 1, out)) 94 | pexit("fwrite"); 95 | 96 | /* write EVA LZMA header */ 97 | if (fgetpos(out, &compsizepos)) 98 | pexit("fgetpos"); 99 | if (1 != fwrite(&compsize, sizeof compsize, 1, out)) 100 | pexit("fwrite"); 101 | /* XXX check length */ 102 | datasize32 = (uint32_t)datasize; 103 | if (1 != fwrite(&datasize32, sizeof datasize32, 1, out)) 104 | pexit("fwrite"); 105 | if (1 != fwrite(&datacrc32, sizeof datacrc32, 1, out)) 106 | pexit("fwrite"); 107 | 108 | /* write modified LZMA header */ 109 | if (1 != fwrite(&properties, sizeof properties, 1, out)) 110 | pexit("fwrite"); 111 | if (1 != fwrite(&dictsize, sizeof dictsize, 1, out)) 112 | pexit("fwrite"); 113 | if (1 != fwrite(&zero, 3, 1, out)) 114 | pexit("fwrite"); 115 | 116 | /* copy compressed data, calculate crc32 */ 117 | while (0 < (elems = fread(&buf, sizeof buf[0], sizeof buf, in))) { 118 | compsize += elems; 119 | if (elems != fwrite(&buf, sizeof buf[0], elems, out)) 120 | pexit("fwrite"); 121 | datacrc32 = crc32(datacrc32, buf, elems); 122 | } 123 | if (ferror(in)) 124 | pexit("fread"); 125 | fclose(in); 126 | 127 | /* re-write record length */ 128 | reclength = compsize + 24; 129 | if (fsetpos(out, &reclengthpos)) 130 | pexit("fsetpos"); 131 | if (1 != fwrite(&reclength, sizeof reclength, 1, out)) 132 | pexit("fwrite"); 133 | 134 | /* re-write EVA LZMA header including size and data crc */ 135 | if (fsetpos(out, &compsizepos)) 136 | pexit("fsetpos"); 137 | if (1 != fwrite(&compsize, sizeof compsize, 1, out)) 138 | pexit("fwrite"); 139 | if (1 != fwrite(&datasize32, sizeof datasize32, 1, out)) 140 | pexit("fwrite"); 141 | if (1 != fwrite(&datacrc32, sizeof datacrc32, 1, out)) 142 | pexit("fwrite"); 143 | 144 | /* calculate record checksum */ 145 | checksum += reclength; 146 | checksum += loadaddress; 147 | checksum_add32(checksum, type); 148 | checksum_add32(checksum, compsize); 149 | checksum_add32(checksum, datasize32); 150 | checksum_add32(checksum, datacrc32); 151 | if (fseek(out, 0, SEEK_CUR)) 152 | pexit("fseek"); 153 | while (0 < (elems = fread(&buf, sizeof buf[0], sizeof buf, out))) { 154 | size_t i; 155 | for (i = 0; i < elems; ++i) 156 | checksum += buf[i]; 157 | } 158 | if (ferror(out)) 159 | pexit("fread"); 160 | if (fseek(out, 0, SEEK_CUR)) 161 | pexit("fseek"); 162 | 163 | checksum = ~checksum + 1; 164 | if (1 != fwrite(&checksum, sizeof checksum, 1, out)) 165 | pexit("fwrite"); 166 | 167 | /* write entry record */ 168 | if (1 != fwrite(&zero, sizeof zero, 1, out)) 169 | pexit("fwrite"); 170 | if (1 != fwrite(&entry, sizeof entry, 1, out)) 171 | pexit("fwrite"); 172 | 173 | if (fclose(out)) 174 | pexit("fclose"); 175 | 176 | return 0; 177 | } 178 | -------------------------------------------------------------------------------- /src/mkheader_gemtek.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * Copyright (C) 2014 Claudio Leite 4 | */ 5 | 6 | /* 7 | * Builds a proper flash image for routers using some Gemtek 8 | * OEM boards. These include the Airlink101 AR725W, the 9 | * Asante SmartHub 600 (AWRT-600N), and Linksys WRT100/110. 10 | * 11 | * The resulting image is compatible with the factory firmware 12 | * web upgrade and TFTP interface. 13 | * 14 | * To build: 15 | * gcc -O2 -o mkheader_gemtek mkheader_gemtek.c -lz 16 | * 17 | * Claudio Leite 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include /* for crc32() */ 26 | 27 | /* 28 | * The header is in little-endian format. In case 29 | * we are on a BE host, we need to swap binary 30 | * values. 31 | */ 32 | #ifdef __APPLE__ 33 | # include 34 | # define le32 OSSwapHostToLittleInt32 35 | #else 36 | # if defined(__linux__) 37 | # include 38 | # if __BYTE_ORDER == __BIG_ENDIAN 39 | # define CPU_BIG_ENDIAN 40 | # endif 41 | # else 42 | # include /* BSD's should have this */ 43 | # if _BYTE_ORDER == _BIG_ENDIAN 44 | # define CPU_BIG_ENDIAN 45 | # endif 46 | # endif 47 | # ifdef CPU_BIG_ENDIAN 48 | # define le32(x) (((x & 0xff000000) >> 24) | \ 49 | ((x & 0x00ff0000) >> 8) | \ 50 | ((x & 0x0000ff00) << 8) | \ 51 | ((x & 0x000000ff) << 24)) 52 | # else 53 | # define le32(x) (x) 54 | # endif 55 | #endif 56 | 57 | struct gemtek_header { 58 | uint8_t magic[4]; 59 | uint8_t version[4]; 60 | uint32_t product_id; 61 | uint32_t imagesz; 62 | uint32_t checksum; 63 | uint32_t fast_checksum; 64 | uint8_t build[4]; 65 | uint8_t lang[4]; 66 | }; 67 | 68 | #define HDRLEN sizeof(struct gemtek_header) 69 | 70 | struct machines { 71 | char *desc; 72 | char *id; 73 | uint32_t maxsize; 74 | struct gemtek_header header; 75 | }; 76 | 77 | struct machines mach_def[] = { 78 | {"Airlink101 AR725W", "ar725w", 0x340000, 79 | {"GMTK", "1003", le32(0x03000001), 0, 0, 80 | 0, "01\0\0", "EN\0\0"}}, 81 | {"Asante AWRT-600N", "awrt600n", 0x340000, 82 | {"A600", "1005", le32(0x03000001), 0, 0, 83 | 0, "01\0\0", "EN\0\0"}}, 84 | {"Linksys WRT100", "wrt100", 0x320000, 85 | {"GMTK", "1007", le32(0x03040001), 0, 0, 86 | 0, "2\0\0\0", "EN\0\0"}}, 87 | {"Linksys WRT110", "wrt110", 0x320000, 88 | {"GMTK", "1007", le32(0x03040001), 0, 0, 89 | 0, "2\0\0\0", "EN\0\0"}}, 90 | {0} 91 | }; 92 | 93 | int 94 | main(int argc, char *argv[]) 95 | { 96 | unsigned long res, flen; 97 | struct gemtek_header my_hdr; 98 | FILE *f, *f_out; 99 | int image_type = -1, index; 100 | uint8_t *buf; 101 | uint32_t crc; 102 | 103 | if (argc < 3) { 104 | fprintf(stderr, "mkheader_gemtek [machine ID]\n"); 105 | fprintf(stderr, " where [machine ID] is one of:\n"); 106 | for (index = 0; mach_def[index].desc != 0; index++) { 107 | fprintf(stderr, " %-10s %s", mach_def[index].id, mach_def[index].desc); 108 | if (index == 0) 109 | fprintf(stderr, " (default)\n"); 110 | else 111 | fprintf(stderr, "\n"); 112 | } 113 | 114 | exit(-1); 115 | } 116 | 117 | if (argc == 4) { 118 | for(index = 0; mach_def[index].id != 0; index++) { 119 | if(strcmp(mach_def[index].id, argv[3]) == 0) { 120 | image_type = index; 121 | break; 122 | } 123 | } 124 | 125 | if(image_type == -1) { 126 | fprintf(stderr, "\nERROR: invalid machine type\n"); 127 | exit(-1); 128 | } 129 | } else 130 | image_type = 0; 131 | 132 | printf("Opening %s...\n", argv[1]); 133 | 134 | f = fopen(argv[1], "r"); 135 | if(!f) { 136 | fprintf(stderr, "\nERROR: couldn't open input image\n"); 137 | exit(-1); 138 | } 139 | 140 | fseek(f, 0, SEEK_END); 141 | flen = (unsigned long) ftell(f); 142 | 143 | printf(" %lu (0x%lX) bytes long\n", flen, flen); 144 | 145 | if (flen > mach_def[image_type].maxsize) { 146 | fprintf(stderr, "\nERROR: image exceeds maximum compatible size\n"); 147 | goto f_error; 148 | } 149 | 150 | buf = malloc(flen + HDRLEN); 151 | if (!buf) { 152 | fprintf(stderr, "\nERROR: couldn't allocate buffer\n"); 153 | goto f_error; 154 | } 155 | rewind(f); 156 | res = fread(buf + HDRLEN, 1, flen, f); 157 | if (res != flen) { 158 | perror("Couldn't read entire file: fread()"); 159 | goto f_error; 160 | } 161 | fclose(f); 162 | 163 | printf("\nCreating %s...\n", argv[2]); 164 | 165 | memcpy(&my_hdr, &mach_def[image_type].header, HDRLEN); 166 | 167 | printf(" Using %s magic\n", mach_def[image_type].desc); 168 | 169 | my_hdr.imagesz = le32(flen + HDRLEN); 170 | memcpy(my_hdr.lang, "EN", 2); 171 | 172 | memcpy(buf, &my_hdr, HDRLEN); 173 | 174 | crc = crc32(0, buf, flen + HDRLEN); 175 | printf(" CRC32: %08X\n", crc); 176 | 177 | my_hdr.checksum = le32(crc); 178 | memcpy(buf, &my_hdr, HDRLEN); 179 | 180 | printf(" Writing...\n"); 181 | 182 | f_out = fopen(argv[2], "w"); 183 | if(!f_out) { 184 | fprintf(stderr, "\nERROR: couldn't open output image\n"); 185 | exit(-1); 186 | } 187 | 188 | fwrite(buf, 1, flen + HDRLEN, f_out); 189 | 190 | fclose(f_out); 191 | 192 | free(buf); 193 | return 0; 194 | 195 | f_error: 196 | fclose(f); 197 | exit(-1); 198 | } 199 | -------------------------------------------------------------------------------- /src/cyg_crc16.c: -------------------------------------------------------------------------------- 1 | //========================================================================== 2 | // 3 | // crc16.c 4 | // 5 | // 16 bit CRC with polynomial x^16+x^12+x^5+1 6 | // 7 | //========================================================================== 8 | //####ECOSGPLCOPYRIGHTBEGIN#### 9 | // ------------------------------------------- 10 | // This file is part of eCos, the Embedded Configurable Operating System. 11 | // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. 12 | // Copyright (C) 2002 Gary Thomas 13 | // 14 | // eCos is free software; you can redistribute it and/or modify it under 15 | // the terms of the GNU General Public License as published by the Free 16 | // Software Foundation; either version 2 or (at your option) any later version. 17 | // 18 | // eCos is distributed in the hope that it will be useful, but WITHOUT ANY 19 | // WARRANTY; without even the implied warranty of MERCHANTABILITY or 20 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 21 | // for more details. 22 | // 23 | // You should have received a copy of the GNU General Public License along 24 | // with eCos; if not, write to the Free Software Foundation, Inc., 25 | // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 26 | // 27 | // As a special exception, if other files instantiate templates or use macros 28 | // or inline functions from this file, or you compile this file and link it 29 | // with other works to produce a work based on this file, this file does not 30 | // by itself cause the resulting work to be covered by the GNU General Public 31 | // License. However the source code for this file must still be made available 32 | // in accordance with section (3) of the GNU General Public License. 33 | // 34 | // This exception does not invalidate any other reasons why a work based on 35 | // this file might be covered by the GNU General Public License. 36 | // 37 | // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. 38 | // at http://sources.redhat.com/ecos/ecos-license/ 39 | // ------------------------------------------- 40 | //####ECOSGPLCOPYRIGHTEND#### 41 | //========================================================================== 42 | //#####DESCRIPTIONBEGIN#### 43 | // 44 | // Author(s): gthomas 45 | // Contributors: gthomas,asl 46 | // Date: 2001-01-31 47 | // Purpose: 48 | // Description: 49 | // 50 | // This code is part of eCos (tm). 51 | // 52 | //####DESCRIPTIONEND#### 53 | // 54 | //========================================================================== 55 | 56 | #if 0 57 | #include 58 | #else 59 | #include "cyg_crc.h" 60 | #endif 61 | 62 | // Table of CRC constants - implements x^16+x^12+x^5+1 63 | static const cyg_uint16 crc16_tab[] = { 64 | 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 65 | 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 66 | 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 67 | 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 68 | 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 69 | 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 70 | 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 71 | 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 72 | 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 73 | 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 74 | 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 75 | 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 76 | 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 77 | 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 78 | 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 79 | 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 80 | 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 81 | 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 82 | 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 83 | 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 84 | 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 85 | 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 86 | 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 87 | 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 88 | 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 89 | 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 90 | 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 91 | 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 92 | 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 93 | 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 94 | 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 95 | 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0, 96 | }; 97 | 98 | cyg_uint16 99 | cyg_crc16(void *ptr, int len) 100 | { 101 | unsigned char *buf = ptr; 102 | int i; 103 | cyg_uint16 cksum; 104 | 105 | cksum = 0; 106 | for (i = 0; i < len; i++) { 107 | cksum = crc16_tab[((cksum>>8) ^ *buf++) & 0xFF] ^ (cksum << 8); 108 | } 109 | return cksum; 110 | } 111 | 112 | -------------------------------------------------------------------------------- /src/sign_dlink_ru.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * This program is designed to sign firmware images so they are accepted 4 | * by D-Link DIR-882 R1 WebUIs. 5 | * 6 | * Copyright (C) 2020 Andrew Pikler 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "md5.h" 18 | 19 | #define BUF_SIZE 4096 20 | #define MD5_HASH_LEN 16 21 | 22 | 23 | typedef struct _md5_digest_t { 24 | uint8_t digest[MD5_HASH_LEN]; 25 | } md5_digest_t; 26 | 27 | typedef struct _salt_t { 28 | char* salt_ascii; 29 | uint8_t* salt_bin; 30 | size_t salt_bin_len; 31 | } salt_t; 32 | 33 | void read_file_bytes(FILE* f, MD5_CTX* md5_ctx) { 34 | uint8_t buf[BUF_SIZE]; 35 | size_t bytes_read; 36 | rewind(f); 37 | 38 | while (0 != (bytes_read = fread(buf, sizeof(uint8_t), BUF_SIZE, f))) { 39 | MD5_Update(md5_ctx, buf, bytes_read); 40 | } 41 | 42 | if (!feof(f)) { 43 | printf("Error: expected to be at EOF\n"); 44 | exit(-1); 45 | } 46 | } 47 | 48 | void add_magic_bytes(FILE* f) { 49 | char magic_bytes[] = { 0x00, 0xc0, 0xff, 0xee }; 50 | size_t magic_bytes_len = 4; 51 | fwrite(magic_bytes, magic_bytes_len, 1, f); 52 | } 53 | 54 | /** 55 | * Add the signature produced by this salt to the file 56 | * The signature consists by creating an MD5 digest wht the salt bytes plus 57 | * all of the bytes in the firmware file, then adding the magic bytes to the 58 | * file 59 | */ 60 | void add_signature(FILE* f, salt_t* salt) { 61 | md5_digest_t digest; 62 | MD5_CTX md5_context; 63 | 64 | MD5_Init(&md5_context); 65 | MD5_Update(&md5_context, salt->salt_bin, salt->salt_bin_len); 66 | read_file_bytes(f, &md5_context); 67 | MD5_Final(digest.digest, &md5_context); 68 | 69 | fwrite(&digest.digest, sizeof(uint8_t), MD5_HASH_LEN, f); 70 | add_magic_bytes(f); 71 | } 72 | 73 | void add_version_suffix(FILE* f) { 74 | char* version_suffix = "c0ffeef0rge"; 75 | fseek(f, 0, SEEK_END); 76 | fwrite(version_suffix, sizeof(char), strlen(version_suffix), f); 77 | } 78 | 79 | int asciihex_to_int(char c) { 80 | if(c >= '0' && c <= 'F') 81 | return c - '0'; 82 | 83 | if(c >= 'a' && c <= 'f') 84 | return 10 + c - 'a'; 85 | return -1; 86 | } 87 | 88 | /** 89 | * Verify this is a valid hex string to convert 90 | */ 91 | void verify_valid_hex_str(char* s) { 92 | int i; 93 | int s_len = strlen(s); 94 | if (s_len == 0) { 95 | printf("invalid empty salt: %s\n", s); 96 | exit(-1); 97 | } 98 | 99 | if (s_len % 2 != 0) { 100 | printf("invalid odd len salt: %s\n", s); 101 | exit(-1); 102 | } 103 | 104 | for (i = 0; i < s_len; ++i) { 105 | if (asciihex_to_int(s[i]) < 0) { 106 | printf("invalid salt (invalid hex char): %s\n", s); 107 | exit(-1); 108 | } 109 | } 110 | } 111 | 112 | /** 113 | * Convert a hex ascii string to an allocated binary array. This array must be free'd 114 | */ 115 | uint8_t* convert_hex_to_bin(char * s) { 116 | int i; 117 | int s_len = strlen(s); 118 | 119 | uint8_t* ret = malloc(s_len / 2); 120 | for (i = 0; i < s_len; i += 2) { 121 | ret[i / 2] = (asciihex_to_int(s[i]) << 4) | asciihex_to_int(s[i + 1]); 122 | } 123 | 124 | return ret; 125 | } 126 | 127 | void init_salt(salt_t* salt, char * salt_ascii) { 128 | salt->salt_ascii = salt_ascii; 129 | salt->salt_bin = convert_hex_to_bin(salt_ascii); 130 | salt->salt_bin_len = strlen(salt_ascii) / 2; 131 | } 132 | 133 | void free_salt(salt_t* salt) { 134 | free(salt->salt_bin); 135 | } 136 | 137 | /** 138 | * Verify that the arguments are valid, or exit with failure 139 | */ 140 | void verify_args(int argc, char** argv) { 141 | int i; 142 | 143 | if (argc < 3) { 144 | printf("Usage: %s ... \n", argv[0]); 145 | exit(1); 146 | } 147 | 148 | for (i = 2; i < argc; i++) { 149 | verify_valid_hex_str(argv[i]); 150 | } 151 | } 152 | 153 | FILE* make_out_file(char* filename) { 154 | uint8_t buf[BUF_SIZE]; 155 | int bytes_read; 156 | char* suffix = ".new"; 157 | int new_filename_len = strlen(filename) + strlen(suffix) + 1; 158 | char* new_filename = malloc(new_filename_len); 159 | strcpy(new_filename, filename); 160 | strcat(new_filename, suffix); 161 | 162 | FILE* f = fopen(filename, "r+"); 163 | if (!f) { 164 | printf("cannot open file %s\n", filename); 165 | exit(2); 166 | } 167 | 168 | FILE* out = fopen(new_filename, "w+"); 169 | free(new_filename); 170 | if (!out) { 171 | printf("cannot open file %s\n", filename); 172 | exit(2); 173 | } 174 | 175 | while (0 != (bytes_read = fread(buf, sizeof(uint8_t), BUF_SIZE, f))) { 176 | fwrite(buf, sizeof(uint8_t), bytes_read, out); 177 | } 178 | fclose(f); 179 | return out; 180 | } 181 | 182 | /** 183 | * Sign the firmware file after all of our checks have completed 184 | */ 185 | void sign_firmware(char* filename, char** salts, int num_salts) { 186 | int i; 187 | salt_t salt; 188 | FILE* f = make_out_file(filename); 189 | 190 | // add a version suffix string - dlink versions do something similar before the first signature 191 | add_version_suffix(f); 192 | 193 | //for each of the salts we are supplied with 194 | for (i = 0; i < num_salts; i++) { 195 | char* salt_str = salts[i]; 196 | // convert this str to binary 197 | init_salt(&salt, salt_str); 198 | 199 | // add the signature to the firmware file produced from this salt 200 | add_signature(f, &salt); 201 | free_salt(&salt); 202 | printf("Signed with salt: %s\n", salt_str); 203 | } 204 | 205 | fclose(f); 206 | } 207 | 208 | 209 | int main(int argc, char ** argv) { 210 | verify_args(argc, argv); 211 | sign_firmware(argv[1], argv+2, argc-2); 212 | return 0; 213 | } 214 | -------------------------------------------------------------------------------- /src/mkwrgimg.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright (C) 2011 Gabor Juhos 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "md5.h" 18 | 19 | #define ERR(fmt, ...) do { \ 20 | fflush(0); \ 21 | fprintf(stderr, "[%s] *** error: " fmt "\n", \ 22 | progname, ## __VA_ARGS__ ); \ 23 | } while (0) 24 | 25 | #define ERRS(fmt, ...) do { \ 26 | int save = errno; \ 27 | fflush(0); \ 28 | fprintf(stderr, "[%s] *** error: " fmt ", %s\n", \ 29 | progname, ## __VA_ARGS__, strerror(save)); \ 30 | } while (0) 31 | 32 | #define WRG_MAGIC 0x20040220 33 | 34 | struct wrg_header { 35 | char signature[32]; 36 | uint32_t magic1; 37 | uint32_t magic2; 38 | uint32_t size; 39 | uint32_t offset; 40 | char devname[32]; 41 | char digest[16]; 42 | } __attribute__ ((packed)); 43 | 44 | static char *progname; 45 | static char *ifname; 46 | static char *ofname; 47 | static char *signature; 48 | static char *dev_name; 49 | static uint32_t offset; 50 | static int big_endian; 51 | 52 | void usage(int status) 53 | { 54 | FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; 55 | 56 | fprintf(stream, "Usage: %s [OPTIONS...]\n", progname); 57 | fprintf(stream, 58 | "\n" 59 | "Options:\n" 60 | " -b create image in big endian format\n" 61 | " -i read input from the file \n" 62 | " -d set device name to \n" 63 | " -o write output to the file \n" 64 | " -O set offset to \n" 65 | " -s set image signature to \n" 66 | " -h show this screen\n" 67 | ); 68 | 69 | exit(status); 70 | } 71 | 72 | static void put_u32(void *data, uint32_t val) 73 | { 74 | unsigned char *p = data; 75 | 76 | if (big_endian) { 77 | p[0] = (val >> 24) & 0xff; 78 | p[1] = (val >> 16) & 0xff; 79 | p[2] = (val >> 8) & 0xff; 80 | p[3] = val & 0xff; 81 | } else { 82 | p[3] = (val >> 24) & 0xff; 83 | p[2] = (val >> 16) & 0xff; 84 | p[1] = (val >> 8) & 0xff; 85 | p[0] = val & 0xff; 86 | } 87 | } 88 | 89 | static void get_digest(struct wrg_header *header, char *data, int size) 90 | { 91 | MD5_CTX ctx; 92 | 93 | MD5_Init(&ctx); 94 | 95 | MD5_Update(&ctx, (char *)&header->offset, sizeof(header->offset)); 96 | MD5_Update(&ctx, (char *)&header->devname, sizeof(header->devname)); 97 | MD5_Update(&ctx, data, size); 98 | 99 | MD5_Final((unsigned char *)header->digest, &ctx); 100 | } 101 | 102 | int main(int argc, char *argv[]) 103 | { 104 | struct wrg_header *header; 105 | char *buf; 106 | struct stat st; 107 | int buflen; 108 | int err; 109 | int res = EXIT_FAILURE; 110 | 111 | FILE *outfile, *infile; 112 | 113 | progname = basename(argv[0]); 114 | 115 | while ( 1 ) { 116 | int c; 117 | 118 | c = getopt(argc, argv, "bd:i:o:s:O:h"); 119 | if (c == -1) 120 | break; 121 | 122 | switch (c) { 123 | case 'b': 124 | big_endian = 1; 125 | break; 126 | case 'd': 127 | dev_name = optarg; 128 | break; 129 | case 'i': 130 | ifname = optarg; 131 | break; 132 | case 'o': 133 | ofname = optarg; 134 | break; 135 | case 's': 136 | signature = optarg; 137 | break; 138 | case 'O': 139 | offset = strtoul(optarg, NULL, 0); 140 | break; 141 | case 'h': 142 | usage(EXIT_SUCCESS); 143 | break; 144 | 145 | default: 146 | usage(EXIT_FAILURE); 147 | break; 148 | } 149 | } 150 | 151 | if (signature == NULL) { 152 | ERR("no signature specified"); 153 | goto err; 154 | } 155 | 156 | if (ifname == NULL) { 157 | ERR("no input file specified"); 158 | goto err; 159 | } 160 | 161 | if (ofname == NULL) { 162 | ERR("no output file specified"); 163 | goto err; 164 | } 165 | 166 | if (dev_name == NULL) { 167 | ERR("no device name specified"); 168 | goto err; 169 | } 170 | 171 | err = stat(ifname, &st); 172 | if (err){ 173 | ERRS("stat failed on %s", ifname); 174 | goto err; 175 | } 176 | 177 | buflen = st.st_size + sizeof(struct wrg_header); 178 | buf = malloc(buflen); 179 | if (!buf) { 180 | ERR("no memory for buffer\n"); 181 | goto err; 182 | } 183 | 184 | infile = fopen(ifname, "r"); 185 | if (infile == NULL) { 186 | ERRS("could not open \"%s\" for reading", ifname); 187 | goto err_free; 188 | } 189 | 190 | errno = 0; 191 | fread(buf + sizeof(struct wrg_header), st.st_size, 1, infile); 192 | if (errno != 0) { 193 | ERRS("unable to read from file %s", ifname); 194 | goto close_in; 195 | } 196 | 197 | header = (struct wrg_header *) buf; 198 | memset(header, '\0', sizeof(struct wrg_header)); 199 | 200 | strncpy(header->signature, signature, sizeof(header->signature)); 201 | strncpy(header->devname, dev_name, sizeof(header->signature)); 202 | put_u32(&header->magic1, WRG_MAGIC); 203 | put_u32(&header->magic2, WRG_MAGIC); 204 | put_u32(&header->size, st.st_size); 205 | put_u32(&header->offset, offset); 206 | 207 | get_digest(header, buf + sizeof(struct wrg_header), st.st_size); 208 | 209 | outfile = fopen(ofname, "w"); 210 | if (outfile == NULL) { 211 | ERRS("could not open \"%s\" for writing", ofname); 212 | goto close_in; 213 | } 214 | 215 | errno = 0; 216 | fwrite(buf, buflen, 1, outfile); 217 | if (errno) { 218 | ERRS("unable to write to file %s", ofname); 219 | goto close_out; 220 | } 221 | 222 | fflush(outfile); 223 | 224 | res = EXIT_SUCCESS; 225 | 226 | close_out: 227 | fclose(outfile); 228 | if (res != EXIT_SUCCESS) 229 | unlink(ofname); 230 | close_in: 231 | fclose(infile); 232 | err_free: 233 | free(buf); 234 | err: 235 | return res; 236 | } 237 | -------------------------------------------------------------------------------- /src/myloader.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * Copyright (C) 2006-2008 Gabor Juhos 4 | */ 5 | 6 | #ifndef _MYLOADER_H_ 7 | #define _MYLOADER_H_ 8 | 9 | /* 10 | * Firmware file format: 11 | * 12 | *
13 | * [] 14 | * ... 15 | * [] 16 | * 17 | * [] 18 | * ... 19 | * [] 20 | * 21 | * 22 | */ 23 | 24 | /* Myloader specific magic numbers */ 25 | #define MYLO_MAGIC_FIRMWARE 0x4C594D00 26 | #define MYLO_MAGIC_20021103 0x20021103 27 | #define MYLO_MAGIC_20021107 0x20021107 28 | 29 | #define MYLO_MAGIC_SYS_PARAMS MYLO_MAGIC_20021107 30 | #define MYLO_MAGIC_PARTITIONS MYLO_MAGIC_20021103 31 | #define MYLO_MAGIC_BOARD_PARAMS MYLO_MAGIC_20021103 32 | 33 | /* 34 | * Addresses of the data structures provided by MyLoader 35 | */ 36 | #define MYLO_MIPS_SYS_PARAMS 0x80000800 /* System Parameters */ 37 | #define MYLO_MIPS_BOARD_PARAMS 0x80000A00 /* Board Parameters */ 38 | #define MYLO_MIPS_PARTITIONS 0x80000C00 /* Partition Table */ 39 | #define MYLO_MIPS_BOOT_PARAMS 0x80000E00 /* Boot Parameters */ 40 | 41 | /* Vendor ID's (seems to be same as the PCI vendor ID's) */ 42 | #define VENID_COMPEX 0x11F6 43 | 44 | /* Devices based on the ADM5120 */ 45 | #define DEVID_COMPEX_NP27G 0x0078 46 | #define DEVID_COMPEX_NP28G 0x044C 47 | #define DEVID_COMPEX_NP28GHS 0x044E 48 | #define DEVID_COMPEX_WP54Gv1C 0x0514 49 | #define DEVID_COMPEX_WP54G 0x0515 50 | #define DEVID_COMPEX_WP54AG 0x0546 51 | #define DEVID_COMPEX_WPP54AG 0x0550 52 | #define DEVID_COMPEX_WPP54G 0x0555 53 | 54 | /* Devices based on the Atheros AR2317 */ 55 | #define DEVID_COMPEX_NP25G 0x05e6 56 | #define DEVID_COMPEX_WPE53G 0x05dc 57 | 58 | /* Devices based on the Atheros AR71xx */ 59 | #define DEVID_COMPEX_WP543 0x0640 60 | #define DEVID_COMPEX_WPE72 0x0672 61 | 62 | /* Devices based on the IXP422 */ 63 | #define DEVID_COMPEX_WP18 0x047E 64 | #define DEVID_COMPEX_NP18A 0x0489 65 | 66 | /* Other devices */ 67 | #define DEVID_COMPEX_NP26G8M 0x03E8 68 | #define DEVID_COMPEX_NP26G16M 0x03E9 69 | 70 | struct mylo_fw_header { 71 | uint32_t magic; /* must be MYLO_MAGIC_FIRMWARE */ 72 | uint32_t crc; /* CRC of the whole firmware */ 73 | uint32_t res0; /* unknown/unused */ 74 | uint32_t res1; /* unknown/unused */ 75 | uint16_t vid; /* vendor ID */ 76 | uint16_t did; /* device ID */ 77 | uint16_t svid; /* sub vendor ID */ 78 | uint16_t sdid; /* sub device ID */ 79 | uint32_t rev; /* device revision */ 80 | uint32_t fwhi; /* FIXME: firmware version high? */ 81 | uint32_t fwlo; /* FIXME: firmware version low? */ 82 | uint32_t flags; /* firmware flags */ 83 | }; 84 | 85 | #define FW_FLAG_BOARD_PARAMS_WP 0x01 /* board parameters are write protected */ 86 | #define FW_FLAG_BOOT_SECTOR_WE 0x02 /* enable of write boot sectors (below 64K) */ 87 | 88 | struct mylo_fw_blockdesc { 89 | uint32_t type; /* block type */ 90 | uint32_t addr; /* relative address to flash start */ 91 | uint32_t dlen; /* size of block data in bytes */ 92 | uint32_t blen; /* total size of block in bytes */ 93 | }; 94 | 95 | #define FW_DESC_TYPE_UNUSED 0 96 | #define FW_DESC_TYPE_USED 1 97 | 98 | struct mylo_partition { 99 | uint16_t flags; /* partition flags */ 100 | uint16_t type; /* type of the partition */ 101 | uint32_t addr; /* relative address of the partition from the 102 | flash start */ 103 | uint32_t size; /* size of the partition in bytes */ 104 | uint32_t param; /* if this is the active partition, the 105 | MyLoader load code to this address */ 106 | }; 107 | 108 | #define PARTITION_FLAG_ACTIVE 0x8000 /* this is the active partition, 109 | * MyLoader loads firmware from here */ 110 | #define PARTITION_FLAG_ISRAM 0x2000 /* FIXME: this is a RAM partition? */ 111 | #define PARTIIION_FLAG_RAMLOAD 0x1000 /* FIXME: load this partition into the RAM? */ 112 | #define PARTITION_FLAG_PRELOAD 0x0800 /* the partition data preloaded to RAM 113 | * before decompression */ 114 | #define PARTITION_FLAG_LZMA 0x0100 /* the partition data compressed with LZMA */ 115 | #define PARTITION_FLAG_HAVEHDR 0x0002 /* the partition data have a header */ 116 | 117 | #define PARTITION_TYPE_FREE 0 118 | #define PARTITION_TYPE_USED 1 119 | 120 | #define MYLO_MAX_PARTITIONS 8 /* maximum number of partitions in the 121 | partition table */ 122 | 123 | struct mylo_partition_table { 124 | uint32_t magic; /* must be MYLO_MAGIC_PARTITIONS */ 125 | uint32_t res0; /* unknown/unused */ 126 | uint32_t res1; /* unknown/unused */ 127 | uint32_t res2; /* unknown/unused */ 128 | struct mylo_partition partitions[MYLO_MAX_PARTITIONS]; 129 | }; 130 | 131 | struct mylo_partition_header { 132 | uint32_t len; /* length of the partition data */ 133 | uint32_t crc; /* CRC value of the partition data */ 134 | }; 135 | 136 | struct mylo_system_params { 137 | uint32_t magic; /* must be MYLO_MAGIC_SYS_PARAMS */ 138 | uint32_t res0; 139 | uint32_t res1; 140 | uint32_t mylo_ver; 141 | uint16_t vid; /* Vendor ID */ 142 | uint16_t did; /* Device ID */ 143 | uint16_t svid; /* Sub Vendor ID */ 144 | uint16_t sdid; /* Sub Device ID */ 145 | uint32_t rev; /* device revision */ 146 | uint32_t fwhi; 147 | uint32_t fwlo; 148 | uint32_t tftp_addr; 149 | uint32_t prog_start; 150 | uint32_t flash_size; /* Size of boot FLASH in bytes */ 151 | uint32_t dram_size; /* Size of onboard RAM in bytes */ 152 | }; 153 | 154 | 155 | struct mylo_eth_addr { 156 | uint8_t mac[6]; 157 | uint8_t csum[2]; 158 | }; 159 | 160 | #define MYLO_ETHADDR_COUNT 8 /* maximum number of ethernet address 161 | in the board parameters */ 162 | 163 | struct mylo_board_params { 164 | uint32_t magic; /* must be MYLO_MAGIC_BOARD_PARAMS */ 165 | uint32_t res0; 166 | uint32_t res1; 167 | uint32_t res2; 168 | struct mylo_eth_addr addr[MYLO_ETHADDR_COUNT]; 169 | }; 170 | 171 | #endif /* _MYLOADER_H_*/ 172 | -------------------------------------------------------------------------------- /src/mkdapimg2.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * (C) Nicolò Veronese 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include // htonl 17 | 18 | // Usage: mkdapimg2 -s signature [-v version] [-r region] 19 | // [-k uImage block size] -i -o 20 | // 21 | // NOTE: The kernel block size is used to know the offset of the rootfs 22 | // in the image file. 23 | // 24 | // The system writes in the uImage partition until the end of uImage 25 | // is reached, after that, the system jumps to the offset specified with the -k 26 | // parameter and begin writing at the beginning of the rootfs MTD partition. 27 | // 28 | // If the -k parameter is the size of the original uImage partition, the system 29 | // continue writing in the rootfs partition starting from the last block 30 | // that has been wrote. (This is useful if the new kernel size is 31 | // different from the original one) 32 | // 33 | // Example: 34 | // ------------------------------------------ 35 | // Creating 7 MTD partitions on "ath-nor0": 36 | // 0x000000000000-0x000000010000 : "u-boot" 37 | // 0x000000010000-0x000000020000 : "ART" 38 | // 0x000000020000-0x000000030000 : "MP" 39 | // 0x000000030000-0x000000040000 : "config" 40 | // 0x000000040000-0x000000120000 : "uImage" 41 | // 0x000000120000-0x000000800000 : "rootfs" 42 | // 0x000000040000-0x000000800000 : "firmware" 43 | // ------------------------------------------ 44 | // 45 | // 0x000000120000-0x000000040000 = 0xE0000 -> 917504 46 | // 47 | // e.g.: mkdapimg2 -s HONEYBEE-FIRMWARE-DAP-1330 -v 1.00.21 -r Default 48 | // -k 917504 -i sysupgrade.bin -o factory.bin 49 | // 50 | // 51 | // The img_hdr_struct was taken from the D-Link SDK: 52 | // DAP-1330_OSS-firmware_1.00b21/DAP-1330_OSS-firmware_1.00b21/uboot/uboot.patch 53 | 54 | #define MAX_SIGN_LEN 32 55 | #define MAX_FW_VER_LEN 16 56 | #define MAX_REG_LEN 8 57 | 58 | struct img_hdr_struct { 59 | uint32_t hdr_len; 60 | uint32_t checksum; 61 | uint32_t total_size; 62 | uint32_t kernel_size; 63 | char signature[MAX_SIGN_LEN]; 64 | char fw_ver[MAX_FW_VER_LEN]; 65 | char fw_reg[MAX_REG_LEN]; 66 | } imghdr ; 67 | 68 | char *progname; 69 | 70 | void 71 | perrexit(int code, char *msg) 72 | { 73 | fprintf(stderr, "%s: %s: %s\n", progname, msg, strerror(errno)); 74 | exit(code); 75 | } 76 | 77 | void 78 | usage() 79 | { 80 | fprintf(stderr, "usage: %s -s signature [-v version] [-r region] [-k uImage part size] -i -o \n", progname); 81 | exit(1); 82 | } 83 | 84 | int 85 | main(int ac, char *av[]) 86 | { 87 | char signature[MAX_SIGN_LEN]; 88 | char version[MAX_FW_VER_LEN]; 89 | char region[MAX_REG_LEN]; 90 | int kernel = 0; 91 | 92 | FILE *ifile = NULL; 93 | FILE *ofile = NULL; 94 | int c; 95 | 96 | uint32_t cksum; 97 | uint32_t bcnt; 98 | 99 | progname = basename(av[0]); 100 | 101 | memset(signature, 0, sizeof(signature)); 102 | memset(version, 0, sizeof(version)); 103 | memset(region, 0, sizeof(region)); 104 | 105 | while ( 1 ) { 106 | char *ptr; 107 | int c; 108 | 109 | c = getopt(ac, av, "s:v:r:k:i:o:"); 110 | if (c == -1) 111 | break; 112 | 113 | switch (c) { 114 | case 's': 115 | if (strlen(optarg) > MAX_SIGN_LEN + 1) { 116 | fprintf(stderr, "%s: signature exceeds %d chars\n", 117 | progname, MAX_SIGN_LEN); 118 | exit(1); 119 | } 120 | strcpy(signature, optarg); 121 | break; 122 | case 'v': 123 | if (strlen(optarg) > MAX_FW_VER_LEN + 1) { 124 | fprintf(stderr, "%s: version exceeds %d chars\n", 125 | progname, MAX_FW_VER_LEN); 126 | exit(1); 127 | } 128 | strcpy(version, optarg); 129 | break; 130 | case 'r': 131 | if (strlen(optarg) > MAX_REG_LEN + 1) { 132 | fprintf(stderr, "%s: region exceeds %d chars\n", 133 | progname, MAX_REG_LEN); 134 | exit(1); 135 | } 136 | strcpy(region, optarg); 137 | break; 138 | case 'k': 139 | kernel = strtoul(optarg, &ptr, 0); 140 | if(ptr[0] == 'k'){ 141 | kernel *= 1000; 142 | } 143 | break; 144 | case 'i': 145 | if ((ifile = fopen(optarg, "r")) == NULL) 146 | perrexit(1, optarg); 147 | break; 148 | case 'o': 149 | if ((ofile = fopen(optarg, "w")) == NULL) 150 | perrexit(1, optarg); 151 | break; 152 | default: 153 | usage(); 154 | } 155 | } 156 | 157 | if (signature[0] == 0 || ifile == NULL || ofile == NULL) { 158 | usage(); 159 | exit(1); 160 | } 161 | 162 | for (bcnt = 0, cksum = 0 ; (c = fgetc(ifile)) != EOF ; bcnt++) 163 | cksum += c & 0xff; 164 | 165 | if (fseek(ifile, 0, SEEK_SET) < 0) 166 | perrexit(2, "fseek on input"); 167 | 168 | // Fill in the header 169 | memset(&imghdr, 0, sizeof(imghdr)); 170 | imghdr.hdr_len = sizeof(imghdr); 171 | imghdr.checksum = htonl(cksum); 172 | imghdr.total_size = htonl(bcnt); 173 | imghdr.kernel_size = htonl(kernel); 174 | 175 | strncpy(imghdr.signature, signature, MAX_SIGN_LEN); 176 | strncpy(imghdr.fw_ver, version, MAX_FW_VER_LEN); 177 | strncpy(imghdr.fw_reg, region, MAX_REG_LEN); 178 | 179 | if (fwrite(&imghdr, sizeof(imghdr), 1, ofile) < 0) 180 | perrexit(2, "fwrite header on output"); 181 | 182 | while ((c = fgetc(ifile)) != EOF) { 183 | if (fputc(c, ofile) == EOF) 184 | perrexit(2, "fputc on output"); 185 | } 186 | 187 | if (ferror(ifile)) 188 | perrexit(2, "fgetc on input"); 189 | 190 | fclose(ofile); 191 | fclose(ifile); 192 | 193 | fprintf(stderr, "imgHdr.hdr_len = %lu\n", sizeof(imghdr)); 194 | fprintf(stderr, "imgHdr.checksum = 0x%08x\n", cksum); 195 | fprintf(stderr, "imgHdr.total_size = 0x%08x\n", bcnt); 196 | fprintf(stderr, "imgHdr.kernel_size = 0x%08x\n", kernel); 197 | fprintf(stderr, "imgHdr.header = %s\n", signature); 198 | fprintf(stderr, "imgHdr.fw_ver = %s\n", version); 199 | fprintf(stderr, "imgHdr.fw_reg = %s\n", region); 200 | 201 | return 0; 202 | } 203 | -------------------------------------------------------------------------------- /src/mkplanexfw.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright (C) 2009 Gabor Juhos 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include /* for unlink() */ 12 | #include 13 | #include /* for getopt() */ 14 | #include 15 | #include 16 | #include 17 | 18 | #include "sha1.h" 19 | 20 | #if (__BYTE_ORDER == __BIG_ENDIAN) 21 | # define HOST_TO_BE32(x) (x) 22 | # define BE32_TO_HOST(x) (x) 23 | #else 24 | # define HOST_TO_BE32(x) bswap_32(x) 25 | # define BE32_TO_HOST(x) bswap_32(x) 26 | #endif 27 | 28 | 29 | struct planex_hdr { 30 | uint8_t sha1sum[20]; 31 | char version[8]; 32 | uint8_t unk1[2]; 33 | uint32_t datalen; 34 | } __attribute__ ((packed)); 35 | 36 | struct board_info { 37 | char *id; 38 | uint32_t seed; 39 | uint8_t unk[2]; 40 | uint32_t datalen; 41 | }; 42 | 43 | /* 44 | * Globals 45 | */ 46 | static char *ifname; 47 | static char *progname; 48 | static char *ofname; 49 | static char *version = "1.00.00"; 50 | 51 | static char *board_id; 52 | static struct board_info *board; 53 | 54 | static struct board_info boards[] = { 55 | { 56 | .id = "MZK-W04NU", 57 | .seed = 2, 58 | .unk = {0x04, 0x08}, 59 | .datalen = 0x770000, 60 | }, { 61 | .id = "MZK-W300NH", 62 | .seed = 4, 63 | .unk = {0x00, 0x00}, 64 | .datalen = 0x770000, 65 | }, { 66 | /* terminating entry */ 67 | } 68 | }; 69 | 70 | /* 71 | * Message macros 72 | */ 73 | #define ERR(fmt, ...) do { \ 74 | fflush(0); \ 75 | fprintf(stderr, "[%s] *** error: " fmt "\n", \ 76 | progname, ## __VA_ARGS__ ); \ 77 | } while (0) 78 | 79 | #define ERRS(fmt, ...) do { \ 80 | int save = errno; \ 81 | fflush(0); \ 82 | fprintf(stderr, "[%s] *** error: " fmt ": %s\n", \ 83 | progname, ## __VA_ARGS__, strerror(save)); \ 84 | } while (0) 85 | 86 | static struct board_info *find_board(char *id) 87 | { 88 | struct board_info *ret; 89 | struct board_info *board; 90 | 91 | ret = NULL; 92 | for (board = boards; board->id != NULL; board++){ 93 | if (strcasecmp(id, board->id) == 0) { 94 | ret = board; 95 | break; 96 | } 97 | }; 98 | 99 | return ret; 100 | } 101 | 102 | void usage(int status) 103 | { 104 | FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; 105 | 106 | fprintf(stream, "Usage: %s [OPTIONS...]\n", progname); 107 | fprintf(stream, 108 | "\n" 109 | "Options:\n" 110 | " -B create image for the board specified with \n" 111 | " -i read input from the file \n" 112 | " -o write output to the file \n" 113 | " -v set image version to \n" 114 | " -h show this screen\n" 115 | ); 116 | 117 | exit(status); 118 | } 119 | 120 | int main(int argc, char *argv[]) 121 | { 122 | int res = EXIT_FAILURE; 123 | int buflen; 124 | int err; 125 | struct stat st; 126 | char *buf; 127 | struct planex_hdr *hdr; 128 | sha1_context ctx; 129 | uint32_t seed; 130 | 131 | FILE *outfile, *infile; 132 | 133 | progname = basename(argv[0]); 134 | 135 | while ( 1 ) { 136 | int c; 137 | 138 | c = getopt(argc, argv, "B:i:o:v:h"); 139 | if (c == -1) 140 | break; 141 | 142 | switch (c) { 143 | case 'B': 144 | board_id = optarg; 145 | break; 146 | case 'i': 147 | ifname = optarg; 148 | break; 149 | case 'o': 150 | ofname = optarg; 151 | break; 152 | case 'v': 153 | version = optarg; 154 | break; 155 | case 'h': 156 | usage(EXIT_SUCCESS); 157 | break; 158 | default: 159 | usage(EXIT_FAILURE); 160 | break; 161 | } 162 | } 163 | 164 | if (board_id == NULL) { 165 | ERR("no board specified"); 166 | goto err; 167 | } 168 | 169 | board = find_board(board_id); 170 | if (board == NULL) { 171 | ERR("unknown board '%s'", board_id); 172 | goto err; 173 | }; 174 | 175 | if (ifname == NULL) { 176 | ERR("no input file specified"); 177 | goto err; 178 | } 179 | 180 | if (ofname == NULL) { 181 | ERR("no output file specified"); 182 | goto err; 183 | } 184 | 185 | err = stat(ifname, &st); 186 | if (err){ 187 | ERRS("stat failed on %s", ifname); 188 | goto err; 189 | } 190 | 191 | if (st.st_size > board->datalen) { 192 | ERR("file '%s' is too big - max size: 0x%08X (exceeds %lu bytes)\n", 193 | ifname, board->datalen, st.st_size - board->datalen); 194 | goto err; 195 | } 196 | 197 | buflen = board->datalen + 0x10000; 198 | buf = malloc(buflen); 199 | if (!buf) { 200 | ERR("no memory for buffer\n"); 201 | goto err; 202 | } 203 | 204 | memset(buf, 0xff, buflen); 205 | hdr = (struct planex_hdr *)buf; 206 | 207 | hdr->datalen = HOST_TO_BE32(board->datalen); 208 | hdr->unk1[0] = board->unk[0]; 209 | hdr->unk1[1] = board->unk[1]; 210 | 211 | snprintf(hdr->version, sizeof(hdr->version), "%s", version); 212 | 213 | infile = fopen(ifname, "r"); 214 | if (infile == NULL) { 215 | ERRS("could not open \"%s\" for reading", ifname); 216 | goto err_free; 217 | } 218 | 219 | errno = 0; 220 | fread(buf + sizeof(*hdr), st.st_size, 1, infile); 221 | if (errno != 0) { 222 | ERRS("unable to read from file %s", ifname); 223 | goto err_close_in; 224 | } 225 | 226 | seed = HOST_TO_BE32(board->seed); 227 | sha1_starts(&ctx); 228 | sha1_update(&ctx, (uchar *) &seed, sizeof(seed)); 229 | sha1_update(&ctx, buf + sizeof(*hdr), board->datalen); 230 | sha1_finish(&ctx, hdr->sha1sum); 231 | 232 | outfile = fopen(ofname, "w"); 233 | if (outfile == NULL) { 234 | ERRS("could not open \"%s\" for writing", ofname); 235 | goto err_close_in; 236 | } 237 | 238 | errno = 0; 239 | fwrite(buf, buflen, 1, outfile); 240 | if (errno) { 241 | ERRS("unable to write to file %s", ofname); 242 | goto err_close_out; 243 | } 244 | 245 | res = EXIT_SUCCESS; 246 | 247 | fflush(outfile); 248 | 249 | err_close_out: 250 | fclose(outfile); 251 | if (res != EXIT_SUCCESS) { 252 | unlink(ofname); 253 | } 254 | 255 | err_close_in: 256 | fclose(infile); 257 | 258 | err_free: 259 | free(buf); 260 | 261 | err: 262 | return res; 263 | } 264 | 265 | -------------------------------------------------------------------------------- /src/mktplinkfw-lib.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright (C) 2009 Gabor Juhos 4 | * 5 | * This tool was based on: 6 | * TP-Link WR941 V2 firmware checksum fixing tool. 7 | * Copyright (C) 2008,2009 Wang Jian 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include /* for unlink() */ 15 | #include 16 | #include /* for getopt() */ 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | #include "mktplinkfw-lib.h" 27 | #include "md5.h" 28 | 29 | extern char *ofname; 30 | extern char *progname; 31 | extern uint32_t kernel_len; 32 | extern struct file_info kernel_info; 33 | extern struct file_info rootfs_info; 34 | extern struct flash_layout *layout; 35 | extern uint32_t rootfs_ofs; 36 | extern uint32_t rootfs_align; 37 | extern int combined; 38 | extern int strip_padding; 39 | extern int add_jffs2_eof; 40 | 41 | static unsigned char jffs2_eof_mark[4] = {0xde, 0xad, 0xc0, 0xde}; 42 | 43 | void fill_header(char *buf, int len); 44 | 45 | struct flash_layout *find_layout(struct flash_layout *layouts, const char *id) 46 | { 47 | struct flash_layout *ret; 48 | struct flash_layout *l; 49 | 50 | ret = NULL; 51 | for (l = layouts; l->id != NULL; l++){ 52 | if (strcasecmp(id, l->id) == 0) { 53 | ret = l; 54 | break; 55 | } 56 | }; 57 | 58 | return ret; 59 | } 60 | 61 | void get_md5(const char *data, int size, uint8_t *md5) 62 | { 63 | MD5_CTX ctx; 64 | 65 | MD5_Init(&ctx); 66 | MD5_Update(&ctx, data, size); 67 | MD5_Final(md5, &ctx); 68 | } 69 | 70 | int get_file_stat(struct file_info *fdata) 71 | { 72 | struct stat st; 73 | int res; 74 | 75 | if (fdata->file_name == NULL) 76 | return 0; 77 | 78 | res = stat(fdata->file_name, &st); 79 | if (res){ 80 | ERRS("stat failed on %s", fdata->file_name); 81 | return res; 82 | } 83 | 84 | fdata->file_size = st.st_size; 85 | return 0; 86 | } 87 | 88 | int read_to_buf(const struct file_info *fdata, char *buf) 89 | { 90 | FILE *f; 91 | int ret = EXIT_FAILURE; 92 | 93 | f = fopen(fdata->file_name, "r"); 94 | if (f == NULL) { 95 | ERRS("could not open \"%s\" for reading", fdata->file_name); 96 | goto out; 97 | } 98 | 99 | errno = 0; 100 | fread(buf, fdata->file_size, 1, f); 101 | if (errno != 0) { 102 | ERRS("unable to read from file \"%s\"", fdata->file_name); 103 | goto out_close; 104 | } 105 | 106 | ret = EXIT_SUCCESS; 107 | 108 | out_close: 109 | fclose(f); 110 | out: 111 | return ret; 112 | } 113 | 114 | static int pad_jffs2(char *buf, int currlen, int maxlen) 115 | { 116 | int len; 117 | uint32_t pad_mask; 118 | 119 | len = currlen; 120 | pad_mask = (4 * 1024) | (64 * 1024); /* EOF at 4KB and at 64KB */ 121 | while ((len < maxlen) && (pad_mask != 0)) { 122 | uint32_t mask; 123 | int i; 124 | 125 | for (i = 10; i < 32; i++) { 126 | mask = 1 << i; 127 | if (pad_mask & mask) 128 | break; 129 | } 130 | 131 | len = ALIGN(len, mask); 132 | 133 | for (i = 10; i < 32; i++) { 134 | mask = 1 << i; 135 | if ((len & (mask - 1)) == 0) 136 | pad_mask &= ~mask; 137 | } 138 | 139 | for (i = 0; i < sizeof(jffs2_eof_mark); i++) 140 | buf[len + i] = jffs2_eof_mark[i]; 141 | 142 | len += sizeof(jffs2_eof_mark); 143 | } 144 | 145 | return len; 146 | } 147 | 148 | int write_fw(const char *ofname, const char *data, int len) 149 | { 150 | FILE *f; 151 | int ret = EXIT_FAILURE; 152 | 153 | f = fopen(ofname, "w"); 154 | if (f == NULL) { 155 | ERRS("could not open \"%s\" for writing", ofname); 156 | goto out; 157 | } 158 | 159 | errno = 0; 160 | fwrite(data, len, 1, f); 161 | if (errno) { 162 | ERRS("unable to write output file"); 163 | goto out_flush; 164 | } 165 | 166 | DBG("firmware file \"%s\" completed", ofname); 167 | 168 | ret = EXIT_SUCCESS; 169 | 170 | out_flush: 171 | fflush(f); 172 | fclose(f); 173 | if (ret != EXIT_SUCCESS) { 174 | unlink(ofname); 175 | } 176 | out: 177 | return ret; 178 | } 179 | 180 | /* Helper functions to inspect_fw() representing different output formats */ 181 | inline void inspect_fw_pstr(const char *label, const char *str) 182 | { 183 | printf("%-23s: %s\n", label, str); 184 | } 185 | 186 | inline void inspect_fw_phex(const char *label, uint32_t val) 187 | { 188 | printf("%-23s: 0x%08x\n", label, val); 189 | } 190 | 191 | inline void inspect_fw_phexdec(const char *label, uint32_t val) 192 | { 193 | printf("%-23s: 0x%08x / %8u bytes\n", label, val, val); 194 | } 195 | 196 | inline void inspect_fw_pmd5sum(const char *label, const uint8_t *val, const char *text) 197 | { 198 | int i; 199 | 200 | printf("%-23s:", label); 201 | for (i=0; ifw_max_len; 221 | 222 | buf = malloc(buflen); 223 | if (!buf) { 224 | ERR("no memory for buffer\n"); 225 | goto out; 226 | } 227 | 228 | memset(buf, 0xff, buflen); 229 | p = buf + header_size; 230 | ret = read_to_buf(&kernel_info, p); 231 | if (ret) 232 | goto out_free_buf; 233 | 234 | if (!combined) { 235 | p = buf + rootfs_ofs; 236 | 237 | ret = read_to_buf(&rootfs_info, p); 238 | if (ret) 239 | goto out_free_buf; 240 | 241 | writelen = rootfs_ofs + rootfs_info.file_size; 242 | 243 | if (add_jffs2_eof) 244 | writelen = pad_jffs2(buf, writelen, layout->fw_max_len); 245 | } 246 | 247 | if (!strip_padding) 248 | writelen = buflen; 249 | 250 | fill_header(buf, writelen); 251 | ret = write_fw(ofname, buf, writelen); 252 | if (ret) 253 | goto out_free_buf; 254 | 255 | ret = EXIT_SUCCESS; 256 | 257 | out_free_buf: 258 | free(buf); 259 | out: 260 | return ret; 261 | } 262 | -------------------------------------------------------------------------------- /src/motorola-bin.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-or-later 2 | /* 3 | * motorola-bin.c 4 | * 5 | * Copyright (C) 2005-2006 Mike Baker, 6 | * Imre Kaloz 7 | * D. Hugh Redelmeier 8 | * OpenWrt.org 9 | */ 10 | 11 | /* 12 | * Motorola's firmware flashing code requires an extra header. 13 | * The header is eight bytes (see struct motorola below). 14 | * This program will take a firmware file and create a new one 15 | * with this header: 16 | * motorola-bin --wr850g WR850G_V403.stripped.trx WR850G_V403.trx 17 | * 18 | * Note: Motorola's firmware is distributed with this header. 19 | * If you need to flash Motorola firmware on a router running OpenWRT, 20 | * you will to remove this header. Use the --strip flag: 21 | * motorola-bin --strip WR850G_V403.trx WR850G_V403.stripped.trx 22 | */ 23 | 24 | /* 25 | * February 1, 2006 26 | * 27 | * Add support for for creating WA840G and WE800G images 28 | */ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #define BPB 8 /* bits/byte */ 42 | 43 | static uint32_t crc32[1<> 1)) : (crc >> 1); 56 | crc32[n] = crc; 57 | } 58 | } 59 | 60 | static uint32_t crc32buf(unsigned char *buf, size_t len) 61 | { 62 | uint32_t crc = 0xFFFFFFFF; 63 | 64 | for (; len; len--, buf++) 65 | crc = crc32[(uint8_t)crc ^ *buf] ^ (crc >> BPB); 66 | return crc; 67 | } 68 | 69 | struct motorola { 70 | uint32_t crc; // crc32 of the remainder 71 | uint32_t flags; // unknown, 105770* 72 | }; 73 | 74 | static const struct model { 75 | char digit; /* a digit signifying model (historical) */ 76 | const char *name; 77 | uint32_t flags; 78 | } models[] = { 79 | { '1', "WR850G", 0x10577050LU }, 80 | { '2', "WA840G", 0x10577040LU }, 81 | { '3', "WE800G", 0x10577000LU }, 82 | { '\0', NULL, 0 } 83 | }; 84 | 85 | static void usage(const char *) __attribute__ (( __noreturn__ )); 86 | 87 | static void usage(const char *mess) 88 | { 89 | const struct model *m; 90 | 91 | fprintf(stderr, "Error: %s\n", mess); 92 | fprintf(stderr, "Usage: motorola-bin -device|--strip infile outfile\n"); 93 | fprintf(stderr, "Known devices: "); 94 | 95 | for (m = models; m->digit != '\0'; m++) 96 | fprintf(stderr, " %c - %s", m->digit, m->name); 97 | 98 | fprintf(stderr, "\n"); 99 | exit(1); 100 | } 101 | 102 | int main(int argc, char **argv) 103 | { 104 | off_t len; // of original firmware 105 | int fd; 106 | void *trx; // pointer to original firmware (mmmapped) 107 | struct motorola *firmware; // pionter to prefix + copy of original firmware 108 | uint32_t flags; 109 | 110 | // verify parameters 111 | 112 | if (argc != 4) 113 | usage("wrong number of arguments"); 114 | 115 | // mmap trx file 116 | if ((fd = open(argv[2], O_RDONLY)) < 0 117 | || (len = lseek(fd, 0, SEEK_END)) < 0 118 | || (trx = mmap(0, len, PROT_READ, MAP_SHARED, fd, 0)) == (void *) (-1) 119 | || close(fd) < 0) 120 | { 121 | fprintf(stderr, "Error loading file %s: %s\n", argv[2], strerror(errno)); 122 | exit(1); 123 | } 124 | 125 | init_crc32(); 126 | 127 | if (strcmp(argv[1], "--strip") == 0) 128 | { 129 | const char *ugh = NULL; 130 | 131 | if (len < sizeof(struct motorola)) { 132 | ugh = "input file too short"; 133 | } else { 134 | const struct model *m; 135 | 136 | firmware = trx; 137 | if (htonl(crc32buf(trx + offsetof(struct motorola, flags), len - offsetof(struct motorola, flags))) != firmware->crc) 138 | ugh = "Invalid CRC"; 139 | for (m = models; ; m++) { 140 | if (m->digit == '\0') { 141 | if (ugh == NULL) 142 | ugh = "unrecognized flags field"; 143 | break; 144 | } 145 | if (firmware->flags == htonl(m->flags)) { 146 | fprintf(stderr, "Firmware for Motorola %s\n", m->name); 147 | break; 148 | } 149 | } 150 | } 151 | 152 | if (ugh != NULL) { 153 | fprintf(stderr, "%s\n", ugh); 154 | exit(3); 155 | } else { 156 | // all is well, write the file without the prefix 157 | if ((fd = open(argv[3], O_CREAT|O_WRONLY|O_TRUNC,0644)) < 0 158 | || write(fd, trx + sizeof(struct motorola), len - sizeof(struct motorola)) != len - sizeof(struct motorola) 159 | || close(fd) < 0) 160 | { 161 | fprintf(stderr, "Error storing file %s: %s\n", argv[3], strerror(errno)); 162 | exit(2); 163 | } 164 | } 165 | 166 | } else { 167 | // setup the firmware flags magic number 168 | const struct model *m; 169 | const char *df = argv[1]; 170 | 171 | if (*df != '-') 172 | usage("first argument must start with -"); 173 | if (*++df == '-') 174 | ++df; /* allow but don't require second - */ 175 | 176 | for (m = models; ; m++) { 177 | if (m->digit == '\0') 178 | usage("unrecognized device specified"); 179 | if ((df[0] == m->digit && df[1] == '\0') || strcasecmp(df, m->name) == 0) { 180 | flags = m->flags; 181 | break; 182 | } 183 | } 184 | 185 | 186 | // create a firmware image in memory 187 | // and copy the trx to it 188 | firmware = malloc(sizeof(struct motorola) + len); 189 | memcpy(&firmware[1], trx, len); 190 | 191 | // setup the motorola headers 192 | firmware->flags = htonl(flags); 193 | 194 | // CRC of flags + firmware 195 | firmware->crc = htonl(crc32buf((unsigned char *)&firmware->flags, sizeof(firmware->flags) + len)); 196 | 197 | // write the firmware 198 | if ((fd = open(argv[3], O_CREAT|O_WRONLY|O_TRUNC,0644)) < 0 199 | || write(fd, firmware, sizeof(struct motorola) + len) != sizeof(struct motorola) + len 200 | || close(fd) < 0) 201 | { 202 | fprintf(stderr, "Error storing file %s: %s\n", argv[3], strerror(errno)); 203 | exit(2); 204 | } 205 | 206 | free(firmware); 207 | } 208 | 209 | munmap(trx,len); 210 | 211 | return 0; 212 | } 213 | -------------------------------------------------------------------------------- /src/nand_ecc.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only 2 | /* 3 | * calculate ecc code for nand flash 4 | * 5 | * Copyright (C) 2008 yajin 6 | * Copyright (C) 2009 Felix Fietkau 7 | */ 8 | 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #define DEF_NAND_PAGE_SIZE 2048 19 | #define DEF_NAND_OOB_SIZE 64 20 | #define DEF_NAND_ECC_OFFSET 0x28 21 | 22 | static int page_size = DEF_NAND_PAGE_SIZE; 23 | static int oob_size = DEF_NAND_OOB_SIZE; 24 | static int ecc_offset = DEF_NAND_ECC_OFFSET; 25 | 26 | /* 27 | * Pre-calculated 256-way 1 byte column parity 28 | */ 29 | static const uint8_t nand_ecc_precalc_table[] = { 30 | 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, 31 | 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, 32 | 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, 33 | 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, 34 | 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, 35 | 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, 36 | 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, 37 | 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, 38 | 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, 39 | 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, 40 | 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, 41 | 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, 42 | 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, 43 | 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, 44 | 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, 45 | 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 46 | }; 47 | 48 | /** 49 | * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256-byte block 50 | * @dat: raw data 51 | * @ecc_code: buffer for ECC 52 | */ 53 | int nand_calculate_ecc(const uint8_t *dat, 54 | uint8_t *ecc_code) 55 | { 56 | uint8_t idx, reg1, reg2, reg3, tmp1, tmp2; 57 | int i; 58 | 59 | /* Initialize variables */ 60 | reg1 = reg2 = reg3 = 0; 61 | 62 | /* Build up column parity */ 63 | for(i = 0; i < 256; i++) { 64 | /* Get CP0 - CP5 from table */ 65 | idx = nand_ecc_precalc_table[*dat++]; 66 | reg1 ^= (idx & 0x3f); 67 | 68 | /* All bit XOR = 1 ? */ 69 | if (idx & 0x40) { 70 | reg3 ^= (uint8_t) i; 71 | reg2 ^= ~((uint8_t) i); 72 | } 73 | } 74 | 75 | /* Create non-inverted ECC code from line parity */ 76 | tmp1 = (reg3 & 0x80) >> 0; /* B7 -> B7 */ 77 | tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */ 78 | tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */ 79 | tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */ 80 | tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */ 81 | tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */ 82 | tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */ 83 | tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */ 84 | 85 | tmp2 = (reg3 & 0x08) << 4; /* B3 -> B7 */ 86 | tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */ 87 | tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */ 88 | tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */ 89 | tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */ 90 | tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */ 91 | tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */ 92 | tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */ 93 | 94 | /* Calculate final ECC code */ 95 | #ifdef CONFIG_MTD_NAND_ECC_SMC 96 | ecc_code[0] = ~tmp2; 97 | ecc_code[1] = ~tmp1; 98 | #else 99 | ecc_code[0] = ~tmp1; 100 | ecc_code[1] = ~tmp2; 101 | #endif 102 | ecc_code[2] = ((~reg1) << 2) | 0x03; 103 | 104 | return 0; 105 | } 106 | 107 | /* 108 | * usage: bb-nandflash-ecc start_address size 109 | */ 110 | void usage(const char *prog) 111 | { 112 | fprintf(stderr, "Usage: %s [options] \n" 113 | "Options:\n" 114 | " -p NAND page size (default: %d)\n" 115 | " -o NAND OOB size (default: %d)\n" 116 | " -e NAND ECC offset (default: %d)\n" 117 | "\n", prog, DEF_NAND_PAGE_SIZE, DEF_NAND_OOB_SIZE, 118 | DEF_NAND_ECC_OFFSET); 119 | exit(1); 120 | } 121 | 122 | /*start_address/size does not include oob 123 | */ 124 | int main(int argc, char **argv) 125 | { 126 | uint8_t *page_data = NULL; 127 | uint8_t *ecc_data; 128 | int infd = -1, outfd = -1; 129 | int ret = 1; 130 | ssize_t bytes; 131 | int ch; 132 | 133 | while ((ch = getopt(argc, argv, "e:o:p:")) != -1) { 134 | switch(ch) { 135 | case 'p': 136 | page_size = strtoul(optarg, NULL, 0); 137 | break; 138 | case 'o': 139 | oob_size = strtoul(optarg, NULL, 0); 140 | break; 141 | case 'e': 142 | ecc_offset = strtoul(optarg, NULL, 0); 143 | break; 144 | default: 145 | usage(argv[0]); 146 | } 147 | } 148 | argc -= optind; 149 | if (argc < 2) 150 | usage(argv[0]); 151 | 152 | argv += optind; 153 | 154 | infd = open(argv[0], O_RDONLY, 0); 155 | if (infd < 0) { 156 | perror("open input file"); 157 | goto out; 158 | } 159 | 160 | outfd = open(argv[1], O_WRONLY|O_CREAT|O_TRUNC, 0644); 161 | if (outfd < 0) { 162 | perror("open output file"); 163 | goto out; 164 | } 165 | 166 | page_data = malloc(page_size + oob_size); 167 | 168 | while ((bytes = read(infd, page_data, page_size)) == page_size) { 169 | int j; 170 | 171 | ecc_data = page_data + page_size + ecc_offset; 172 | for (j = 0; j < page_size / 256; j++) 173 | { 174 | nand_calculate_ecc(page_data + j * 256, ecc_data); 175 | ecc_data += 3; 176 | } 177 | write(outfd, page_data, page_size + oob_size); 178 | } 179 | 180 | ret = 0; 181 | out: 182 | if (infd >= 0) 183 | close(infd); 184 | if (outfd >= 0) 185 | close(outfd); 186 | if (page_data) 187 | free(page_data); 188 | return ret; 189 | } 190 | 191 | -------------------------------------------------------------------------------- /src/mkdapimg.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include // htonl 13 | 14 | // Usage: mkdapimg [-p] [-m ] -s -i -o 15 | // 16 | // e.g.: mkdapimg -s RT3052-AP-DAP1350-3 -i sysupgrade.bin -o factory.bin 17 | // 18 | // If the model string is not given, we will assume that 19 | // the leading characters upto the first "-" is the model. 20 | // 21 | // The "-p" (patch) option is used to patch the exisiting image with the 22 | // specified model and signature. 23 | // The "-x" (fix) option will recalculate the payload size and checksum 24 | // during the patch mode operation. 25 | 26 | // The img_hdr_struct was taken from the D-Link SDK: 27 | // DAP-1350_A1_FW1.11NA_GPL/GPL_Source_Code/Uboot/DAP-1350/httpd/header.h 28 | 29 | #define MAX_MODEL_NAME_LEN 20 30 | #define MAX_SIG_LEN 30 31 | #define MAX_REGION_LEN 4 32 | #define MAX_VERSION_LEN 12 33 | 34 | struct img_hdr_struct { 35 | uint32_t checksum; 36 | char model[MAX_MODEL_NAME_LEN]; 37 | char sig[MAX_SIG_LEN]; 38 | uint8_t partition; 39 | uint8_t hdr_len; 40 | uint8_t rsv1; 41 | uint8_t rsv2; 42 | uint32_t flash_byte_cnt; 43 | } imghdr ; 44 | 45 | char *progname; 46 | 47 | void 48 | perrexit(int code, char *msg) 49 | { 50 | fprintf(stderr, "%s: %s: %s\n", progname, msg, strerror(errno)); 51 | exit(code); 52 | } 53 | 54 | void 55 | usage() 56 | { 57 | fprintf(stderr, "usage: %s [-p] [-m model] [-r region] [-v version] -s signature -i input -o output\n", progname); 58 | exit(1); 59 | } 60 | 61 | int 62 | main(int ac, char *av[]) 63 | { 64 | char model[MAX_MODEL_NAME_LEN+1]; 65 | char signature[MAX_SIG_LEN+1]; 66 | char region[MAX_REGION_LEN+1]; 67 | char version[MAX_VERSION_LEN+1]; 68 | int patchmode = 0; 69 | int fixmode = 0; 70 | int have_regionversion = 0; 71 | 72 | FILE *ifile = NULL; 73 | FILE *ofile = NULL; 74 | int c; 75 | uint32_t cksum; 76 | uint32_t bcnt; 77 | 78 | progname = basename(av[0]); 79 | memset(model, 0, sizeof(model)); 80 | memset(signature, 0, sizeof(signature)); 81 | memset(region, 0, sizeof(region)); 82 | memset(version, 0, sizeof(version)); 83 | 84 | while ( 1 ) { 85 | int c; 86 | 87 | c = getopt(ac, av, "pxm:r:v:s:i:o:"); 88 | if (c == -1) 89 | break; 90 | 91 | switch (c) { 92 | case 'p': 93 | patchmode = 1; 94 | break; 95 | case 'x': 96 | fixmode = 1; 97 | break; 98 | case 'm': 99 | if (strlen(optarg) > MAX_MODEL_NAME_LEN) { 100 | fprintf(stderr, "%s: model name exceeds %d chars\n", 101 | progname, MAX_MODEL_NAME_LEN); 102 | exit(1); 103 | } 104 | strcpy(model, optarg); 105 | break; 106 | case 'r': 107 | if (strlen(optarg) > MAX_REGION_LEN) { 108 | fprintf(stderr, "%s: region exceeds %d chars\n", 109 | progname, MAX_REGION_LEN); 110 | exit(1); 111 | } 112 | have_regionversion = 1; 113 | strcpy(region, optarg); 114 | break; 115 | case 'v': 116 | if (strlen(optarg) > MAX_VERSION_LEN) { 117 | fprintf(stderr, "%s: version exceeds %d chars\n", 118 | progname, MAX_VERSION_LEN); 119 | exit(1); 120 | } 121 | have_regionversion = 1; 122 | strcpy(version, optarg); 123 | break; 124 | case 's': 125 | if (strlen(optarg) > MAX_SIG_LEN) { 126 | fprintf(stderr, "%s: signature exceeds %d chars\n", 127 | progname, MAX_SIG_LEN); 128 | exit(1); 129 | } 130 | strcpy(signature, optarg); 131 | break; 132 | case 'i': 133 | if ((ifile = fopen(optarg, "r")) == NULL) 134 | perrexit(1, optarg); 135 | break; 136 | case 'o': 137 | if ((ofile = fopen(optarg, "w")) == NULL) 138 | perrexit(1, optarg); 139 | break; 140 | default: 141 | usage(); 142 | } 143 | } 144 | 145 | if (signature[0] == 0 || ifile == NULL || ofile == NULL) { 146 | usage(); 147 | } 148 | 149 | if (model[0] == 0) { 150 | char *p = strchr(signature, '-'); 151 | if (p == NULL) { 152 | fprintf(stderr, "%s: model name unknown\n", progname); 153 | exit(1); 154 | } 155 | if (p - signature > MAX_MODEL_NAME_LEN) { 156 | *p = 0; 157 | fprintf(stderr, "%s: auto model name failed, string %s too long\n", progname, signature); 158 | exit(1); 159 | } 160 | strncpy(model, signature, p - signature); 161 | } 162 | 163 | if (patchmode) { 164 | if (fread(&imghdr, sizeof(imghdr), 1, ifile) < 0) 165 | perrexit(2, "fread on input"); 166 | } 167 | 168 | for (bcnt = 0, cksum = 0 ; (c = fgetc(ifile)) != EOF ; bcnt++) 169 | cksum += c & 0xff; 170 | 171 | if (fseek(ifile, patchmode ? sizeof(imghdr) : 0, SEEK_SET) < 0) 172 | perrexit(2, "fseek on input"); 173 | 174 | if (patchmode == 0) { 175 | // Fill in the header 176 | memset(&imghdr, 0, sizeof(imghdr)); 177 | imghdr.checksum = htonl(cksum); 178 | imghdr.partition = 0 ; // don't care? 179 | imghdr.hdr_len = sizeof(imghdr); 180 | if (have_regionversion) { 181 | imghdr.hdr_len += MAX_REGION_LEN; 182 | imghdr.hdr_len += MAX_VERSION_LEN; 183 | } 184 | imghdr.flash_byte_cnt = htonl(bcnt); 185 | } else { 186 | if (ntohl(imghdr.checksum) != cksum) { 187 | fprintf(stderr, "%s: patch mode, checksum mismatch\n", 188 | progname); 189 | if (fixmode) { 190 | fprintf(stderr, "%s: fixing\n", progname); 191 | imghdr.checksum = htonl(cksum); 192 | } else 193 | exit(3); 194 | } else if (ntohl(imghdr.flash_byte_cnt) != bcnt) { 195 | fprintf(stderr, "%s: patch mode, size mismatch\n", 196 | progname); 197 | if (fixmode) { 198 | fprintf(stderr, "%s: fixing\n", progname); 199 | imghdr.flash_byte_cnt = htonl(bcnt); 200 | } else 201 | exit(3); 202 | } 203 | } 204 | 205 | strncpy(imghdr.model, model, MAX_MODEL_NAME_LEN); 206 | strncpy(imghdr.sig, signature, MAX_SIG_LEN); 207 | 208 | if (fwrite(&imghdr, sizeof(imghdr), 1, ofile) < 0) 209 | perrexit(2, "fwrite header on output"); 210 | if (have_regionversion) { 211 | if (fwrite(®ion, MAX_REGION_LEN, 1, ofile) < 0) 212 | perrexit(2, "fwrite header on output"); 213 | if (fwrite(&version, MAX_VERSION_LEN, 1, ofile) < 0) 214 | perrexit(2, "fwrite header on output"); 215 | } 216 | 217 | while ((c = fgetc(ifile)) != EOF) { 218 | if (fputc(c, ofile) == EOF) 219 | perrexit(2, "fputc on output"); 220 | } 221 | 222 | if (ferror(ifile)) 223 | perrexit(2, "fgetc on input"); 224 | 225 | 226 | fclose(ofile); 227 | fclose(ifile); 228 | } 229 | -------------------------------------------------------------------------------- /src/iptime-naspkg.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright (c) 2020 Sungbo Eo 4 | * 5 | * This code is based on mkdhpimg.c and mkzcfw.c 6 | * Copyright (C) 2010 Gabor Juhos 7 | * Copyright (c) 2016 FUKAUMI Naoki 8 | * 9 | * Checksum algorithm is derived from EFM's mknas utility 10 | * found in GPL'ed T16000 source. 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 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(×tamp); 132 | 133 | return asctime(gmtime(×tamp)); 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 \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 | -------------------------------------------------------------------------------- /src/mkqdimg.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* 3 | * Copyright (C) 2025 Coia Prant 4 | * 5 | * The golang version can be found at: 6 | * 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "sha1.h" 20 | 21 | #define HDR_PADDING_BYTE 0x00 22 | #define PADDING_BYTE 0xff 23 | 24 | #define MAX_LENGTH 16647168 25 | #define BOARD_ID_LENGTH 8 26 | #define VERSION_LENGTH 8 27 | #define UBOOT_LENGTH 196608 28 | 29 | #define HDR_LENGTH 0x00000400 30 | #define HDR_OFF_BOARD_ID 0 31 | #define HDR_OFF_VERSION 8 32 | #define HDR_OFF_UBOOT 16 33 | #define HDR_OFF_FIRMWARE 32 34 | #define HDR_OFF_MAGIC 48 35 | #define HDR_OFF_CHECKSUM 52 36 | #define HDR_OFF_UBOOT_LEN 72 37 | #define HDR_OFF_FIRMWARE_LEN 76 38 | #define HDR_MAGIC 538248722 39 | 40 | /* 41 | * Globals 42 | */ 43 | static char *progname; 44 | 45 | /* 46 | * Message macros 47 | */ 48 | #define ERR(fmt, ...) do { \ 49 | fflush(0); \ 50 | fprintf(stderr, "[%s] *** error: " fmt "\n", \ 51 | progname, ## __VA_ARGS__); \ 52 | } while (0) 53 | 54 | #define ERRS(fmt, ...) do { \ 55 | int save = errno; \ 56 | fflush(0); \ 57 | fprintf(stderr, "[%s] *** error: " fmt "\n", \ 58 | progname, ## __VA_ARGS__, strerror(save)); \ 59 | } while (0) 60 | 61 | static void usage(int status) 62 | { 63 | FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; 64 | 65 | fprintf(stream, "Usage: %s [OPTIONS...]\n", progname); 66 | fprintf(stream, 67 | "\n" 68 | "Options:\n" 69 | " -B create image for the board specified with \n" 70 | " -V version string\n" 71 | " -u read uboot image from the file \n" 72 | " -f read firmware image from the file \n" 73 | " -o write output to the file \n" 74 | " -h show this screen\n" 75 | ); 76 | 77 | exit(status); 78 | } 79 | 80 | void writele(unsigned char *buf, size_t offset, uint32_t value) 81 | { 82 | value = htole32(value); 83 | memcpy(buf + offset, &value, sizeof(uint32_t)); 84 | } 85 | 86 | int main(int argc, char *argv[]) 87 | { 88 | int ret = EXIT_FAILURE; 89 | long ulen, flen, buflen = HDR_LENGTH, fspace; 90 | unsigned char *buf; 91 | char *board_id = NULL, *version = NULL, *ufname = NULL, *ffname = NULL, *ofname = NULL; 92 | FILE *out, *uboot = NULL, *firmware = NULL; 93 | 94 | progname = basename(argv[0]); 95 | 96 | while (1) { 97 | int c; 98 | 99 | c = getopt(argc, argv, "B:V:u:f:o:h"); 100 | if (c == -1) 101 | break; 102 | 103 | switch (c) { 104 | case 'B': 105 | board_id = optarg; 106 | break; 107 | case 'V': 108 | version = optarg; 109 | break; 110 | case 'u': 111 | ufname = optarg; 112 | break; 113 | case 'f': 114 | ffname = optarg; 115 | break; 116 | case 'o': 117 | ofname = optarg; 118 | break; 119 | case 'h': 120 | usage(EXIT_SUCCESS); 121 | break; 122 | default: 123 | usage(EXIT_FAILURE); 124 | break; 125 | } 126 | } 127 | 128 | if (board_id == NULL) { 129 | ERR("no board specified"); 130 | goto err; 131 | } 132 | 133 | if (strlen(board_id) > BOARD_ID_LENGTH) { 134 | ERR("board_id \"%s\" is too long - max length: 8\n", 135 | board_id); 136 | goto err; 137 | } 138 | 139 | if (version != NULL && strlen(version) > VERSION_LENGTH) { 140 | ERR("version \"%s\" is too long - max length: 8\n", 141 | version); 142 | goto err; 143 | } 144 | 145 | if (ofname == NULL) { 146 | ERR("no output file specified"); 147 | goto err; 148 | } 149 | 150 | if (ufname != NULL) { 151 | uboot = fopen(ufname, "r"); 152 | if (uboot == NULL) { 153 | ERRS("could not open \"%s\" for reading: %s", ufname); 154 | goto err; 155 | } 156 | 157 | /* Get uboot length */ 158 | fseek(uboot, 0, SEEK_END); 159 | ulen = ftell(uboot); 160 | rewind(uboot); 161 | 162 | if (ulen > UBOOT_LENGTH) { 163 | fclose(uboot); 164 | ERR("file \"%s\" is too big - max size: 0x%08d\n", 165 | ufname, UBOOT_LENGTH); 166 | goto err; 167 | } 168 | 169 | buflen += UBOOT_LENGTH; 170 | } 171 | 172 | if (ffname != NULL) { 173 | firmware = fopen(ffname, "r"); 174 | if (firmware == NULL) { 175 | ERRS("could not open \"%s\" for reading: %s", ffname); 176 | goto err; 177 | } 178 | 179 | /* Get firmware length */ 180 | fseek(firmware, 0, SEEK_END); 181 | flen = ftell(firmware); 182 | rewind(firmware); 183 | 184 | fspace = MAX_LENGTH - buflen; 185 | if (flen > fspace) { 186 | ERR("file \"%s\" is too big - max size: 0x%08ld\n", 187 | ffname, fspace); 188 | goto err_close; 189 | } 190 | 191 | buflen += flen; 192 | } 193 | 194 | /* Allocate and initialize buffer for final image */ 195 | buf = malloc(buflen); 196 | if (buf == NULL) { 197 | ERRS("no memory for buffer: %s\n"); 198 | goto err_close; 199 | } 200 | memset(buf, HDR_PADDING_BYTE, HDR_LENGTH); 201 | memset(buf + HDR_LENGTH, PADDING_BYTE, buflen - HDR_LENGTH); 202 | 203 | /* Write board id */ 204 | memcpy(buf + HDR_OFF_BOARD_ID, board_id, strlen(board_id)); 205 | 206 | /* Write version */ 207 | if (version != NULL) { 208 | memcpy(buf + HDR_OFF_VERSION, version, strlen(version)); 209 | } 210 | 211 | if (uboot != NULL) { 212 | /* Write UBOOT ID */ 213 | memcpy(buf + HDR_OFF_UBOOT, "UBOOT", 5); 214 | 215 | /* Load U-Boot */ 216 | fread(buf + HDR_LENGTH, ulen, 1, uboot); 217 | 218 | /* Write U-Boot Length */ 219 | writele(buf, HDR_OFF_UBOOT_LEN, UBOOT_LENGTH); 220 | } 221 | 222 | if (firmware != NULL) { 223 | /* Write FIRMWARE ID */ 224 | memcpy(buf + HDR_OFF_FIRMWARE, "FIRMWARE", 8); 225 | 226 | /* Load Firmware */ 227 | if (uboot != NULL) { 228 | fread(buf + HDR_LENGTH + UBOOT_LENGTH, flen, 1, firmware); 229 | } else { 230 | fread(buf + HDR_LENGTH, flen, 1, firmware); 231 | } 232 | 233 | /* Write Firmware Length */ 234 | writele(buf, HDR_OFF_FIRMWARE_LEN, flen); 235 | } 236 | 237 | /* Write magic */ 238 | writele(buf, HDR_OFF_MAGIC, HDR_MAGIC); 239 | 240 | /* Write checksum and static hash */ 241 | sha1_csum(buf + HDR_LENGTH, buflen - HDR_LENGTH, buf + HDR_OFF_CHECKSUM); 242 | 243 | /* Save finished image */ 244 | out = fopen(ofname, "w"); 245 | if (out == NULL) { 246 | ERRS("could not open \"%s\" for writing: %s", ofname); 247 | goto err_free; 248 | } 249 | fwrite(buf, buflen, 1, out); 250 | 251 | ret = EXIT_SUCCESS; 252 | 253 | fclose(out); 254 | 255 | err_free: 256 | free(buf); 257 | 258 | err_close: 259 | if (uboot != NULL) { 260 | fclose(uboot); 261 | } 262 | 263 | if (firmware != NULL) { 264 | fclose(firmware); 265 | } 266 | 267 | err: 268 | return ret; 269 | } 270 | -------------------------------------------------------------------------------- /src/zytrx.c: -------------------------------------------------------------------------------- 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 9 | * Gabor Juhos 10 | * Copyright (C) 2021 Bjørn Mork 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #define BPB 8 /* bits/byte */ 26 | 27 | static uint32_t crc32[1<> 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 -v -i [-o ]\n\n", name); 122 | fprintf(stderr, "Supported 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 | -------------------------------------------------------------------------------- /src/hcsmakeimage.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "bcmalgo.h" 14 | 15 | 16 | int flag_print_version; 17 | int flag_print_help; 18 | int flag_compress; 19 | 20 | uint16_t sa2100_magic = 0x2100; 21 | uint16_t sa3349_magic = 0x3349; 22 | uint32_t default_date = 0x00000000; //A long time ago in a galaxy far far away.... 23 | uint32_t default_load_address = 0x80010000; //The default load_address for the firmware image 24 | 25 | static void print_help ( const char* ename ) 26 | { 27 | printf ( "Firmware image packer and calculator for broadcom-based modems.\n" ); 28 | printf ( "Part of bcm-utils package.\n" ); 29 | printf ( "(c) 2009 Necromant (http://necromant.ath.cx). Thanks to Luke-jr for his initial work.\n" ); 30 | printf ( "usage: %s [options]\n", ename ); 31 | printf ( "Valid options are:\n" ); 32 | printf ( "--magic_bytes=value \t- specify magic bytes at the beginning of the image. default - 3349\n" ); 33 | printf ( "\t\t\t these can be sa2100 (for DPC2100 modem),\n\t\t\t sa3349 (haxorware guys use this one for some reason),\n\t\t\t or a custom hex value e.g. 0xFFFF\n" ); 34 | printf ( "--compress \t\t - Make use of LZMA (weird!) compression (Doesn't work yet).\n" ); 35 | printf ( "--rev_maj=value\t\t - major revision number. default 0\n" ); 36 | printf ( "--rev_min=value\t\t - minor revision number default 0\n" ); 37 | printf ( "--filename=value\t - use this filename in header instead of default (input filename)\n" ); 38 | printf ( "--ldaddress=value\t - hex value of the target load address. defaults to 0x80010000\n" ); 39 | printf ( "--input_file=value\t - What file are we packing?\n" ); 40 | printf ( "--output_file=value\t - What file shall we write? (default: image.bin)\n" ); 41 | #ifdef _HAX0RSTYLE 42 | printf ( "--credz\t - Give some credz!\n" ); 43 | #endif 44 | printf ( "\n" ); 45 | } 46 | 47 | static time_t source_date_epoch = -1; 48 | static void set_source_date_epoch() { 49 | char *env = getenv("SOURCE_DATE_EPOCH"); 50 | char *endptr = env; 51 | errno = 0; 52 | if (env && *env) { 53 | source_date_epoch = strtoull(env, &endptr, 10); 54 | if (errno || (endptr && *endptr != '\0')) { 55 | fprintf(stderr, "Invalid SOURCE_DATE_EPOCH"); 56 | exit(1); 57 | } 58 | } 59 | } 60 | 61 | int main ( int argc, char** argv ) 62 | { 63 | if ( argc<2 ) 64 | { 65 | print_help ( argv[0] ); 66 | } 67 | 68 | static struct option long_options[] = 69 | { 70 | {"magic_bytes", required_argument, 0, 'm'}, 71 | {"rev_maj", required_argument, 0, 'j'}, 72 | {"rev_min", required_argument, 0, 'n'}, 73 | {"ldaddress", required_argument, 0, 'l'}, 74 | {"filename", required_argument, 0, 'f'}, 75 | {"input_file", required_argument, 0, 'i'}, 76 | {"output_file", required_argument, 0, 'o'}, 77 | {"compress", no_argument, &flag_compress, 'c'}, 78 | {"version", no_argument, &flag_print_version, 'v'}, 79 | {"help", no_argument, &flag_print_help, 'h'}, 80 | {0, 0, 0, 0} 81 | }; 82 | int option_index = 0; 83 | int opt_result=0; 84 | char* filename=NULL; 85 | char* input=NULL; 86 | char* magic=NULL; 87 | char* major=NULL; 88 | char* minor=NULL; 89 | char* ldaddr=NULL; 90 | char* output=NULL; 91 | 92 | while ( opt_result>=0 ) 93 | { 94 | opt_result = getopt_long ( argc, argv, "m:j:n:f:i:o:vh", long_options, &option_index ); 95 | switch ( opt_result ) 96 | { 97 | case 0: 98 | printf ( "o!\n" ); 99 | break; 100 | case 'h': 101 | print_help ( argv[0] ); 102 | break; 103 | case 'l': 104 | ldaddr=optarg; 105 | break; 106 | case 'f': 107 | filename=optarg; 108 | break; 109 | case 'i': 110 | input=optarg; 111 | break; 112 | case 'o': 113 | output=optarg; 114 | break; 115 | case 'm': 116 | magic=optarg; 117 | break; 118 | case 'j': 119 | major=optarg; 120 | break; 121 | case 'n': 122 | minor=optarg; 123 | break; 124 | } 125 | } 126 | if ( input==NULL ) 127 | { 128 | printf ( "Telepaths are still on holidays. I guess you should tell me what file should I process.\n\n" ); 129 | exit ( 1 ); 130 | } 131 | if ( access ( input,R_OK ) !=0 ) 132 | { 133 | printf ( "I cannot access the file %s. Is it there? Am I allowed?\n\n", input ); 134 | exit ( 1 ); 135 | } 136 | uint32_t magicnum=sa2100_magic; 137 | 138 | if ( magic ) 139 | { 140 | if ( strcmp ( magic,"sa2100" ) ==0 ) magicnum=sa2100_magic; else 141 | if ( strcmp ( magic,"sa3349" ) ==0 ) magicnum=sa3349_magic; else 142 | { 143 | sscanf ( magic, "0x%04X", &magicnum ); 144 | } 145 | } 146 | unsigned int majrev=0; 147 | if ( major ) 148 | { 149 | sscanf ( major, "%d", &majrev ); 150 | } 151 | unsigned int minrev=0; 152 | if ( minor ) 153 | { 154 | sscanf ( minor, "%d", &minrev ); 155 | } 156 | uint32_t ldaddress = default_load_address; 157 | if ( ldaddr ) 158 | { 159 | sscanf ( ldaddr, "0x%08X", &ldaddress ); 160 | } 161 | char* dupe = strdup(input); 162 | char* fname = basename ( dupe ); 163 | if ( filename ) 164 | { 165 | fname = filename; 166 | } 167 | 168 | time_t t = -1; 169 | set_source_date_epoch(); 170 | if (source_date_epoch != -1) { 171 | t = source_date_epoch; 172 | } else if ((time(&t) == (time_t)(-1))) { 173 | fprintf(stderr, "time call failed\n"); 174 | return EXIT_FAILURE; 175 | } 176 | 177 | struct stat buf; 178 | stat ( input,&buf ); 179 | ldr_header_t* head = construct_header ( magicnum, (uint16_t) majrev, (uint16_t) minrev, ( uint32_t ) t, ( uint32_t ) buf.st_size, ldaddress, fname, get_file_crc ( input ) ); 180 | free(dupe); 181 | //uint32_t magic, uint16_t rev_maj,uint16_t rev_min, uint32_t build_date, uint32_t filelen, uint32_t ldaddress, const char* filename, uint32_t crc 182 | //FILE* fd = fopen ("/tftpboot/haxorware11rev32.bin","r"); 183 | //fread(head,sizeof(ldr_header_t),1,fd); 184 | char* filebuffer = malloc ( buf.st_size+10 ); 185 | FILE* fd = fopen ( input,"r" ); 186 | fread ( filebuffer, 1, buf.st_size,fd ); 187 | fclose (fd); 188 | if (!output) 189 | { 190 | output = malloc(strlen(input+5)); 191 | strcpy(output,input); 192 | strcat(output,".bin"); 193 | } 194 | dump_header ( head ); 195 | FILE* fd_out = fopen ( output,"w+" ); 196 | if (!fd_out) 197 | { 198 | fprintf(stderr, "Failed to open output file: %s\n", output); 199 | free(filebuffer); 200 | exit(1); 201 | } 202 | fwrite ( head,1,sizeof ( ldr_header_t ),fd_out ); 203 | fwrite ( filebuffer,1,buf.st_size,fd_out ); 204 | printf("Firmware image %s is ready\n", output); 205 | free(filebuffer); 206 | fclose(fd_out); 207 | return 0; 208 | } 209 | -------------------------------------------------------------------------------- /src/mksercommfw.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #if !defined(__BYTE_ORDER) 12 | #error "Unknown byte order" 13 | #endif 14 | 15 | #if __BYTE_ORDER == __BIG_ENDIAN 16 | #define cpu_to_be32(x) (x) 17 | #elif __BYTE_ORDER == __LITTLE_ENDIAN 18 | #define cpu_to_be32(x) bswap_32(x) 19 | #else 20 | #error "Unsupported endianness" 21 | #endif 22 | 23 | /* #define DEBUG 1 */ 24 | 25 | #ifdef DEBUG 26 | #define DBG(...) {printf(__VA_ARGS__); } 27 | #else 28 | #define DBG(...) {} 29 | #endif 30 | 31 | #define ERR(...) {printf(__VA_ARGS__); } 32 | 33 | /* 34 | * Fw Header Layout for Netgear / Sercomm devices (bytes) 35 | * 36 | * Size : 512 bytes + zipped image size 37 | * 38 | * Locations: 39 | * magic : 0-6 ASCII 40 | * version: 7-11 fixed 41 | * hwID : 11-44 ASCII 42 | * hwVer : 45-54 ASCII 43 | * swVer : 55-62 uint32_t in BE 44 | * magic : 63-69 ASCII 45 | * ChkSum : 511 Inverse value of the full image checksum while this location is 0x00 46 | */ 47 | static const char* magic = "sErCoMm"; /* 7 */ 48 | static const unsigned char version[4] = { 0x00, 0x01, 0x00, 0x00 }; 49 | static const int header_sz = 512; 50 | static const int footer_sz = 71; 51 | 52 | static int is_header = 1; 53 | 54 | struct file_info { 55 | char* file_name; /* name of the file */ 56 | char* file_data; /* data of the file in memory */ 57 | u_int32_t file_size; /* length of the file */ 58 | }; 59 | 60 | static u_int8_t getCheckSum(char* data, int len) { 61 | u_int8_t new = 0; 62 | int i; 63 | 64 | if (!data) { 65 | ERR("Invalid pointer provided!\n"); 66 | return 0; 67 | } 68 | 69 | for (i = 0; i < len; i++) { 70 | new += data[i]; 71 | } 72 | 73 | return new; 74 | } 75 | 76 | /* 77 | * read file into buffer 78 | * add space for header/footer 79 | */ 80 | static int copyToOutputBuf(struct file_info* finfo) { 81 | FILE* fp = NULL; 82 | 83 | int file_sz = 0; 84 | int extra_sz; 85 | int hdr_pos; 86 | int img_pos; 87 | 88 | if (!finfo || !finfo->file_name) { 89 | ERR("Invalid pointer provided!\n"); 90 | return -1; 91 | } 92 | 93 | DBG("Opening file: %s\n", finfo->file_name); 94 | 95 | if (!(fp = fopen(finfo->file_name, "rb"))) { 96 | ERR("Error opening file: %s\n", finfo->file_name); 97 | return -1; 98 | } 99 | 100 | /* Get filesize */ 101 | rewind(fp); 102 | fseek(fp, 0L, SEEK_END); 103 | file_sz = ftell(fp); 104 | rewind(fp); 105 | 106 | if (file_sz < 1) { 107 | ERR("Error getting filesize: %s\n", finfo->file_name); 108 | fclose(fp); 109 | return -1; 110 | } 111 | 112 | if (is_header) { 113 | extra_sz = header_sz; 114 | hdr_pos = 0; 115 | img_pos = header_sz; 116 | } else { 117 | extra_sz = footer_sz; 118 | hdr_pos = file_sz; 119 | img_pos = 0; 120 | } 121 | 122 | DBG("Filesize: %i\n", file_sz); 123 | finfo->file_size = file_sz + extra_sz; 124 | 125 | if (!(finfo->file_data = malloc(finfo->file_size))) { 126 | ERR("Out of memory!\n"); 127 | fclose(fp); 128 | return -1; 129 | } 130 | 131 | /* init header/footer bytes */ 132 | memset(finfo->file_data + hdr_pos, 0, extra_sz); 133 | 134 | /* read file and take care of leading header if exists */ 135 | if (fread(finfo->file_data + img_pos, 1, file_sz, fp) != file_sz) { 136 | ERR("Error reading file %s\n", finfo->file_name); 137 | fclose(fp); 138 | return -1; 139 | } 140 | 141 | DBG("File: read successful\n"); 142 | fclose(fp); 143 | 144 | return hdr_pos; 145 | } 146 | 147 | static int writeFile(struct file_info* finfo) { 148 | FILE* fp; 149 | 150 | if (!finfo || !finfo->file_name) { 151 | ERR("Invalid pointer provided!\n"); 152 | return -1; 153 | } 154 | 155 | DBG("Opening file: %s\n", finfo->file_name); 156 | 157 | if (!(fp = fopen(finfo->file_name, "w"))) { 158 | ERR("Error opening file: %s\n", finfo->file_name); 159 | return -1; 160 | } 161 | 162 | DBG("Writing file: %s\n", finfo->file_name); 163 | 164 | if (fwrite(finfo->file_data, 1, finfo->file_size, fp) != finfo->file_size) { 165 | ERR("Wanted to write, but something went wrong!\n"); 166 | fclose(fp); 167 | return -1; 168 | } 169 | 170 | fclose(fp); 171 | return 0; 172 | } 173 | 174 | static void usage(char* argv[]) { 175 | printf("Usage: %s [OPTIONS...]\n" 176 | "\n" 177 | "Options:\n" 178 | " -f add sercom footer (if absent, header)\n" 179 | " -b use hardware id specified with (ASCII)\n" 180 | " -r use hardware revision specified with (ASCII)\n" 181 | " -v set image version to (decimal, hex or octal notation)\n" 182 | " -i input file\n" 183 | , argv[0]); 184 | } 185 | 186 | int main(int argc, char* argv[]) { 187 | struct file_info image = { 0 }; 188 | 189 | char* hwID = NULL; 190 | char* hwVer = NULL; 191 | u_int32_t swVer = 0; 192 | u_int8_t chkSum; 193 | int hdr_offset; 194 | 195 | while ( 1 ) { 196 | int c; 197 | 198 | c = getopt(argc, argv, "b:i:r:v:f"); 199 | if (c == -1) 200 | break; 201 | 202 | switch (c) { 203 | case 'b': 204 | hwID = optarg; 205 | break; 206 | case 'f': 207 | is_header = 0; 208 | break; 209 | case 'i': 210 | image.file_name = optarg; 211 | break; 212 | case 'r': 213 | hwVer = optarg; 214 | break; 215 | case 'v': 216 | swVer = (u_int32_t) strtol(optarg, NULL, 0); 217 | swVer = cpu_to_be32(swVer); 218 | break; 219 | default: 220 | usage(argv); 221 | return EXIT_FAILURE; 222 | } 223 | } 224 | 225 | if (!hwID || !hwVer || !image.file_name) { 226 | usage(argv); 227 | return EXIT_FAILURE; 228 | } 229 | 230 | /* 231 | * copy input to buffer, add extra space for header/footer and return 232 | * header position 233 | */ 234 | hdr_offset = copyToOutputBuf(&image); 235 | if (hdr_offset < 0) 236 | return EXIT_FAILURE; 237 | 238 | DBG("Filling header: %s %s %2X %s\n", hwID, hwVer, swVer, magic); 239 | 240 | strncpy(image.file_data + hdr_offset + 0, magic, 7); 241 | memcpy(image.file_data + hdr_offset + 7, version, sizeof(version)); 242 | strncpy(image.file_data + hdr_offset + 11, hwID, 34); 243 | strncpy(image.file_data + hdr_offset + 45, hwVer, 10); 244 | memcpy(image.file_data + hdr_offset + 55, &swVer, sizeof(swVer)); 245 | strncpy(image.file_data + hdr_offset + 63, magic, 7); 246 | 247 | /* calculate checksum and invert checksum */ 248 | if (is_header) { 249 | chkSum = getCheckSum(image.file_data, image.file_size); 250 | chkSum = (chkSum ^ 0xFF) + 1; 251 | DBG("Checksum for Image: %hhX\n", chkSum); 252 | 253 | /* write checksum to header */ 254 | image.file_data[511] = (char) chkSum; 255 | } 256 | 257 | /* overwrite input file */ 258 | if (writeFile(&image)) 259 | return EXIT_FAILURE; 260 | 261 | return EXIT_SUCCESS; 262 | } 263 | --------------------------------------------------------------------------------