1/* 2 * Copyright (C) 2014 Claudio Leite <leitec@staticky.com> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 */ 18 19/* 20 * Builds a proper flash image for routers using some Gemtek 21 * OEM boards. These include the Airlink101 AR725W, the 22 * Asante SmartHub 600 (AWRT-600N), and Linksys WRT100/110. 23 * 24 * The resulting image is compatible with the factory firmware 25 * web upgrade and TFTP interface. 26 * 27 * To build: 28 * gcc -O2 -o mkheader_gemtek mkheader_gemtek.c -lz 29 * 30 * Claudio Leite <leitec@staticky.com> 31 */ 32 33#include <stdio.h> 34#include <stdlib.h> 35#include <stdint.h> 36#include <string.h> 37 38#include <zlib.h> /* for crc32() */ 39 40/* 41 * The header is in little-endian format. In case 42 * we are on a BE host, we need to swap binary 43 * values. 44 */ 45#ifdef __APPLE__ 46# include <libkern/OSByteOrder.h> 47# define le32 OSSwapHostToLittleInt32 48#else 49# if defined(__linux__) 50# include <endian.h> 51# if __BYTE_ORDER == __BIG_ENDIAN 52# define CPU_BIG_ENDIAN 53# endif 54# else 55# include <sys/endian.h> /* BSD's should have this */ 56# if _BYTE_ORDER == _BIG_ENDIAN 57# define CPU_BIG_ENDIAN 58# endif 59# endif 60# ifdef CPU_BIG_ENDIAN 61# define le32(x) (((x & 0xff000000) >> 24) | \ 62 ((x & 0x00ff0000) >> 8) | \ 63 ((x & 0x0000ff00) << 8) | \ 64 ((x & 0x000000ff) << 24)) 65# else 66# define le32(x) (x) 67# endif 68#endif 69 70struct gemtek_header { 71 uint8_t magic[4]; 72 uint8_t version[4]; 73 uint32_t product_id; 74 uint32_t imagesz; 75 uint32_t checksum; 76 uint32_t fast_checksum; 77 uint8_t build[4]; 78 uint8_t lang[4]; 79}; 80 81#define HDRLEN sizeof(struct gemtek_header) 82 83struct machines { 84 char *desc; 85 char *id; 86 uint32_t maxsize; 87 struct gemtek_header header; 88}; 89 90struct machines mach_def[] = { 91 {"Airlink101 AR725W", "ar725w", 0x340000, 92 {"GMTK", "1003", le32(0x03000001), 0, 0, 93 0, "01\0\0", "EN\0\0"}}, 94 {"Asante AWRT-600N", "awrt600n", 0x340000, 95 {"A600", "1005", le32(0x03000001), 0, 0, 96 0, "01\0\0", "EN\0\0"}}, 97 {"Linksys WRT100", "wrt100", 0x320000, 98 {"GMTK", "1007", le32(0x03040001), 0, 0, 99 0, "2\0\0\0", "EN\0\0"}}, 100 {"Linksys WRT110", "wrt110", 0x320000, 101 {"GMTK", "1007", le32(0x03040001), 0, 0, 102 0, "2\0\0\0", "EN\0\0"}}, 103 {0} 104}; 105 106int 107main(int argc, char *argv[]) 108{ 109 unsigned long res, flen; 110 struct gemtek_header my_hdr; 111 FILE *f, *f_out; 112 int image_type = -1, index; 113 uint8_t *buf; 114 uint32_t crc; 115 116 if (argc < 3) { 117 fprintf(stderr, "mkheader_gemtek <uImage> <webflash image> [machine ID]\n"); 118 fprintf(stderr, " where [machine ID] is one of:\n"); 119 for (index = 0; mach_def[index].desc != 0; index++) { 120 fprintf(stderr, " %-10s %s", mach_def[index].id, mach_def[index].desc); 121 if (index == 0) 122 fprintf(stderr, " (default)\n"); 123 else 124 fprintf(stderr, "\n"); 125 } 126 127 exit(-1); 128 } 129 130 if (argc == 4) { 131 for(index = 0; mach_def[index].id != 0; index++) { 132 if(strcmp(mach_def[index].id, argv[3]) == 0) { 133 image_type = index; 134 break; 135 } 136 } 137 138 if(image_type == -1) { 139 fprintf(stderr, "\nERROR: invalid machine type\n"); 140 exit(-1); 141 } 142 } else 143 image_type = 0; 144 145 printf("Opening %s...\n", argv[1]); 146 147 f = fopen(argv[1], "r"); 148 if(!f) { 149 fprintf(stderr, "\nERROR: couldn't open input image\n"); 150 exit(-1); 151 } 152 153 fseek(f, 0, SEEK_END); 154 flen = (unsigned long) ftell(f); 155 156 printf(" %lu (0x%lX) bytes long\n", flen, flen); 157 158 if (flen > mach_def[image_type].maxsize) { 159 fprintf(stderr, "\nERROR: image exceeds maximum compatible size\n"); 160 goto f_error; 161 } 162 163 buf = malloc(flen + HDRLEN); 164 if (!buf) { 165 fprintf(stderr, "\nERROR: couldn't allocate buffer\n"); 166 goto f_error; 167 } 168 rewind(f); 169 res = fread(buf + HDRLEN, 1, flen, f); 170 if (res != flen) { 171 perror("Couldn't read entire file: fread()"); 172 goto f_error; 173 } 174 fclose(f); 175 176 printf("\nCreating %s...\n", argv[2]); 177 178 memcpy(&my_hdr, &mach_def[image_type].header, HDRLEN); 179 180 printf(" Using %s magic\n", mach_def[image_type].desc); 181 182 my_hdr.imagesz = le32(flen + HDRLEN); 183 memcpy(my_hdr.lang, "EN", 2); 184 185 memcpy(buf, &my_hdr, HDRLEN); 186 187 crc = crc32(0, buf, flen + HDRLEN); 188 printf(" CRC32: %08X\n", crc); 189 190 my_hdr.checksum = le32(crc); 191 memcpy(buf, &my_hdr, HDRLEN); 192 193 printf(" Writing...\n"); 194 195 f_out = fopen(argv[2], "w"); 196 if(!f_out) { 197 fprintf(stderr, "\nERROR: couldn't open output image\n"); 198 exit(-1); 199 } 200 201 fwrite(buf, 1, flen + HDRLEN, f_out); 202 203 fclose(f_out); 204 205 free(buf); 206 return 0; 207 208f_error: 209 fclose(f); 210 exit(-1); 211} 212