Annotation of elwix/tools/mktplinkfw/mktplinkfw.c, revision 1.1.2.2

1.1.2.1   misho       1: /*
                      2:  * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org>
                      3:  *
                      4:  * This tool was based on:
                      5:  *   TP-Link WR941 V2 firmware checksum fixing tool.
                      6:  *   Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn>
                      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 <stdio.h>
                     15: #include <stdlib.h>
                     16: #include <stdint.h>
                     17: #include <string.h>
                     18: #include <unistd.h>     /* for unlink() */
                     19: #include <libgen.h>
                     20: #include <getopt.h>     /* for getopt() */
                     21: #include <stdarg.h>
                     22: #include <errno.h>
                     23: #include <sys/stat.h>
                     24: #include <arpa/inet.h>
                     25: 
                     26: #include <openssl/md5.h>
                     27: 
                     28: #define        HOST_TO_BE32(x)         htonl(x)
                     29: #define        BE32_TO_HOST(x)         ntohl(x)
                     30: 
                     31: /*
                     32:  * This is linux specific; it completely fails to get the endianness
                     33:  * correct when building on FreeBSD.
                     34:  */
                     35: #if 0
                     36: #if (__BYTE_ORDER == __BIG_ENDIAN)
                     37: #  define HOST_TO_BE32(x)      (x)
                     38: #  define BE32_TO_HOST(x)      (x)
                     39: #else
                     40: #  define HOST_TO_BE32(x)      bswap_32(x)
                     41: #  define BE32_TO_HOST(x)      bswap_32(x)
                     42: #endif
                     43: #endif
                     44: 
                     45: #define HEADER_VERSION_V1      0x01000000
1.1.2.2 ! misho      46: #define HWID_TL_MR3020_V1      0x30200001
1.1.2.1   misho      47: #define HWID_TL_MR3220_V1      0x32200001
                     48: #define HWID_TL_MR3420_V1      0x34200001
                     49: #define HWID_TL_WA901ND_V1     0x09010001
                     50: #define HWID_TL_WA901ND_V2     0x09010002
                     51: #define HWID_TL_WR703N_V1      0x07030101
                     52: #define HWID_TL_WR741ND_V1     0x07410001
                     53: #define HWID_TL_WR740N_V1      0x07400001
                     54: #define HWID_TL_WR740N_V3      0x07400300
                     55: #define HWID_TL_WR743ND_V1     0x07430001
                     56: #define HWID_TL_WR841N_V1_5    0x08410002
                     57: #define HWID_TL_WR841ND_V3     0x08410003
                     58: #define HWID_TL_WR841ND_V5     0x08410005
                     59: #define HWID_TL_WR841ND_V7     0x08410007
                     60: #define HWID_TL_WR941ND_V2     0x09410002
                     61: #define HWID_TL_WR941ND_V4     0x09410004
                     62: #define HWID_TL_WR1043ND_V1    0x10430001
                     63: 
                     64: #define MD5SUM_LEN     16
                     65: 
                     66: struct file_info {
                     67:        char            *file_name;     /* name of the file */
                     68:        uint32_t        file_size;      /* length of the file */
                     69: };
                     70: 
                     71: struct fw_header {
                     72:        uint32_t        version;        /* header version */
                     73:        char            vendor_name[24];
                     74:        char            fw_version[36];
                     75:        uint32_t        hw_id;          /* hardware id */
                     76:        uint32_t        hw_rev;         /* hardware revision */
                     77:        uint32_t        unk1;
                     78:        uint8_t         md5sum1[MD5SUM_LEN];
                     79:        uint32_t        unk2;
                     80:        uint8_t         md5sum2[MD5SUM_LEN];
                     81:        uint32_t        unk3;
                     82:        uint32_t        kernel_la;      /* kernel load address */
                     83:        uint32_t        kernel_ep;      /* kernel entry point */
                     84:        uint32_t        fw_length;      /* total length of the firmware */
                     85:        uint32_t        kernel_ofs;     /* kernel data offset */
                     86:        uint32_t        kernel_len;     /* kernel data length */
                     87:        uint32_t        rootfs_ofs;     /* rootfs data offset */
                     88:        uint32_t        rootfs_len;     /* rootfs data length */
                     89:        uint32_t        boot_ofs;       /* bootloader data offset */
                     90:        uint32_t        boot_len;       /* bootloader data length */
                     91:        uint8_t         pad[360];
                     92: } __attribute__ ((packed));
                     93: 
                     94: struct board_info {
                     95:        char            *id;
                     96:        uint32_t        hw_id;
                     97:        uint32_t        hw_rev;
                     98:        uint32_t        fw_max_len;
                     99:        uint32_t        kernel_la;
                    100:        uint32_t        kernel_ep;
                    101:        uint32_t        rootfs_ofs;
                    102: };
                    103: 
                    104: /*
                    105:  * Globals
                    106:  */
                    107: static char *ofname;
                    108: static char *progname;
                    109: static char *vendor = "TP-LINK Technologies";
                    110: static char *version = "ver. 1.0";
                    111: 
                    112: static char *board_id;
                    113: static struct board_info *board;
                    114: static struct file_info kernel_info;
                    115: static uint32_t kernel_la = 0;
                    116: static uint32_t kernel_ep = 0;
                    117: static struct file_info rootfs_info;
                    118: static uint32_t rootfs_ofs = 0;
                    119: static struct file_info boot_info;
                    120: static int combined;
                    121: static int strip_padding;
                    122: 
                    123: static struct file_info inspect_info;
                    124: static int extract = 0;
                    125: 
                    126: char md5salt_normal[MD5SUM_LEN] = {
                    127:        0xdc, 0xd7, 0x3a, 0xa5, 0xc3, 0x95, 0x98, 0xfb,
                    128:        0xdd, 0xf9, 0xe7, 0xf4, 0x0e, 0xae, 0x47, 0x38,
                    129: };
                    130: 
                    131: char md5salt_boot[MD5SUM_LEN] = {
                    132:        0x8c, 0xef, 0x33, 0x5b, 0xd5, 0xc5, 0xce, 0xfa,
                    133:        0xa7, 0x9c, 0x28, 0xda, 0xb2, 0xe9, 0x0f, 0x42,
                    134: };
                    135: 
                    136: static struct board_info boards[] = {
                    137:        {
1.1.2.2 ! misho     138:                .id             = "TL-MR3020v1",
        !           139:                .hw_id          = HWID_TL_MR3020_V1,
        !           140:                .hw_rev         = 1,
        !           141:                /*
        !           142:                 * Actual size of firmware is 3.8MB but for now, allow larger
        !           143:                 * sizes until we work out a plan for this unit
        !           144:                 * .fw_max_len  = 0x3c0000,
        !           145:                 */
        !           146:                .fw_max_len     = 0x640000,
        !           147:                .kernel_la      = 0x80060000,
        !           148:                .kernel_ep      = 0x80060000,
        !           149:                .rootfs_ofs     = 0x100000,
        !           150:        }, {
1.1.2.1   misho     151:                .id             = "TL-MR3220v1",
                    152:                .hw_id          = HWID_TL_MR3220_V1,
                    153:                .hw_rev         = 1,
                    154:                .fw_max_len     = 0x3c0000,
                    155:                .kernel_la      = 0x80060000,
                    156:                .kernel_ep      = 0x80060000,
                    157:                .rootfs_ofs     = 0x140000,
                    158:        }, {
                    159:                .id             = "TL-MR3420v1",
                    160:                .hw_id          = HWID_TL_MR3420_V1,
                    161:                .hw_rev         = 1,
                    162:                .fw_max_len     = 0x3c0000,
                    163:                .kernel_la      = 0x80060000,
                    164:                .kernel_ep      = 0x80060000,
                    165:                .rootfs_ofs     = 0x140000,
                    166:        }, {
                    167:                .id             = "TL-WA901NDv1",
                    168:                .hw_id          = HWID_TL_WA901ND_V1,
                    169:                .hw_rev         = 1,
                    170:                .fw_max_len     = 0x3c0000,
                    171:                .kernel_la      = 0x80060000,
                    172:                .kernel_ep      = 0x80060000,
                    173:                .rootfs_ofs     = 0x140000,
                    174:        }, {
                    175:                .id             = "TL-WA901NDv2",
                    176:                .hw_id          = HWID_TL_WA901ND_V2,
                    177:                .hw_rev         = 1,
                    178:                .fw_max_len     = 0x3c0000,
                    179:                .kernel_la      = 0x80060000,
                    180:                .kernel_ep      = 0x80060000,
                    181:                .rootfs_ofs     = 0x140000,
                    182:        }, {
                    183:                .id             = "TL-WR741NDv1",
                    184:                .hw_id          = HWID_TL_WR741ND_V1,
                    185:                .hw_rev         = 1,
                    186:                .fw_max_len     = 0x3c0000,
                    187:                .kernel_la      = 0x80060000,
                    188:                .kernel_ep      = 0x80060000,
                    189:                .rootfs_ofs     = 0x140000,
                    190:        }, {
                    191:                .id             = "TL-WR740Nv1",
                    192:                .hw_id          = HWID_TL_WR740N_V1,
                    193:                .hw_rev         = 1,
                    194:                .fw_max_len     = 0x3c0000,
                    195:                .kernel_la      = 0x80060000,
                    196:                .kernel_ep      = 0x80060000,
                    197:                .rootfs_ofs     = 0x140000,
                    198:        }, {
                    199:                .id             = "TL-WR740Nv3",
                    200:                .hw_id          = HWID_TL_WR740N_V3,
                    201:                .hw_rev         = 1,
                    202:                .fw_max_len     = 0x3c0000,
                    203:                .kernel_la      = 0x80060000,
                    204:                .kernel_ep      = 0x80060000,
                    205:                .rootfs_ofs     = 0x140000,
                    206:        }, {
                    207:                .id             = "TL-WR743NDv1",
                    208:                .hw_id          = HWID_TL_WR743ND_V1,
                    209:                .hw_rev         = 1,
                    210:                .fw_max_len     = 0x3c0000,
                    211:                .kernel_la      = 0x80060000,
                    212:                .kernel_ep      = 0x80060000,
                    213:                .rootfs_ofs     = 0x140000,
                    214:        }, {
                    215:                .id             = "TL-WR841Nv1.5",
                    216:                .hw_id          = HWID_TL_WR841N_V1_5,
                    217:                .hw_rev         = 2,
                    218:                .fw_max_len     = 0x3c0000,
                    219:                .kernel_la      = 0x80060000,
                    220:                .kernel_ep      = 0x80060000,
                    221:                .rootfs_ofs     = 0x140000,
                    222:        }, {
                    223:                .id             = "TL-WR841NDv3",
                    224:                .hw_id          = HWID_TL_WR841ND_V3,
                    225:                .hw_rev         = 3,
                    226:                .fw_max_len     = 0x3c0000,
                    227:                .kernel_la      = 0x80060000,
                    228:                .kernel_ep      = 0x80060000,
                    229:                .rootfs_ofs     = 0x140000,
                    230:        }, {
                    231:                .id             = "TL-WR841NDv5",
                    232:                .hw_id          = HWID_TL_WR841ND_V5,
                    233:                .hw_rev         = 1,
                    234:                .fw_max_len     = 0x3c0000,
                    235:                .kernel_la      = 0x80060000,
                    236:                .kernel_ep      = 0x80060000,
                    237:                .rootfs_ofs     = 0x140000,
                    238:        }, {
                    239:                .id             = "TL-WR841NDv7",
                    240:                .hw_id          = HWID_TL_WR841ND_V7,
                    241:                .hw_rev         = 1,
                    242:                .fw_max_len     = 0x3c0000,
                    243:                .kernel_la      = 0x80060000,
                    244:                .kernel_ep      = 0x80060000,
                    245:                .rootfs_ofs     = 0x140000,
                    246:        }, {
                    247:                .id             = "TL-WR941NDv2",
                    248:                .hw_id          = HWID_TL_WR941ND_V2,
                    249:                .hw_rev         = 2,
                    250:                .fw_max_len     = 0x3c0000,
                    251:                .kernel_la      = 0x80060000,
                    252:                .kernel_ep      = 0x80060000,
                    253:                .rootfs_ofs     = 0x140000,
                    254:        }, {
                    255:                .id             = "TL-WR941NDv4",
                    256:                .hw_id          = HWID_TL_WR941ND_V4,
                    257:                .hw_rev         = 1,
                    258:                .fw_max_len     = 0x3c0000,
                    259:                .kernel_la      = 0x80060000,
                    260:                .kernel_ep      = 0x80060000,
                    261:                .rootfs_ofs     = 0x140000,
                    262:        }, {
                    263:                .id             = "TL-WR1043NDv1",
                    264:                .hw_id          = HWID_TL_WR1043ND_V1,
                    265:                .hw_rev         = 1,
                    266:                .fw_max_len     = 0x7c0000,
                    267:                .kernel_la      = 0x80060000,
                    268:                .kernel_ep      = 0x80060000,
                    269:                .rootfs_ofs     = 0x140000,
                    270:        }, {
                    271:                .id             = "TL-WR703Nv1",
                    272:                .hw_id          = HWID_TL_WR703N_V1,
                    273:                .hw_rev         = 1,
                    274:                .fw_max_len     = 0x3c0000,
                    275:                .kernel_la      = 0x80060000,
                    276:                .kernel_ep      = 0x80060000,
                    277:                .rootfs_ofs     = 0x100000,
                    278:        }, {
                    279:                /* terminating entry */
                    280:        }
                    281: };
                    282: 
                    283: /*
                    284:  * Message macros
                    285:  */
                    286: #define ERR(fmt, ...) do { \
                    287:        fflush(0); \
                    288:        fprintf(stderr, "[%s] *** error: " fmt "\n", \
                    289:                        progname, ## __VA_ARGS__ ); \
                    290: } while (0)
                    291: 
                    292: #define ERRS(fmt, ...) do { \
                    293:        int save = errno; \
                    294:        fflush(0); \
1.1.2.2 ! misho     295:        fprintf(stderr, "[%s] *** error: " fmt " error:%s\n", \
1.1.2.1   misho     296:                        progname, ## __VA_ARGS__, strerror(save)); \
                    297: } while (0)
                    298: 
                    299: #define DBG(fmt, ...) do { \
                    300:        fprintf(stderr, "[%s] " fmt "\n", progname, ## __VA_ARGS__ ); \
                    301: } while (0)
                    302: 
                    303: static struct board_info *find_board(char *id)
                    304: {
                    305:        struct board_info *ret;
                    306:        struct board_info *board;
                    307: 
                    308:        ret = NULL;
                    309:        for (board = boards; board->id != NULL; board++){
                    310:                if (strcasecmp(id, board->id) == 0) {
                    311:                        ret = board;
                    312:                        break;
                    313:                }
                    314:        };
                    315: 
                    316:        return ret;
                    317: }
                    318: 
                    319: static struct board_info *find_board_by_hwid(uint32_t hw_id)
                    320: {
                    321:        struct board_info *board;
                    322: 
                    323:        for (board = boards; board->id != NULL; board++) {
                    324:                if (hw_id == board->hw_id)
                    325:                        return board;
                    326:        };
                    327: 
                    328:        return NULL;
                    329: }
                    330: 
                    331: 
                    332: static void usage(int status)
                    333: {
                    334:        FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout;
                    335:        struct board_info *board;
                    336: 
                    337:        fprintf(stream, "Usage: %s [OPTIONS...]\n", progname);
                    338:        fprintf(stream,
                    339: "\n"
                    340: "Options:\n"
                    341: "  -B <board>      create image for the board specified with <board>\n"
                    342: "  -c              use combined kernel image\n"
                    343: "  -E <ep>         overwrite kernel entry point with <ep> (hexval prefixed with 0x)\n"
                    344: "  -L <la>         overwrite kernel load address with <la> (hexval prefixed with 0x)\n"
                    345: "  -k <file>       read kernel image from the file <file>\n"
                    346: "  -r <file>       read rootfs image from the file <file>\n"
                    347: "  -R <offset>     overwrite rootfs offset with <offset> (hexval prefixed with 0x)\n"
                    348: "  -o <file>       write output to the file <file>\n"
                    349: "  -s              strip padding from the end of the image\n"
                    350: "  -N <vendor>     set image vendor to <vendor>\n"
                    351: "  -V <version>    set image version to <version>\n"
                    352: "  -i <file>       inspect given firmware file <file>\n"
                    353: "  -x              extract kernel and rootfs while inspecting (requires -i)\n"
                    354: "  -h              show this screen\n"
                    355:        );
                    356: 
                    357:        exit(status);
                    358: }
                    359: 
1.1.2.2 ! misho     360: static void get_md5(char *data, int size, uint8_t *md5)
1.1.2.1   misho     361: {
                    362:        MD5_CTX ctx;
                    363: 
                    364:        MD5_Init(&ctx);
                    365:        MD5_Update(&ctx, data, size);
1.1.2.2 ! misho     366:        MD5_Final(md5, &ctx);
1.1.2.1   misho     367: }
                    368: 
                    369: static int get_file_stat(struct file_info *fdata)
                    370: {
                    371:        struct stat st;
                    372:        int res;
                    373: 
                    374:        if (fdata->file_name == NULL)
                    375:                return 0;
                    376: 
                    377:        res = stat(fdata->file_name, &st);
                    378:        if (res){
                    379:                ERRS("stat failed on %s", fdata->file_name);
                    380:                return res;
                    381:        }
                    382: 
                    383:        fdata->file_size = st.st_size;
                    384:        return 0;
                    385: }
                    386: 
                    387: static int read_to_buf(struct file_info *fdata, char *buf)
                    388: {
                    389:        FILE *f;
                    390:        int ret = EXIT_FAILURE;
                    391: 
                    392:        f = fopen(fdata->file_name, "r");
                    393:        if (f == NULL) {
                    394:                ERRS("could not open \"%s\" for reading", fdata->file_name);
                    395:                goto out;
                    396:        }
                    397: 
                    398:        errno = 0;
                    399:        fread(buf, fdata->file_size, 1, f);
                    400:        if (errno != 0) {
                    401:                ERRS("unable to read from file \"%s\"", fdata->file_name);
                    402:                goto out_close;
                    403:        }
                    404: 
                    405:        ret = EXIT_SUCCESS;
                    406: 
                    407:  out_close:
                    408:        fclose(f);
                    409:  out:
                    410:        return ret;
                    411: }
                    412: 
                    413: static int check_options(void)
                    414: {
                    415:        int ret;
                    416: 
                    417:        if (inspect_info.file_name) {
                    418:                ret = get_file_stat(&inspect_info);
                    419:                if (ret)
                    420:                        return ret;
                    421: 
                    422:                return 0;
                    423:        } else if (extract) {
                    424:                ERR("no firmware for inspection specified");
                    425:                return -1;
                    426:        }
                    427: 
                    428:        if (board_id == NULL) {
                    429:                ERR("no board specified");
                    430:                return -1;
                    431:        }
                    432: 
                    433:        board = find_board(board_id);
                    434:        if (board == NULL) {
                    435:                ERR("unknown/unsupported board id \"%s\"", board_id);
                    436:                return -1;
                    437:        }
                    438:        if (!kernel_la)
                    439:                kernel_la = board->kernel_la;
                    440:        if (!kernel_ep)
                    441:                kernel_ep = board->kernel_ep;
                    442:        if (!rootfs_ofs)
                    443:                rootfs_ofs = board->rootfs_ofs;
                    444: 
                    445:        if (kernel_info.file_name == NULL) {
                    446:                ERR("no kernel image specified");
                    447:                return -1;
                    448:        }
                    449: 
                    450:        ret = get_file_stat(&kernel_info);
                    451:        if (ret)
                    452:                return ret;
                    453: 
                    454:        if (combined) {
                    455:                if (kernel_info.file_size >
                    456:                    board->fw_max_len - sizeof(struct fw_header)) {
1.1.2.2 ! misho     457:                        ERR("Combined kernel image is too big. Max[%lu] kernel img [%d]", 
        !           458:                            board->fw_max_len - sizeof(struct fw_header), kernel_info.file_size);
1.1.2.1   misho     459:                        return -1;
                    460:                }
                    461:        } else {
                    462:                if (kernel_info.file_size >
1.1.2.2 ! misho     463:                    (rootfs_ofs - sizeof(struct fw_header))) {
        !           464:                        ERR("kernel image is too big. Max[%lu] kernel img [%d]", 
        !           465:                            rootfs_ofs - sizeof(struct fw_header), kernel_info.file_size);
1.1.2.1   misho     466:                        return -1;
                    467:                }
                    468:                if (rootfs_info.file_name == NULL) {
                    469:                        ERR("no rootfs image specified");
                    470:                        return -1;
                    471:                }
                    472: 
                    473:                ret = get_file_stat(&rootfs_info);
                    474:                if (ret)
                    475:                        return ret;
                    476: 
                    477:                if (rootfs_info.file_size >
                    478:                     (board->fw_max_len - rootfs_ofs)) {
1.1.2.2 ! misho     479:                        ERR("rootfs image is too big. Max[%d] fs img [%d]",
        !           480:                            board->fw_max_len - rootfs_ofs, rootfs_info.file_size);
1.1.2.1   misho     481:                        return -1;
                    482:                }
                    483:        }
                    484: 
                    485:        if (ofname == NULL) {
                    486:                ERR("no output file specified");
                    487:                return -1;
                    488:        }
                    489: 
                    490:        return 0;
                    491: }
                    492: 
                    493: static void fill_header(char *buf, int len)
                    494: {
                    495:        struct fw_header *hdr = (struct fw_header *)buf;
                    496: 
                    497:        memset(hdr, 0, sizeof(struct fw_header));
                    498: 
                    499:        hdr->version = HOST_TO_BE32(HEADER_VERSION_V1);
                    500:        strncpy(hdr->vendor_name, vendor, sizeof(hdr->vendor_name));
                    501:        strncpy(hdr->fw_version, version, sizeof(hdr->fw_version));
                    502:        hdr->hw_id = HOST_TO_BE32(board->hw_id);
                    503:        hdr->hw_rev = HOST_TO_BE32(board->hw_rev);
                    504: 
                    505:        if (boot_info.file_size == 0)
                    506:                memcpy(hdr->md5sum1, md5salt_normal, sizeof(hdr->md5sum1));
                    507:        else
                    508:                memcpy(hdr->md5sum1, md5salt_boot, sizeof(hdr->md5sum1));
                    509: 
                    510:        hdr->kernel_la = HOST_TO_BE32(kernel_la);
                    511:        hdr->kernel_ep = HOST_TO_BE32(kernel_ep);
                    512:        hdr->fw_length = HOST_TO_BE32(board->fw_max_len);
                    513:        hdr->kernel_ofs = HOST_TO_BE32(sizeof(struct fw_header));
                    514:        hdr->kernel_len = HOST_TO_BE32(kernel_info.file_size);
                    515:        if (!combined) {
                    516:                hdr->rootfs_ofs = HOST_TO_BE32(rootfs_ofs);
                    517:                hdr->rootfs_len = HOST_TO_BE32(rootfs_info.file_size);
                    518:        }
                    519: 
1.1.2.2 ! misho     520:        get_md5(buf, len, hdr->md5sum1);
1.1.2.1   misho     521: }
                    522: 
                    523: static int write_fw(char *data, int len)
                    524: {
                    525:        FILE *f;
                    526:        int ret = EXIT_FAILURE;
                    527: 
                    528:        f = fopen(ofname, "w");
                    529:        if (f == NULL) {
                    530:                ERRS("could not open \"%s\" for writing", ofname);
                    531:                goto out;
                    532:        }
                    533: 
                    534:        errno = 0;
                    535:        fwrite(data, len, 1, f);
                    536:        if (errno) {
1.1.2.2 ! misho     537:                ERRS("unable to write output file \"%s\"", ofname);
1.1.2.1   misho     538:                goto out_flush;
                    539:        }
                    540: 
                    541:        DBG("firmware file \"%s\" completed", ofname);
                    542: 
                    543:        ret = EXIT_SUCCESS;
                    544: 
                    545:  out_flush:
                    546:        fflush(f);
                    547:        fclose(f);
                    548:        if (ret != EXIT_SUCCESS) {
                    549:                unlink(ofname);
                    550:        }
                    551:  out:
                    552:        return ret;
                    553: }
                    554: 
                    555: static int build_fw(void)
                    556: {
                    557:        int buflen;
                    558:        char *buf;
                    559:        char *p;
                    560:        int ret = EXIT_FAILURE;
                    561:        int writelen = 0;
                    562: 
                    563:        buflen = board->fw_max_len;
                    564: 
                    565:        buf = malloc(buflen);
                    566:        if (!buf) {
                    567:                ERR("no memory for buffer\n");
                    568:                goto out;
                    569:        }
                    570: 
                    571:        memset(buf, 0xff, buflen);
                    572:        p = buf + sizeof(struct fw_header);
                    573:        ret = read_to_buf(&kernel_info, p);
                    574:        if (ret)
                    575:                goto out_free_buf;
                    576: 
                    577:        writelen = kernel_info.file_size;
                    578: 
                    579:        if (!combined) {
                    580:                p = buf + rootfs_ofs;
                    581:                ret = read_to_buf(&rootfs_info, p);
                    582:                if (ret)
                    583:                        goto out_free_buf;
                    584: 
                    585:                writelen = rootfs_ofs + rootfs_info.file_size;
                    586:        }
                    587: 
                    588:        if (!strip_padding)
                    589:                writelen = buflen;
                    590: 
                    591:        fill_header(buf, writelen);
                    592:        ret = write_fw(buf, writelen);
                    593:        if (ret)
                    594:                goto out_free_buf;
                    595: 
                    596:        ret = EXIT_SUCCESS;
                    597: 
                    598:  out_free_buf:
                    599:        free(buf);
                    600:  out:
                    601:        return ret;
                    602: }
                    603: 
                    604: /* Helper functions to inspect_fw() representing different output formats */
                    605: static inline void inspect_fw_pstr(char *label, char *str)
                    606: {
                    607:        printf("%-23s: %s\n", label, str);
                    608: }
                    609: 
                    610: static inline void inspect_fw_phex(char *label, uint32_t val)
                    611: {
                    612:        printf("%-23s: 0x%08x\n", label, val);
                    613: }
                    614: 
                    615: static inline void inspect_fw_phexpost(char *label,
                    616:                                        uint32_t val, char *post)
                    617: {
                    618:        printf("%-23s: 0x%08x (%s)\n", label, val, post);
                    619: }
                    620: 
                    621: static inline void inspect_fw_phexdef(char *label,
                    622:                                       uint32_t val, uint32_t defval)
                    623: {
                    624:        printf("%-23s: 0x%08x                  ", label, val);
                    625: 
                    626:        if (val == defval)
                    627:                printf("(== OpenWrt default)\n");
                    628:        else
                    629:                printf("(OpenWrt default: 0x%08x)\n", defval);
                    630: }
                    631: 
                    632: static inline void inspect_fw_phexexp(char *label,
                    633:                                       uint32_t val, uint32_t expval)
                    634: {
                    635:        printf("%-23s: 0x%08x ", label, val);
                    636: 
                    637:        if (val == expval)
                    638:                printf("(ok)\n");
                    639:        else
                    640:                printf("(expected: 0x%08x)\n", expval);
                    641: }
                    642: 
                    643: static inline void inspect_fw_phexdec(char *label, uint32_t val)
                    644: {
                    645:        printf("%-23s: 0x%08x / %8u bytes\n", label, val, val);
                    646: }
                    647: 
                    648: static inline void inspect_fw_phexdecdef(char *label,
                    649:                                          uint32_t val, uint32_t defval)
                    650: {
                    651:        printf("%-23s: 0x%08x / %8u bytes ", label, val, val);
                    652: 
                    653:        if (val == defval)
                    654:                printf("(== OpenWrt default)\n");
                    655:        else
                    656:                printf("(OpenWrt default: 0x%08x)\n", defval);
                    657: }
                    658: 
                    659: static inline void inspect_fw_pmd5sum(char *label, uint8_t *val, char *text)
                    660: {
                    661:        int i;
                    662: 
                    663:        printf("%-23s:", label);
                    664:        for (i=0; i<MD5SUM_LEN; i++)
                    665:                printf(" %02x", val[i]);
                    666:        printf(" %s\n", text);
                    667: }
                    668: 
                    669: static int inspect_fw(void)
                    670: {
                    671:        char *buf;
                    672:        struct fw_header *hdr;
                    673:        uint8_t md5sum[MD5SUM_LEN];
                    674:        struct board_info *board;
                    675:        int ret = EXIT_FAILURE;
                    676: 
                    677:        buf = malloc(inspect_info.file_size);
                    678:        if (!buf) {
                    679:                ERR("no memory for buffer!\n");
                    680:                goto out;
                    681:        }
                    682: 
                    683:        ret = read_to_buf(&inspect_info, buf);
                    684:        if (ret)
                    685:                goto out_free_buf;
                    686:        hdr = (struct fw_header *)buf;
                    687: 
                    688:        inspect_fw_pstr("File name", inspect_info.file_name);
                    689:        inspect_fw_phexdec("File size", inspect_info.file_size);
                    690: 
                    691:        if (BE32_TO_HOST(hdr->version) != HEADER_VERSION_V1) {
                    692:                ERR("file does not seem to have V1 header!\n");
                    693:                goto out_free_buf;
                    694:        }
                    695: 
                    696:        inspect_fw_phexdec("Version 1 Header size", sizeof(struct fw_header));
                    697: 
                    698:        if (BE32_TO_HOST(hdr->unk1) != 0)
                    699:                inspect_fw_phexdec("Unknown value 1", hdr->unk1);
                    700: 
                    701:        memcpy(md5sum, hdr->md5sum1, sizeof(md5sum));
                    702:        if (BE32_TO_HOST(hdr->boot_len) == 0)
                    703:                memcpy(hdr->md5sum1, md5salt_normal, sizeof(md5sum));
                    704:        else
                    705:                memcpy(hdr->md5sum1, md5salt_boot, sizeof(md5sum));
1.1.2.2 ! misho     706:        get_md5(buf, inspect_info.file_size, hdr->md5sum1);
1.1.2.1   misho     707: 
                    708:        if (memcmp(md5sum, hdr->md5sum1, sizeof(md5sum))) {
                    709:                inspect_fw_pmd5sum("Header MD5Sum1", md5sum, "(*ERROR*)");
                    710:                inspect_fw_pmd5sum("          --> expected", hdr->md5sum1, "");
                    711:        } else {
                    712:                inspect_fw_pmd5sum("Header MD5Sum1", md5sum, "(ok)");
                    713:        }
                    714:        if (BE32_TO_HOST(hdr->unk2) != 0)
                    715:                inspect_fw_phexdec("Unknown value 2", hdr->unk2);
                    716:        inspect_fw_pmd5sum("Header MD5Sum2", hdr->md5sum2,
                    717:                           "(purpose yet unknown, unchecked here)");
                    718:        if (BE32_TO_HOST(hdr->unk3) != 0)
                    719:                inspect_fw_phexdec("Unknown value 3", hdr->unk3);
                    720: 
                    721:        printf("\n");
                    722: 
                    723:        inspect_fw_pstr("Vendor name", hdr->vendor_name);
                    724:        inspect_fw_pstr("Firmware version", hdr->fw_version);
                    725:        board = find_board_by_hwid(BE32_TO_HOST(hdr->hw_id));
                    726:        if (board) {
                    727:                inspect_fw_phexpost("Hardware ID",
                    728:                                    BE32_TO_HOST(hdr->hw_id), board->id);
                    729:                inspect_fw_phexexp("Hardware Revision",
                    730:                                   BE32_TO_HOST(hdr->hw_rev), board->hw_rev);
                    731:        } else {
                    732:                inspect_fw_phexpost("Hardware ID",
                    733:                                    BE32_TO_HOST(hdr->hw_id), "unknown");
                    734:                inspect_fw_phex("Hardware Revision",
                    735:                                BE32_TO_HOST(hdr->hw_rev));
                    736:        }
                    737: 
                    738:        printf("\n");
                    739: 
                    740:        inspect_fw_phexdec("Kernel data offset",
                    741:                           BE32_TO_HOST(hdr->kernel_ofs));
                    742:        inspect_fw_phexdec("Kernel data length",
                    743:                           BE32_TO_HOST(hdr->kernel_len));
                    744:        if (board) {
                    745:                inspect_fw_phexdef("Kernel load address",
                    746:                                   BE32_TO_HOST(hdr->kernel_la),
                    747:                                   board->kernel_la);
                    748:                inspect_fw_phexdef("Kernel entry point",
                    749:                                   BE32_TO_HOST(hdr->kernel_ep),
                    750:                                   board->kernel_ep);
                    751:                inspect_fw_phexdecdef("Rootfs data offset",
                    752:                                      BE32_TO_HOST(hdr->rootfs_ofs),
                    753:                                      board->rootfs_ofs);
                    754:        } else {
                    755:                inspect_fw_phex("Kernel load address",
                    756:                                BE32_TO_HOST(hdr->kernel_la));
                    757:                inspect_fw_phex("Kernel entry point",
                    758:                                BE32_TO_HOST(hdr->kernel_ep));
                    759:                inspect_fw_phexdec("Rootfs data offset",
                    760:                                   BE32_TO_HOST(hdr->rootfs_ofs));
                    761:        }
                    762:        inspect_fw_phexdec("Rootfs data length",
                    763:                           BE32_TO_HOST(hdr->rootfs_len));
                    764:        inspect_fw_phexdec("Boot loader data offset",
                    765:                           BE32_TO_HOST(hdr->boot_ofs));
                    766:        inspect_fw_phexdec("Boot loader data length",
                    767:                           BE32_TO_HOST(hdr->boot_len));
                    768:        inspect_fw_phexdec("Total firmware length",
                    769:                           BE32_TO_HOST(hdr->fw_length));
                    770: 
                    771:        if (extract) {
                    772:                FILE *fp;
                    773:                char *filename;
                    774: 
                    775:                printf("\n");
                    776: 
                    777:                filename = malloc(strlen(inspect_info.file_name) + 8);
                    778:                sprintf(filename, "%s-kernel", inspect_info.file_name);
                    779:                printf("Extracting kernel to \"%s\"...\n", filename);
                    780:                fp = fopen(filename, "w");
                    781:                if (fp) {
                    782:                        if (!fwrite(buf + BE32_TO_HOST(hdr->kernel_ofs),
                    783:                                    BE32_TO_HOST(hdr->kernel_len), 1, fp)) {
                    784:                                ERR("error in fwrite(): %s", strerror(errno));
                    785:                        }
                    786:                        fclose(fp);
                    787:                } else {
                    788:                        ERR("error in fopen(): %s", strerror(errno));
                    789:                }
                    790:                free(filename);
                    791: 
                    792:                filename = malloc(strlen(inspect_info.file_name) + 8);
                    793:                sprintf(filename, "%s-rootfs", inspect_info.file_name);
                    794:                printf("Extracting rootfs to \"%s\"...\n", filename);
                    795:                fp = fopen(filename, "w");
                    796:                if (fp) {
                    797:                        if (!fwrite(buf + BE32_TO_HOST(hdr->rootfs_ofs),
                    798:                                    BE32_TO_HOST(hdr->rootfs_len), 1, fp)) {
                    799:                                ERR("error in fwrite(): %s", strerror(errno));
                    800:                        }
                    801:                        fclose(fp);
                    802:                } else {
                    803:                        ERR("error in fopen(): %s", strerror(errno));
                    804:                }
                    805:                free(filename);
                    806:        }
                    807: 
                    808:  out_free_buf:
                    809:        free(buf);
                    810:  out:
                    811:        return ret;
                    812: }
                    813: 
                    814: int main(int argc, char *argv[])
                    815: {
                    816:        int ret = EXIT_FAILURE;
                    817:        int err;
                    818: 
                    819:        FILE *outfile;
                    820: 
                    821:        progname = basename(argv[0]);
                    822: 
                    823:        while ( 1 ) {
                    824:                int c;
                    825: 
                    826:                c = getopt(argc, argv, "B:E:L:V:N:ci:k:r:R:o:xhs");
                    827:                if (c == -1)
                    828:                        break;
                    829: 
                    830:                switch (c) {
                    831:                case 'B':
                    832:                        board_id = optarg;
                    833:                        break;
                    834:                case 'E':
                    835:                        sscanf(optarg, "0x%x", &kernel_ep);
                    836:                        break;
                    837:                case 'L':
                    838:                        sscanf(optarg, "0x%x", &kernel_la);
                    839:                        break;
                    840:                case 'V':
                    841:                        version = optarg;
                    842:                        break;
                    843:                case 'N':
                    844:                        vendor = optarg;
                    845:                        break;
                    846:                case 'c':
                    847:                        combined++;
                    848:                        break;
                    849:                case 'k':
                    850:                        kernel_info.file_name = optarg;
                    851:                        break;
                    852:                case 'r':
                    853:                        rootfs_info.file_name = optarg;
                    854:                        break;
                    855:                case 'R':
                    856:                        sscanf(optarg, "0x%x", &rootfs_ofs);
                    857:                        break;
                    858:                case 'o':
                    859:                        ofname = optarg;
                    860:                        break;
                    861:                case 's':
                    862:                        strip_padding = 1;
                    863:                        break;
                    864:                case 'i':
                    865:                        inspect_info.file_name = optarg;
                    866:                        break;
                    867:                case 'x':
                    868:                        extract = 1;
                    869:                        break;
                    870:                case 'h':
                    871:                        usage(EXIT_SUCCESS);
                    872:                        break;
                    873:                default:
                    874:                        usage(EXIT_FAILURE);
                    875:                        break;
                    876:                }
                    877:        }
                    878: 
                    879:        ret = check_options();
                    880:        if (ret)
                    881:                goto out;
                    882: 
                    883:        if (!inspect_info.file_name)
                    884:                ret = build_fw();
                    885:        else
                    886:                ret = inspect_fw();
                    887: 
                    888:  out:
                    889:        return ret;
                    890: }
                    891: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>