• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/firmware-utils/src/edimax_fw_header.c

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Copyright (C) 2014 Gabor Juhos <juhosg@openwrt.org>
  4  */
  5 
  6 #include <stdio.h>
  7 #include <stdlib.h>
  8 #include <stdint.h>
  9 #include <string.h>
 10 #include <unistd.h>     /* for unlink() */
 11 #include <libgen.h>
 12 #include <getopt.h>     /* for getopt() */
 13 #include <stdarg.h>
 14 #include <errno.h>
 15 #include <sys/stat.h>
 16 
 17 #include <arpa/inet.h>
 18 #include <netinet/in.h>
 19 
 20 #define MAX_MAGIC_LEN           16
 21 #define MAX_MODEL_LEN           32
 22 #define MAX_VERSION_LEN         14
 23 #define MAX_MTD_NAME_LEN        16
 24 
 25 #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
 26 
 27 struct edimax_header {
 28         char            magic[MAX_MAGIC_LEN];
 29         char            model[MAX_MODEL_LEN];
 30         unsigned char   force;
 31         unsigned char   header_csum;
 32         unsigned char   data_csum;
 33         uint32_t        data_size;
 34         uint32_t        start_addr;
 35         uint32_t        end_addr;
 36         char            fw_version[MAX_VERSION_LEN];
 37         unsigned char   type;
 38         char            mtd_name[MAX_MTD_NAME_LEN];
 39 } __attribute__ ((packed));
 40 
 41 /*
 42  * Globals
 43  */
 44 static char *ofname;
 45 static char *ifname;
 46 static char *progname;
 47 
 48 static char *model;
 49 static char *magic = "eDiMaX";
 50 static char *fw_version = "";
 51 static char *mtd_name;
 52 static int force;
 53 static uint32_t start_addr;
 54 static uint32_t end_addr;
 55 static uint8_t image_type;
 56 static int data_size;
 57 
 58 /*
 59  * Message macros
 60  */
 61 #define ERR(fmt, ...) do { \
 62         fflush(0); \
 63         fprintf(stderr, "[%s] *** error: " fmt "\n", \
 64                         progname, ## __VA_ARGS__ ); \
 65 } while (0)
 66 
 67 #define ERRS(fmt, ...) do { \
 68         int save = errno; \
 69         fflush(0); \
 70         fprintf(stderr, "[%s] *** error: " fmt " (%s)\n", \
 71                         progname, ## __VA_ARGS__, strerror(save)); \
 72 } while (0)
 73 
 74 #define DBG(fmt, ...) do { \
 75         fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
 76 } while (0)
 77 
 78 static void usage(int status)
 79 {
 80         FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
 81 
 82         fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
 83         fprintf(stream,
 84 "\n"
 85 "Options:\n"
 86 "  -e <addr>       set end addr to <addr>\n"
 87 "  -f              set force flag\n"
 88 "  -h              show this screen\n"
 89 "  -i <file>       read input data from the file <file>\n"
 90 "  -o <file>       write output to the file <file>\n"
 91 "  -m <model>      set model to <model>\n"
 92 "  -M <magic>      set image magic to <magic>\n"
 93 "  -n <name>       set MTD device name to <name>\n"
 94 "  -s <addr>       set start address to <addr>\n"
 95 "  -t <type>       set image type to <type>\n"
 96 "  -v <version>    set firmware version to <version>\n"
 97         );
 98 
 99         exit(status);
100 }
101 
102 int
103 str2u32(char *arg, uint32_t *val)
104 {
105         char *err = NULL;
106         uint32_t t;
107 
108         errno=0;
109         t = strtoul(arg, &err, 0);
110         if (errno || (err==arg) || ((err != NULL) && *err)) {
111                 return -1;
112         }
113 
114         *val = t;
115         return 0;
116 }
117 
118 int
119 str2u8(char *arg, uint8_t *val)
120 {
121         char *err = NULL;
122         uint32_t t;
123 
124         errno=0;
125         t = strtoul(arg, &err, 0);
126         if (errno || (err==arg) || ((err != NULL) && *err) || (t >= 0x100)) {
127                 return -1;
128         }
129 
130         *val = t & 0xFF;
131         return 0;
132 }
133 
134 static int get_file_size(char *name)
135 {
136         struct stat st;
137         int res;
138 
139         res = stat(name, &st);
140         if (res){
141                 ERRS("stat failed on %s", name);
142                 return -1;
143         }
144 
145         return st.st_size;
146 }
147 
148 static int read_to_buf(char *name, char *buf, int buflen)
149 {
150         FILE *f;
151         int ret = EXIT_FAILURE;
152 
153         f = fopen(name, "r");
154         if (f == NULL) {
155                 ERRS("could not open \"%s\" for reading", name);
156                 goto out;
157         }
158 
159         errno = 0;
160         fread(buf, buflen, 1, f);
161         if (errno != 0) {
162                 ERRS("unable to read from file \"%s\"", name);
163                 goto out_close;
164         }
165 
166         ret = EXIT_SUCCESS;
167 
168 out_close:
169         fclose(f);
170 out:
171         return ret;
172 }
173 
174 static int check_options(void)
175 {
176 #define CHKSTR(_name, _msg)                             \
177         do {                                            \
178                 if (_name == NULL) {                    \
179                         ERR("no %s specified", _msg);   \
180                         return -1;                      \
181                 }                                       \
182         } while (0)
183 
184 #define CHKSTRLEN(_name, _msg)                                          \
185         do {                                                            \
186                 int field_len;                                          \
187                 CHKSTR(_name, _msg);                                    \
188                 field_len = FIELD_SIZEOF(struct edimax_header, _name) - 1; \
189                 if (strlen(_name) > field_len) {                        \
190                         ERR("'%s' is too long, max %s length is %d",    \
191                             _name, _msg, field_len);                    \
192                         return -1;                                      \
193                 }                                                       \
194         } while (0)
195 
196         CHKSTR(ofname, "output file");
197         CHKSTR(ifname, "input file");
198 
199         CHKSTRLEN(magic, "magic");
200         CHKSTRLEN(model, "model");
201         CHKSTRLEN(mtd_name, "MTD device name");
202         CHKSTRLEN(fw_version, "firware version");
203 
204         data_size = get_file_size(ifname);
205         if (data_size < 0)
206                 return -1;
207 
208         return 0;
209 }
210 
211 static int write_fw(char *data, int len)
212 {
213         FILE *f;
214         int ret = EXIT_FAILURE;
215 
216         f = fopen(ofname, "w");
217         if (f == NULL) {
218                 ERRS("could not open \"%s\" for writing", ofname);
219                 goto out;
220         }
221 
222         errno = 0;
223         fwrite(data, len, 1, f);
224         if (errno) {
225                 ERRS("unable to write output file");
226                 goto out_flush;
227         }
228 
229         DBG("firmware file \"%s\" completed", ofname);
230 
231         ret = EXIT_SUCCESS;
232 
233 out_flush:
234         fflush(f);
235         fclose(f);
236         if (ret != EXIT_SUCCESS) {
237                 unlink(ofname);
238         }
239 out:
240         return ret;
241 }
242 
243 static unsigned char checksum(unsigned char *p, unsigned len)
244 {
245         unsigned char csum = 0;
246 
247         while (len--)
248                 csum += *p++;
249 
250         csum ^= 0xb9;
251 
252         return csum;
253 }
254 
255 static int build_fw(void)
256 {
257         int buflen;
258         char *buf;
259         char *data;
260         struct edimax_header *hdr;
261         int ret = EXIT_FAILURE;
262 
263         buflen = sizeof(struct edimax_header) + data_size;
264 
265         buf = malloc(buflen);
266         if (!buf) {
267                 ERR("no memory for buffer\n");
268                 goto out;
269         }
270 
271         data = buf + sizeof(struct edimax_header);
272 
273         /* read input file */
274         ret = read_to_buf(ifname, data, data_size);
275         if (ret)
276                 goto out_free_buf;
277 
278         /* fill firmware header */
279         hdr = (struct edimax_header *)buf;
280         memset(hdr, 0, sizeof(struct edimax_header));
281 
282         strncpy(hdr->model, model, sizeof(hdr->model));
283         strncpy(hdr->magic, magic, sizeof(hdr->magic));
284         strncpy(hdr->fw_version, fw_version, sizeof(hdr->fw_version));
285         strncpy(hdr->mtd_name, mtd_name, sizeof(hdr->mtd_name));
286 
287         hdr->force = force;
288         hdr->start_addr = htonl(start_addr);
289         hdr->end_addr = htonl(end_addr);
290         hdr->data_size = htonl(data_size);
291         hdr->type = image_type;
292 
293         hdr->data_csum = checksum((unsigned char *)data, data_size);
294         hdr->header_csum = checksum((unsigned char *)hdr,
295                                     sizeof(struct edimax_header));
296 
297         ret = write_fw(buf, buflen);
298         if (ret)
299                 goto out_free_buf;
300 
301         ret = EXIT_SUCCESS;
302 
303 out_free_buf:
304         free(buf);
305 out:
306         return ret;
307 }
308 
309 int main(int argc, char *argv[])
310 {
311         int ret = EXIT_FAILURE;
312 
313         progname = basename(argv[0]);
314 
315         while (1) {
316                 int c;
317 
318                 c = getopt(argc, argv, "e:fhi:o:m:M:n:s:t:v:");
319                 if (c == -1)
320                         break;
321 
322                 switch (c) {
323                 case 'e':
324                         if (str2u32(optarg, &end_addr)) {
325                                 ERR("%s is invalid '%s'",
326                                     "end address", optarg);
327                                 goto out;
328                         }
329                         break;
330                 case 'f':
331                         force = 1;
332                         break;
333                 case 'i':
334                         ifname = optarg;
335                         break;
336                 case 'h':
337                         usage(EXIT_SUCCESS);
338                         break;
339                 case 'o':
340                         ofname = optarg;
341                         break;
342                 case 'm':
343                         model = optarg;
344                         break;
345                 case 'M':
346                         magic = optarg;
347                         break;
348                 case 'n':
349                         mtd_name = optarg;
350                         break;
351                 case 's':
352                         if (str2u32(optarg, &start_addr)) {
353                                 ERR("%s is invalid '%s'",
354                                     "start address", optarg);
355                                 goto out;
356                         }
357                         break;
358                 case 't':
359                         if (str2u8(optarg, &image_type)) {
360                                 ERR("%s is invalid '%s'",
361                                     "image type", optarg);
362                                 goto out;
363                         }
364                         break;
365                 case 'v':
366                         fw_version = optarg;
367                         break;
368                 default:
369                         usage(EXIT_FAILURE);
370                         break;
371                 }
372         }
373 
374         ret = check_options();
375         if (ret)
376                 goto out;
377 
378         ret = build_fw();
379 
380 out:
381         return ret;
382 }
383 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt