firmware-utils: add sercomm/netgear tool
[openwrt/openwrt.git] / tools / firmware-utils / src / mksercommfw.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4
5 /* #define DEBUG 1 */
6
7 /*
8 * Fw Header Layout for Netgear / Sercomm devices
9 * */
10 static const char *magic = "sErCoMm"; /* 7 */
11 /* 7-11: version control/download control ? */
12 unsigned char version[4] = {0x00, 0x01, 0x00, 0x00};
13 char *hwID = ""; /* 11-43 , ASCII/HEX */
14 char *hwVer = ""; /* 44-57 , ASCII/HEX */
15 char *swVer = ""; /* 58-62 , ASCII/HEX */
16 /* magic again. */
17
18 #define HEADER_SIZE 71
19
20 /* null bytes until 511 */
21 u_int32_t checksum = 0xFF; /* checksum */
22 /* 512 onwards -> ZIP containing rootfs with the same Header */
23
24
25 /* appended on rootfs for the Header. */
26 const int footer_size = 128;
27
28 struct file_info {
29 char *file_name; /* name of the file */
30 char *file_data; /* data of the file in memory */
31 u_int32_t file_size; /* length of the file */
32 };
33
34 u_int8_t getCheckSum(char *data, int len)
35 {
36
37 int32_t previous = 0;
38 u_int32_t new = 0;
39
40 for (u_int32_t i = 0; i < len; i++) {
41 new = (data[i] + previous) % 256;
42 previous = new | previous & -256;
43 }
44 return (u_int8_t) new;
45 }
46
47 void *bufferFile(struct file_info *finfo, int dontload)
48 {
49 int fs = 0;
50 FILE *f = NULL;
51
52 #ifdef DEBUG
53 printf("Opening file: %s\n", finfo->file_name);
54 #endif
55 f = fopen(finfo->file_name, "rb");
56 if (f == NULL) {
57 perror("Error");
58 exit(1);
59 }
60
61 fseek(f, 0L, SEEK_END);
62 fs = ftell(f);
63 rewind(f);
64
65 #ifdef DEBUG
66 printf("Filesize: %i .\n", fs);
67 #endif
68
69 finfo->file_size = fs;
70
71 if (dontload) {
72 return 0;
73 }
74
75 char *data = malloc(fs);
76 finfo->file_data = data;
77
78 int read = fread(data, fs, 1, f);
79
80 if (read != 1) {
81 printf("Error reading file %s.", finfo->file_name);
82 exit(1);
83 }
84
85 #ifdef DEBUG
86 printf("File: read successfully %i bytes.\n", read*fs);
87 #endif
88 fclose(f);
89 }
90
91 void *writeFile(struct file_info *finfo)
92 {
93
94 #ifdef DEBUG
95 printf("Writing file: %s.\n", finfo->file_name);
96 #endif
97
98 FILE *fout = fopen(finfo->file_name, "w");
99
100 if (!fwrite(finfo->file_data, finfo->file_size, 1, fout)) {
101 printf("Wanted to write, but something went wrong.\n");
102 fclose(fout);
103 exit(1);
104 }
105 fclose(fout);
106 }
107
108 void *rmFile(struct file_info *finfo)
109 {
110 remove(finfo->file_name);
111 free(finfo->file_data);
112 finfo->file_size = 0;
113 }
114
115 void *usage(char *argv[])
116 {
117 printf("Usage: %s <sysupgradefile> <kernel_offset> <HWID> <HWVER> <SWID>\n"
118 "All are positional arguments ... \n"
119 " sysupgradefile: File with the kernel uimage at 0\n"
120 " kernel_offset: Offset in Hex where the kernel is located\n"
121 " HWID: Hardware ID, ASCII\n"
122 " HWVER: Hardware Version, ASCII\n"
123 " SWID: Software Version, Hex\n"
124 " \n"
125 " ", argv[0]);
126 }
127
128 int main(int argc, char *argv[])
129 {
130 printf("Building fw image for sercomm devices.\n");
131
132 if (argc == 2) {
133 struct file_info myfile = {argv[1], 0, 0};
134 bufferFile(&myfile, 0);
135 char chksum = getCheckSum(myfile.file_data, myfile.file_size);
136 printf("Checksum for File: %X.\n", chksum);
137 return;
138 }
139
140 if (argc != 6) {
141 usage(argv);
142 return 1;
143 }
144
145 /* Args */
146
147 struct file_info sysupgrade = {argv[1], 0, 0};
148 bufferFile(&sysupgrade, 0);
149
150 int kernel_offset = 0x90000; /* offset for the kernel inside the rootfs, default val */
151 sscanf(argv[2], "%X", &kernel_offset);
152 #ifdef DEBUG
153 printf("Kernel_offset: at %X/%i bytes.\n", kernel_offset, kernel_offset);
154 #endif
155 char *hwID = argv[3];
156 char *hwVer = argv[4];
157 u_int32_t swVer = 0;
158 sscanf(argv[5],"%4X",&swVer);
159 swVer = bswap_32(swVer);
160
161 char *rootfsname = malloc(2*strlen(sysupgrade.file_name) + 8);
162 sprintf(rootfsname, "%s.rootfs", sysupgrade.file_name);
163
164 char *zipfsname = malloc(2*strlen(rootfsname) + 5);
165 sprintf(zipfsname, "%s.zip", rootfsname);
166 /* / Args */
167
168 #ifdef DEBUG
169 printf("Building header: %s %s %2X %s.\n", hwID , hwVer, swVer, magic);
170 #endif
171 /* Construct the firmware header/magic */
172 struct file_info header = {0, 0, 0};
173 header.file_size = HEADER_SIZE;
174 header.file_data = malloc(HEADER_SIZE);
175 bzero(header.file_data, header.file_size);
176
177 char *tg = header.file_data;
178 strcpy(tg, magic);
179 memcpy(tg+7, version, 4*sizeof(char));
180 strcpy(tg+11, hwID);
181 strcpy(tg+45, hwVer);
182 memcpy(tg+55, &swVer,sizeof(u_int32_t));
183 strcpy(tg+63, magic);
184
185 #ifdef DEBUG
186 printf("Header done, now creating rootfs.");
187 #endif
188 /* Construct a rootfs */
189 struct file_info rootfs = {0, 0, 0};
190 rootfs.file_size = sysupgrade.file_size + kernel_offset + footer_size;
191 rootfs.file_data = malloc(rootfs.file_size);
192 bzero(rootfs.file_data, rootfs.file_size);
193 rootfs.file_name = rootfsname;
194
195 /* copy Owrt image to Kernel location */
196 memcpy(rootfs.file_data+kernel_offset, sysupgrade.file_data, sysupgrade.file_size);
197
198 /* 22 added to get away from sysup image, no other reason.
199 * updater searches for magic anyway */
200 tg = rootfs.file_data + kernel_offset + sysupgrade.file_size+22;
201
202 memcpy(tg, header.file_data, header.file_size);
203 writeFile(&rootfs);
204
205 #ifdef DEBUG
206 printf("Preparing to zip.\n");
207 #endif
208 /* now that we got the rootfs, repeat the whole thing again(sorta):
209 * 1. zip the rootfs */
210 char *zipper = malloc(5 + 2*strlen(rootfs.file_name) + 4);
211 sprintf(zipper, "%s %s %s", "zip ", zipfsname, rootfs.file_name);
212 int ret = system(zipper);
213
214 /* clear rootfs file */
215 rmFile(&rootfs);
216
217 /* and load zipped fs */
218 struct file_info zippedfs = {zipfsname, 0, 0};
219 bufferFile(&zippedfs, 0);
220
221 #ifdef DEBUG
222 printf("Creating Image.\n");
223 #endif
224
225 /* 2. create new file 512+rootfs size */
226 struct file_info image = {argv[1], 0, 0};
227 image.file_data = malloc(zippedfs.file_size + 512);
228 image.file_size = zippedfs.file_size + 512;
229
230 /* 3. copy zipfile at loc 512 */
231 memcpy(image.file_data+512, zippedfs.file_data, zippedfs.file_size);
232 rmFile(&zippedfs);
233
234 /* 4. add header to file */
235 memcpy(image.file_data, header.file_data, header.file_size);
236
237 /* 5. do a checksum run, and compute checksum */
238 char chksum = getCheckSum(image.file_data, image.file_size);
239 #ifdef DEBUG
240 printf("Checksum for Image: %X.\n", chksum);
241 #endif
242
243 /* 6. write the checksum invert into byte 511 to bring it to 0 */
244 chksum = (chksum ^ 0xFF) + 1;
245 memcpy(image.file_data+511, &chksum, 1);
246
247 chksum = getCheckSum(image.file_data, image.file_size);
248 #ifdef DEBUG
249 printf("Checksum for after fix: %X.\n", chksum);
250 #endif
251 /* 7. pray that the updater will accept the file */
252 writeFile(&image);
253 return 0;
254 }