/* _JNJ` .JNMH` JMMF` `;. .NMM) `MN. MMM) (MML (MMM` MMML M I D N I G H T C o D E (NMMF MHNH NMML .MMM NMML .NMH 4MMNL .#F `4HNNL_ ` `"""` Copyright (C) 2004-2005 "Ian (Larry) Latter" This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, and mirrored at the Midnight Code web site; as at version 2 of the License only. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License (version 2) along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA, or see http://midnightcode.org/gplv2.txt */ /* * October 4, 2005 - v0.6 * * Thanks to Eric B for providing header magic for the F5D8230-4 (v1) * TODO: Different hardware versions should be command-line optioned * */ /* * January 29, 2005 - v0.5 * * Tool exended to support original openwrt trx tool functionality. * OMG ... this code needs a rethink .. but not tonight josephine .. * */ /* * January 26, 2005 - v0.4 * * Tool exended to support extraction of kernel, file system and * nvram vars from image. This version was never published. * */ /* * October 10, 2004 - v0.3 * * This "belky" tool is a hacked addition to OpenWRT's "trx" tool * (as at July 29, 2004) which in itself is a hacked replacement for * the 'trx' utility used to create wrt54g .trx firmware files. It * isn't pretty, but ... you know ... * * -- Adapted from "trx" by Manuel Novoa III of August 2004 * */ /* * Nb: what was never made clear was that this file had been written * to compile cleanly under Visual Studio - to build a native * win32 binary. Fortunately, this was not ever needed to be * used, however, the hooks have been left in place for someone * more adventurous. * */ /* * Compile; * * touch stdafx.h * cc belky.c -o belky * # or; make belky * */ /* Visual Studio requires this header */ #ifdef _MSC_VER #include "stdafx.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #define O_BINARY 0 #if __BYTE_ORDER == __BIG_ENDIAN #define STORE32_LE(X) bswap_32(X) #define PULL32_LE(X) bswap_32(X) #elif __BYTE_ORDER == __LITTLE_ENDIAN #define STORE32_LE(X) (X) #define PULL32_LE(X) (X) #else #error unkown endianness! #endif uint32_t crc32buf(char *buf, size_t len); /**********************************************************************/ /* Program Info */ char vernam[32] = "belky"; char vernum[6] = "0.5"; /* Type codes */ int TYPE_TRX = 1; int TYPE_EXTENDED = 2; /* home-made goodies .. * Thanks to Eric B for providing header magic for the F5D8230-4 (v1) */ // #define BELKY_MAGIC_H 0x002f0102 /* F5D8230-4 Header Magic */ #define BELKY_MAGIC_H 0x44414F4C /* "LOAD" */ #define TRX_MAGIC 0x30524448 /* "HDR0" */ #define BELKY_MAGIC_F 0x5241564E /* "NVAR" */ // Seems the Header Version is wrong .. hmmm #define BELKY_VERS_H 0x00000800 /* Version Magic */ #define TRX_VERSION 1 #define BELKY_VERS_F 0x00008000 /* Version Magic */ #define BELKY_MAX_LEN 0x3A0000 struct belky_header { uint32_t magic; /* 0 ... 3 "LOAD" */ uint32_t len; /* 4 ... 7 Length of file including header */ uint32_t crc32; /* 8 ... 11 32-bit CRC (ver to eof), LE, !bit */ uint32_t version; /* 12 ... 27 0x8000 (32bit LE), 0, 0, 0 */ uint32_t pad_0; uint32_t pad_1; uint32_t pad_2; }; struct belky_header *header; struct trx_header { uint32_t magic; /* "HDR0" */ uint32_t len; /* Length of file including header */ uint32_t crc32; /* 32-bit CRC from flag_version to end of file */ uint32_t flag_version; /* 0:15 flags, 16:31 version */ uint32_t offsets[3]; /* Partition offsets from start of header */ }; struct trx_header *theader; struct belky_footer { uint32_t magic; /* 0 ... 3 "NVAR" */ uint32_t len; /* 4 ... 7 Length of footer including magic */ uint32_t crc32; /* 8 ... 11 32-bit CRC (ver to eof), LE */ uint32_t version; /* 12 ... 27 0x8000 (32bit LE), 0, 0, 0 */ uint32_t pad_0; uint32_t pad_1; uint32_t pad_2; }; struct belky_footer *footer; /* Transient program global variables */ uint32_t action_type; uint32_t fs_count; uint32_t config_create; uint32_t config_extract; uint32_t config_maxlen; char config_kernel[256]; char config_fs0[256]; char config_fs1[256]; char config_fs2[256]; char config_trx[256]; char config_output[256]; char config_userconf[256]; /* disabling this allows assumptions to be made, RE user request */ int allow_dumb_defaults = 0; /**********************************************************************/ int input_validation(void) { /* action (create/extractg) check */ if (config_extract == 0 && config_create == 0) { printf("%s: no action (create or extract) specified " "(try --help).\n", vernam); return -1; } if (config_extract > 0 && config_create > 0) { printf("%s: two actions (create and extract) specified " "(try --help).\n", vernam); return -1; } /* output file check */ if (strlen(config_output) == 0 && action_type == TYPE_EXTENDED) { if (allow_dumb_defaults) { strncpy(config_output, "firmware.belkin", 255); } else { printf("%s: no output file specified " "(try --help).\n", vernam); return -1; } } /* OpenWRT firmware file check */ if (strlen(config_trx) == 0) { if (allow_dumb_defaults) { strncpy(config_trx, "linux.trx", 255); } if (strlen(config_kernel) == 0 || strlen(config_fs0) ==0) { printf("%s: no trx, and no alternative (kernel or " "filesystem) files specified (try --help).\n", vernam); return -1; } } /* user.conf file check */ if (strlen(config_userconf) == 0 && action_type == TYPE_EXTENDED) { if (allow_dumb_defaults) { strncpy(config_userconf, "user.conf", 255); } if (strlen(config_trx) == 0) { printf("%s: no trx or user.conf file specified " "(try --help).\n", vernam); return -1; } } /* filesystem stacking check */ if (strlen(config_fs1) != 0 && strlen(config_fs0) == 0) { printf("%s: fs1 specified without fs0 (?) " "(try --help).\n", vernam); return -1; } /* if (strlen(config_fs2) != 0 && strlen(config_fs0) == 0) { printf("%s: fs2 specified without fs0 (?) " "(try --help).\n", vernam); return -1; } if (strlen(config_fs2) != 0 && strlen(config_fs1) == 0) { printf("%s: fs2 specified without fs1 (?) " "(try --help).\n", vernam); return -1; } */ if (strlen(config_fs0) != 0) fs_count++; if (strlen(config_fs1) != 0) fs_count++; /* if (strlen(config_fs2) != 0) fs_count++; */ /* action and pre-reqs check */ if (action_type == TYPE_TRX && (strlen(config_kernel) == 0 || fs_count == 0)) { printf("%s: TRX requested, but kernel or file system " "parameter is missing (try --help).\n", vernam); return -1; } /* maxlen check */ if (config_maxlen > BELKY_MAX_LEN) { printf("%s: *warning* maxlen [%u] exceeds default maximum " " [%u]\n", vernam, config_maxlen, BELKY_MAX_LEN); printf("%s: Be very careful, you may overwrite NVRAM\n", vernam); } else { config_maxlen = BELKY_MAX_LEN; } return 0; } int read_in_data_file(char * data_file, void * buffer, int maxbytes, int type) { int fd; int bytes; char filesize[3]; bytes = 0; if (maxbytes < 0) { printf("%s: spare buffer space is negative -- " "increase maxlen (?)\n", vernam); return -1; } if ((fd = open(data_file, O_BINARY | O_RDONLY )) < 0) { printf("%s: unable to open file [%s] for reading.\n", vernam, data_file); return -1; } if(lseek(fd, 0, SEEK_SET) < 0) { printf("%s: unable to seek to start of file [%s]\n", vernam, data_file); return -1; } /* special work for user.conf file */ if (type == 2) { memset(filesize, 0, 3); bytes = read(fd, filesize, 2); if (bytes < 0) { printf("%s: unable to read from user.conf file [%s].\n", vernam, data_file); return -1; } bytes = (uint8_t)filesize[1] * 256 + (uint8_t)filesize[0]; if (bytes > 0) { if ((bytes - 18) <= maxbytes) { maxbytes = bytes - 18; } else { printf("%s: more data in file [%s] than space " "left in buffer -- increase maxlen?\n", vernam, data_file); return -1; } } else { printf("%s: unable to read file size from header of " "file [%s].\n", vernam, data_file); return -1; } } bytes = read(fd, buffer, maxbytes); close(fd); if(bytes < 0) { printf("%s: unable to read from file [%s].\n", vernam, data_file); return -1; } return bytes; } int write_out_data_file(char * data_file, void * buffer, int maxbytes, int type) { int fd; int bytes; char filesize[3]; if (maxbytes <= 0) { printf("%s: embedded file to be written had corrupt " "length (?)\n", vernam); return -1; } if ((fd = open(data_file, O_BINARY | O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH )) < 0) { printf("%s: unable to open file [%s] for writing.\n", vernam, data_file); return -1; } bytes = write(fd, buffer, maxbytes); close(fd); if(bytes <= 0) { printf("%s: unable to write to file [%s].\n", vernam, data_file); return -1; } return bytes; } int write_firmware(char * data_file, char * buffer, int maxbytes) { int fd; if ((fd = open(data_file, O_BINARY | O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH )) < 0) { printf("%s: unable to open firmware file [%s] for writing.\n", vernam, data_file); return -1; } if (write(fd, buffer, maxbytes) <= 0) { printf("%s: unable to write to firmware file [%s].\n", vernam, data_file); return -1; } close(fd); return 0; } int fill_headers(uint32_t filelen, uint32_t trxlen, uint32_t footerlen, int ft) { if (ft == 0) { theader->magic = STORE32_LE(TRX_MAGIC); theader->flag_version = STORE32_LE((TRX_VERSION << 16)); theader->crc32 = crc32buf((char *) &theader->flag_version, trxlen - offsetof(struct trx_header, flag_version)); theader->crc32 = STORE32_LE(theader->crc32); theader->len = STORE32_LE(trxlen); } if (action_type == TYPE_TRX) return 0; footer->magic = STORE32_LE(BELKY_MAGIC_F); footer->version = STORE32_LE(BELKY_VERS_F); footer->crc32 = crc32buf((char *) &footer->version, footerlen - offsetof(struct belky_footer, version)); footer->crc32 = STORE32_LE(footer->crc32); footer->len = STORE32_LE(footerlen); // Seems the Header Version is wrong .. hmmm header->magic = STORE32_LE(BELKY_MAGIC_H); header->version = STORE32_LE(BELKY_VERS_F); header->crc32 = crc32buf((char *) &header->version, filelen - offsetof(struct belky_header, version)); header->crc32 = STORE32_LE(header->crc32); header->len = STORE32_LE(filelen); return 0; } int write_debug(char * data_file, char * buffer, int maxbytes) { int fd; if ((fd = open(data_file, O_BINARY | O_RDWR | O_CREAT | O_TRUNC )) < 0) { printf("%s: unable to open debug file [%s] for writing.\n", vernam, data_file); return -1; } if (write(fd, buffer, maxbytes) <= 0) { printf("%s: unable to write to debug file [%s].\n", vernam, data_file); return -1; } close(fd); return 0; } int usage(int errlvl, char * runbin) { /* how many printf's must a man print out, before he is truly a man */ /* printf("%s: Usage;\n\n", vernam); printf(" Create;\n"); printf(" %s -c[et] [-t {linux.trx}] [-u {user.conf}] " "[-e {firmware.belkin}] [-m maxlen]\n", runbin); printf("\n"); printf(" Extract;\n"); printf(" %s -x[et] [-t {linux.trx}] [-u {user.conf}] " "[-e {firmware.belkin}] [-m maxlen]\n", runbin); printf("\n\n"); */ printf("%s: Parameters;\n\n", vernam); printf(" Long Short Args Description\n"); printf(" ~~~~~~~~~~ ~~~~~~~ ~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" "~~~~~~~~~~~~~~~~\n"); printf(" --create[et] -ce|-ct Create [e]xtended or [t]rx " "type firmware\n"); printf(" --exfirm -e {file} Use extended firmware file " "{file}\n"); printf(" --filesystem0 -fs0 {file} Use file {file} as the first " "file system\n"); printf(" --filesystem1 -fs1 {file} Use file {file} as the second " "file system\n"); /* printf(" --filesystem2 -fs2 {file} Use file {file} as the third " "file system\n"); */ printf(" --help -h Display this help screen\n"); printf(" --kernel -k {file} Use kernel file {file}\n"); printf(" --maxlen -m {num} Over-ride / set firmware max " "length to {num}\n"); printf(" --trx -t {file} Use OpenWRT (Broadcom) TRX " "firmware file {file}\n"); printf(" --userconf -u {file} Use Belkin \"user.conf\" file " "{file}\n"); printf(" --version -V Display version and exit\n"); printf(" --extract[et] -xe|-xt Extract [e]xtended or [t]rx " "type firmware\n"); printf("\n\n"); printf("%s: Example;\n\n", vernam); printf(" %s -xe -e F5D7230-4_x.bin " "-k kernel.bin -fs0 cramfs.bin -u nvram.txt\n", runbin); printf(" %s -ct -t linux.trx -k kernel.bin -fs0 cramfs.bin\n", runbin); printf("\n"); /* the answer, my friend, is exit number one ... */ /* the answer is exit number one .. */ exit(errlvl); } void parse_args(int argc, char** argv) { int argn; /* defaults */ action_type = 0; fs_count = 0; config_create = 0; config_extract = 0; config_maxlen = 0; memset(config_fs0, 0, 256); memset(config_fs1, 0, 256); memset(config_fs2, 0, 256); memset(config_kernel, 0, 256); memset(config_trx, 0, 256); memset(config_output, 0, 256); memset(config_userconf, 0, 256); argn = 1; while (argn < argc && argv[argn][0] == '-') { // -ce, --createe if (strcmp(argv[argn], "-ce") == 0 || strcmp(argv[argn], "--createe") == 0) { config_create = TYPE_EXTENDED; action_type = config_create; } // -ct, --createt else if (strcmp(argv[argn], "-ct") == 0 || strcmp(argv[argn], "--createt") == 0) { config_create = TYPE_TRX; action_type = config_create; } // -e, --exfirm else if ((strcmp(argv[argn], "-e") == 0 || strcmp(argv[argn], "--exfirm") == 0) && argn + 1 < argc) { ++argn; strncpy(config_output, argv[argn], 255); } // -fs0, --filesystem0 else if ((strcmp(argv[argn], "-fs0") == 0 || strcmp(argv[argn], "--filesystem0") == 0) && argn + 1 < argc) { ++argn; strncpy(config_fs0, argv[argn], 255); } // -fs1, --filesystem1 else if ((strcmp(argv[argn], "-fs1") == 0 || strcmp(argv[argn], "--filesystem1") == 0) && argn + 1 < argc) { ++argn; strncpy(config_fs1, argv[argn], 255); } // -fs2, --filesystem2 /* else if ((strcmp(argv[argn], "-fs2") == 0 || strcmp(argv[argn], "--filesystem2") == 0) && argn + 1 < argc) { ++argn; strncpy(config_fs2, argv[argn], 255); } */ // -h, --help else if (strcmp(argv[argn], "-h") == 0 || strcmp(argv[argn], "--help") == 0) { usage(0, argv[0]); } // -k, --kernel else if ((strcmp(argv[argn], "-k") == 0 || strcmp(argv[argn], "--kernel") == 0) && argn + 1 < argc) { ++argn; strncpy(config_kernel, argv[argn], 255); } // -m, --maxlen else if ((strcmp(argv[argn], "-m") == 0 || strcmp(argv[argn], "--maxlen") == 0) && argn + 1 < argc) { ++argn; config_maxlen = (uint32_t)atoi(argv[argn]); } // -t, --trx else if ((strcmp(argv[argn], "-t") == 0 || strcmp(argv[argn], "--trx") == 0) && argn + 1 < argc) { ++argn; strncpy(config_trx, argv[argn], 255); } // -u, --userconf else if ((strcmp(argv[argn], "-u") == 0 || strcmp(argv[argn], "--userconf") == 0) && argn + 1 < argc) { ++argn; strncpy(config_userconf, argv[argn], 255); } // -V, --version else if (strcmp(argv[argn], "-V") == 0 || strcmp(argv[argn], "--version") == 0) { printf("%s v%s\n", vernam, vernum); exit(0); } // -xe, --extracte else if (strcmp(argv[argn], "-xe") == 0 || strcmp(argv[argn], "--extracte") == 0) { config_extract = TYPE_EXTENDED; action_type = config_extract; } // -xt, --extractt else if (strcmp(argv[argn], "-xt") == 0 || strcmp(argv[argn], "--extractt") == 0) { config_extract = TYPE_TRX; action_type = config_extract; } // doh else { printf("%s: Unrecognised command parameter [%s]," " exiting.\n", vernam, argv[argn]); usage(1, argv[0]); } ++argn; } if ( argn != argc ) usage(1, argv[0]); } // Evil way to make main main #ifdef WIN32 int _tmain(int argc, _TCHAR* argv[]) { #else int main(int argc, char **argv) { #endif /* win32 */ int maxlen; int bytes; int totlen; int trxlen; int fotlen; int fromtrx; int pullen; #if O_BINARY _setmode (fileno(stdin), O_BINARY); _setmode (fileno(stdout), O_BINARY); #endif /* obtain configuration state */ parse_args(argc, argv); /* input validation check */ if (input_validation() < 0) { return -1; } /* create memory region for firmware storage */ if ((header = (struct belky_header *)malloc(config_maxlen)) == NULL) { printf("%s: unable to malloc [%d] bytes.\n", vernam, config_maxlen); if (header) free(header); return -1; } memset(header, 0, config_maxlen); /* v0.5 supports trx de/construction */ theader = (struct trx_header *)((char *)header + sizeof(struct belky_header)); /* v0.4 supports image extraction */ if (config_extract) { if (action_type == TYPE_TRX) { maxlen = config_maxlen - sizeof(struct belky_header); /* read firmware from linux.trx file */ bytes = read_in_data_file(config_trx, (void *)theader, maxlen, 1); } else { maxlen = config_maxlen; /* read firmware from firmware.belkin file */ bytes = read_in_data_file(config_output, (void *)header, maxlen, 1); } if (bytes < 0) { return -1; } /* pull out extended files? */ if (action_type == TYPE_EXTENDED) { /* setup the footer location */ footer = (struct belky_footer *)((char *)header + (uint32_t)PULL32_LE(theader->len) + sizeof(struct belky_footer)); /* pull out trx ?*/ if (strlen(config_trx) !=0) { pullen = PULL32_LE(theader->len); write_firmware(config_trx, (char *)theader, pullen); if (bytes < 0) { return -1; } } /* pull out nvram ?*/ if (strlen(config_userconf) !=0) { pullen = PULL32_LE(footer->len) - sizeof(struct belky_footer); write_firmware(config_userconf, (char *)footer + sizeof(struct belky_footer), pullen); if (bytes < 0) { return -1; } } } /* pull out kernel ?*/ if (strlen(config_kernel) !=0) { if (theader->offsets[0] == 0) { printf("%s: no kernel file offset found\n", vernam); return -1; } if (theader->offsets[1] != 0) { pullen = PULL32_LE(theader->offsets[1]) - PULL32_LE(theader->offsets[0]); } else { pullen = PULL32_LE(theader->len) - PULL32_LE(theader->offsets[0]); } write_firmware(config_kernel, (char *)theader + theader->offsets[0], pullen); if (bytes < 0) { return -1; } } /* pull out fs0 ?*/ if (strlen(config_fs0) !=0) { if (theader->offsets[1] == 0) { printf("%s: no fs0 offset found\n", vernam); return -1; } if (theader->offsets[2] != 0) { pullen = PULL32_LE(theader->offsets[2]) - PULL32_LE(theader->offsets[1]); } else { pullen = PULL32_LE(theader->len) - PULL32_LE(theader->offsets[1]); } write_firmware(config_fs0, (char *)theader + theader->offsets[1], pullen); if (bytes < 0) { return -1; } } /* pull out fs1 ?*/ if (strlen(config_fs1) !=0) { if (theader->offsets[2] == 0) { printf("%s: no fs1 offset found\n", vernam); return -1; } pullen = PULL32_LE(theader->len) - PULL32_LE(theader->offsets[2]); write_firmware(config_fs1, (char *)theader + theader->offsets[2], pullen); if (bytes < 0) { return -1; } } } else { /* add the meat - build the trx component first */ trxlen = 0; /* assumption based on no defaults .. */ if (strlen(config_kernel) != 0) { /* not created from a trx file */ fromtrx = 0; /* create trx from source files */ trxlen = sizeof(struct trx_header); /* + kernel */ theader->offsets[0] = STORE32_LE(trxlen); maxlen = config_maxlen - sizeof(struct belky_header) - trxlen; if (action_type == TYPE_EXTENDED) maxlen = maxlen - sizeof(struct belky_footer); bytes = read_in_data_file(config_kernel, (void *)theader + trxlen, maxlen, 1); if (bytes < 0) { return -1; } /* structure alignment? take ur word 4 it. */ if (fs_count > 0) { if (bytes & (4-1)) { // memset(theader + trxlen + 4, 0, // 4 - (bytes & (4-1))); bytes += 4 - (bytes & (4-1)); } } trxlen += bytes; if (strlen(config_fs0) != 0) { /* + fs0 */ theader->offsets[1] = STORE32_LE(trxlen); maxlen = config_maxlen - sizeof(struct belky_header) - trxlen; if (action_type == TYPE_EXTENDED) maxlen = maxlen - sizeof(struct belky_footer); bytes = read_in_data_file(config_fs0, (void *)theader + trxlen, maxlen, 1); if (bytes < 0) { return -1; } /* structure alignment? take ur word 4 it. */ if (fs_count > 1) { if (bytes & (4-1)) { memset(theader + trxlen + 4, 0, 4 - (bytes & (4-1))); bytes += 4 - (bytes & (4-1)); } } trxlen += bytes; } if (strlen(config_fs1) != 0) { /* + fs1 */ theader->offsets[2] = STORE32_LE(trxlen); maxlen = config_maxlen - sizeof(struct belky_header) - trxlen; if (action_type == TYPE_EXTENDED) maxlen = maxlen - sizeof(struct belky_footer); bytes = read_in_data_file(config_fs1, (void *)theader + trxlen, maxlen, 1); if (bytes < 0) { return -1; } /* structure alignment? take ur word 4 it. */ /* if (fs_count > 1) { if (bytes & (4-1)) { memset(theader + trxlen + 4, 0, 4 - (bytes & (4-1))); bytes += 4 - (bytes & (4-1)); } } */ trxlen += bytes; } bytes = trxlen & (0x1000 - 1); if (bytes) { // memset(theader + trxlen, 0, 0x1000 - bytes); trxlen += 0x1000 - bytes; } } else { /* created from a trx file */ fromtrx = 1; /* read in the linux.trx file */ maxlen = config_maxlen - sizeof(struct belky_header) - sizeof(struct belky_footer); bytes = read_in_data_file(config_trx, (void *)header + sizeof(struct belky_header), maxlen, 1); if (bytes < 0) { return -1; } trxlen = bytes; } if (action_type == TYPE_TRX) { /* total length of trx firmware */ totlen = trxlen; } else { /* total length of extended firmware, so far */ totlen = sizeof(struct belky_header) + trxlen; /* set the correct footer offset */ footer = (struct belky_footer *)((char *)header + (uint32_t)totlen); if (strlen(config_userconf) == 0) { printf("%s: extended firmware requested, " "NVRAM file is missing " "(try --help).\n", vernam); return -1; } /* read in the user.conf file */ maxlen = config_maxlen - sizeof(struct belky_footer) - totlen; bytes = read_in_data_file(config_userconf, (void *)footer + sizeof(struct belky_footer), maxlen, 1); if (bytes < 0) { return -1; } /* structure alignment? take ur word 4 it. */ /* if (bytes & (4-1)) { bytes += 4 - (bytes & (4-1)); } */ fotlen = sizeof(struct belky_footer) + bytes; totlen += fotlen; /* fotlen = sizeof(footer->version) + sizeof(footer->pad_0) + sizeof(footer->pad_1) + sizeof(footer->pad_2) + bytes; */ } /* time to colour in the picture */ if (fill_headers((uint32_t)totlen, (uint32_t)trxlen, (uint32_t)fotlen, fromtrx) < 0) { return -1; } maxlen = totlen; /* write firmware to firmware.belkin file */ if (action_type == TYPE_TRX) { bytes = write_firmware(config_trx, (char *)theader, maxlen); } else { bytes = write_firmware(config_output, (char *)header, maxlen); } if (bytes < 0) { return -1; } } return(0); } /**********************************************************************/ /* The following was grabbed and tweaked from the old snippets collection * of public domain C code. */ /**********************************************************************\ |* Demonstration program to compute the 32-bit CRC used as the frame *| |* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71 *| |* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level *| |* protocol). The 32-bit FCS was added via the Federal Register, *| |* 1 June 1982, p.23798. I presume but don't know for certain that *| |* this polynomial is or will be included in CCITT V.41, which *| |* defines the 16-bit CRC (often called CRC-CCITT) polynomial. FIPS *| |* PUB 78 says that the 32-bit FCS reduces otherwise undetected *| |* errors by a factor of 10^-5 over 16-bit FCS. *| \**********************************************************************/ /* Copyright (C) 1986 Gary S. Brown. You may use this program, or code or tables extracted from it, as desired without restriction. */ /* First, the polynomial itself and its table of feedback terms. The */ /* polynomial is */ /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ /* Note that we take it "backwards" and put the highest-order term in */ /* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ /* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ /* the MSB being 1. */ /* Note that the usual hardware shift register implementation, which */ /* is what we're using (we're merely optimizing it by doing eight-bit */ /* chunks at a time) shifts bits into the lowest-order term. In our */ /* implementation, that means shifting towards the right. Why do we */ /* do it this way? Because the calculated CRC must be transmitted in */ /* order from highest-order term to lowest-order term. UARTs transmit */ /* characters in order from LSB to MSB. By storing the CRC this way, */ /* we hand it to the UART in the order low-byte to high-byte; the UART */ /* sends each low-bit to hight-bit; and the result is transmission bit */ /* by bit from highest- to lowest-order term without requiring any bit */ /* shuffling on our part. Reception works similarly. */ /* The feedback terms table consists of 256, 32-bit entries. Notes: */ /* */ /* 1. The table can be generated at runtime if desired; code to do so */ /* is shown later. It might not be obvious, but the feedback */ /* terms simply represent the results of eight shift/xor opera- */ /* tions for all combinations of data and CRC register values. */ /* */ /* 2. The CRC accumulation logic is the same for all CRC polynomials, */ /* be they sixteen or thirty-two bits wide. You simply choose the */ /* appropriate table. Alternatively, because the table can be */ /* generated at runtime, you can start by generating the table for */ /* the polynomial in question and use exactly the same "updcrc", */ /* if your application needn't simultaneously handle two CRC */ /* polynomials. (Note, however, that XMODEM is strange.) */ /* */ /* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */ /* of course, 32-bit entries work OK if the high 16 bits are zero. */ /* */ /* 4. The values must be right-shifted by eight bits by the "updcrc" */ /* logic; the shift must be unsigned (bring in zeroes). On some */ /* hardware you could probably optimize the shift in assembler by */ /* using byte-swap instructions. */ static const uint32_t crc_32_tab[] = { /* CRC polynomial 0xedb88320 */ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; #define UPDC32(octet,crc) (crc_32_tab[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8)) uint32_t crc32buf(char *buf, size_t len) { uint32_t crc; crc = 0xFFFFFFFF; for ( ; len; --len, ++buf) { crc = UPDC32(*buf, crc); } return crc; }