diff --git a/target/linux/ipq40xx/image/Makefile b/target/linux/ipq40xx/image/Makefile index 626223a7cb..ae146cdc54 100644 --- a/target/linux/ipq40xx/image/Makefile +++ b/target/linux/ipq40xx/image/Makefile @@ -51,6 +51,14 @@ define Device/DniImage endef DEVICE_VARS += NETGEAR_BOARD_ID NETGEAR_HW_ID +define Build/SenaoFW + -$(STAGING_DIR_HOST)/bin/mksenaofw \ + -n $(BOARD_NAME) -r $(VENDOR_ID) -p $(1) \ + -c $(DATECODE) -w $(2) -x $(CW_VER) -t 0 \ + -e $@ \ + -o $@.new + @cp $@.new $@ +endef define Device/8dev_jalapeno $(call Device/FitImage) @@ -168,17 +176,27 @@ endef TARGET_DEVICES += engenius_eap1300 define Device/engenius_ens620ext - $(call Device/FitImage) - DEVICE_DTS := qcom-ipq4018-ens620ext - DEVICE_DTS_CONFIG := config@4 - BLOCKSIZE := 64k - PAGESIZE := 256 - DEVICE_TITLE := EnGenius ENS620EXT - IMAGE_SIZE := 21823488 - KERNEL_SIZE := 5120k - FILESYSTEMS := squashfs - IMAGES := sysupgrade.bin - IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | check-size $$$$(IMAGE_SIZE) | append-metadata + $(call Device/FitImage) + DEVICE_DTS := qcom-ipq4018-ens620ext + DEVICE_DTS_CONFIG := config@4 + BLOCKSIZE := 64k + PAGESIZE := 256 + DEVICE_TITLE := EnGenius ENS620EXT + BOARD_NAME := ENS620EXT + VENDOR_ID := 0x0101 + PRODUCT_ID := 0x79 + PRODUCT_ID_NEW := 0xA4 + DATECODE := 190507 + FW_VER := 3.1.2 + FW_VER_NEW := 3.5.6 + CW_VER := 1.8.99 + IMAGE_SIZE := 21823488 + KERNEL_SIZE := 5120k + FILESYSTEMS := squashfs + IMAGES := sysupgrade.bin factory_30.bin factory_35.bin + IMAGE/sysupgrade.bin := append-kernel | append-rootfs | pad-rootfs | check-size $$$$(IMAGE_SIZE) | append-metadata + IMAGE/factory_30.bin := append-kernel | pad-to $$$$(KERNEL_SIZE) | append-rootfs | pad-rootfs | check-size $$$$(IMAGE_SIZE) | SenaoFW $$$$(PRODUCT_ID) $$$$(FW_VER) + IMAGE/factory_35.bin := qsdk-ipq-factory-nor | check-size $$$$(IMAGE_SIZE) | SenaoFW $$$$(PRODUCT_ID_NEW) $$$$(FW_VER_NEW) DEVICE_PACKAGES := ipq-wifi-engenius_ens620ext endef TARGET_DEVICES += engenius_ens620ext diff --git a/tools/firmware-utils/Makefile b/tools/firmware-utils/Makefile index 76d5929af5..bde90f0ecd 100644 --- a/tools/firmware-utils/Makefile +++ b/tools/firmware-utils/Makefile @@ -23,7 +23,7 @@ define Host/Compile $(call cc,otrx) $(call cc,motorola-bin) $(call cc,dgfirmware) - $(call cc,mksenaofw md5) + $(call cc,mksenaofw md5, -Wall --std=gnu99) $(call cc,trx2usr) $(call cc,ptgen) $(call cc,srec2bin) diff --git a/tools/firmware-utils/src/mksenaofw.c b/tools/firmware-utils/src/mksenaofw.c index 0f10ebdfbe..b0fb7203c3 100644 --- a/tools/firmware-utils/src/mksenaofw.c +++ b/tools/firmware-utils/src/mksenaofw.c @@ -55,6 +55,7 @@ typedef enum { } op_mode; static firmware_type FIRMWARE_TYPES[] = { + { 0x00, "combo" }, /* Used for new capwap-included style header */ { 0x01, "bootloader" }, { 0x02, "kernel" }, { 0x03, "kernelapp" }, @@ -70,6 +71,21 @@ static firmware_type FIRMWARE_TYPES[] = { { 0x0c, "langpack (D-Link)" } }; +#define MOD_DEFAULT 0x616C6C00 +#define SKU_DEFAULT 0x0 +#define DATECODE_NONE 0xFFFFFFFF +#define FIRMWARE_TYPE_NONE 0xFF + +struct capwap_header { + uint32_t mod; + uint32_t sku; + uint32_t firmware_ver[3]; + uint32_t datecode; + uint32_t capwap_ver[3]; + uint32_t model_size; + uint8_t model[]; +}; + static long get_file_size(const char *filename) { FILE *fp_file; @@ -84,15 +100,14 @@ static long get_file_size(const char *filename) return result; } -static int header_checksum(void *data, int len) +static int header_checksum(void *data, size_t len) { - int i; - int sum; + int sum = 0; /* shouldn't this be unsigned ? */ + size_t i; - sum = 0; - if (data != NULL && len >= 0) { + if (data != NULL && len > 0) { for (i = 0; i < len; ++i) - sum += *(unsigned char *) (data + i); + sum += ((unsigned char *)data)[i]; return sum; } @@ -124,18 +139,20 @@ static int md5_file(const char *filename, uint8_t *dst) } static int encode_image(const char *input_file_name, - const char *output_file_name, img_header *header, int block_size) + const char *output_file_name, img_header *header, + struct capwap_header *cw_header, int block_size) { char buf[BUF_SIZE]; - size_t bytes_read; size_t pad_len = 0; size_t bytes_avail; + size_t bytes_read; - FILE *fp_input; FILE *fp_output; + FILE *fp_input; - int i; + int model_size; long magic; + size_t i; fp_input = fopen(input_file_name, "r+b"); if (!fp_input) { @@ -172,6 +189,11 @@ static int encode_image(const char *input_file_name, } header->zero = 0; header->chksum = header_checksum(header, HDR_LEN); + if (cw_header) { + header->chksum += header_checksum(cw_header, + sizeof(struct capwap_header) + cw_header->model_size); + } + header->head = htonl(header->head); header->vendor_id = htonl(header->vendor_id); header->product_id = htonl(header->product_id); @@ -183,6 +205,22 @@ static int encode_image(const char *input_file_name, fwrite(header, HDR_LEN, 1, fp_output); + if (cw_header) { + model_size = cw_header->model_size; + cw_header->mod = htonl(cw_header->mod); + cw_header->sku = htonl(cw_header->sku); + cw_header->firmware_ver[0] = htonl(cw_header->firmware_ver[0]); + cw_header->firmware_ver[1] = htonl(cw_header->firmware_ver[1]); + cw_header->firmware_ver[2] = htonl(cw_header->firmware_ver[2]); + cw_header->datecode = htonl(cw_header->datecode); + cw_header->capwap_ver[0] = htonl(cw_header->capwap_ver[0]); + cw_header->capwap_ver[1] = htonl(cw_header->capwap_ver[1]); + cw_header->capwap_ver[2] = htonl(cw_header->capwap_ver[2]); + cw_header->model_size = htonl(cw_header->model_size); + fwrite(cw_header, sizeof(struct capwap_header) + model_size, 1, + fp_output); + } + while (!feof(fp_input) || pad_len > 0) { if (!feof(fp_input)) @@ -212,32 +250,33 @@ static int encode_image(const char *input_file_name, int decode_image(const char *input_file_name, const char *output_file_name) { - img_header header; + struct capwap_header cw_header; char buf[BUF_SIZE]; + img_header header; + char *pmodel = NULL; FILE *fp_input; FILE *fp_output; - unsigned int i; size_t bytes_read; size_t bytes_written; + unsigned int i; fp_input = fopen(input_file_name, "r+b"); if (!fp_input) { fprintf(stderr, "Cannot open %s !!\n", input_file_name); - fclose(fp_input); return -1; } fp_output = fopen(output_file_name, "w+b"); if (!fp_output) { fprintf(stderr, "Cannot open %s !!\n", output_file_name); - fclose(fp_output); + fclose(fp_input); return -1; } if (fread(&header, 1, HDR_LEN, fp_input) != HDR_LEN) { - fprintf(stderr, "Incorrect header size!!"); + fprintf(stderr, "Incorrect header size reading base header!!"); fclose(fp_input); fclose(fp_output); return -1; @@ -251,6 +290,44 @@ int decode_image(const char *input_file_name, const char *output_file_name) header.chksum = ntohl(header.chksum); header.magic = ntohl(header.magic); + /* read capwap header if firmware_type is zero */ + if (header.firmware_type == 0) { + if (fread(&cw_header, 1, sizeof(struct capwap_header), + fp_input) != sizeof(struct capwap_header)) { + fprintf(stderr, "Incorrect header size reading capwap_header!!"); + fclose(fp_input); + fclose(fp_output); + return -1; + } + cw_header.mod = ntohl(cw_header.mod); + cw_header.sku = ntohl(cw_header.sku); + cw_header.firmware_ver[0] = ntohl(cw_header.firmware_ver[0]); + cw_header.firmware_ver[1] = ntohl(cw_header.firmware_ver[1]); + cw_header.firmware_ver[2] = ntohl(cw_header.firmware_ver[2]); + cw_header.datecode = ntohl(cw_header.datecode); + cw_header.capwap_ver[0] = ntohl(cw_header.capwap_ver[0]); + cw_header.capwap_ver[1] = ntohl(cw_header.capwap_ver[1]); + cw_header.capwap_ver[2] = ntohl(cw_header.capwap_ver[2]); + cw_header.model_size = ntohl(cw_header.model_size); + + pmodel = malloc(cw_header.model_size + 1); + if (pmodel) { + pmodel[cw_header.model_size] = '\0'; + if (fread(pmodel, 1, cw_header.model_size, fp_input) != + cw_header.model_size) { + fprintf(stderr, "Incorrect header size reading model name!!"); + fclose(fp_input); + fclose(fp_output); + return -1; + } + } else { + fprintf(stderr, "Incorrect header size reading model name!!"); + fclose(fp_input); + fclose(fp_output); + return -1; + } + } + bytes_written = 0; while (!feof(fp_input)) { @@ -281,7 +358,7 @@ int decode_image(const char *input_file_name, const char *output_file_name) static void usage(const char *progname, int status) { FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; - int i; + size_t i; fprintf(stream, "Usage: %s [OPTIONS...]\n", progname); fprintf(stream, "\n" @@ -301,28 +378,47 @@ static void usage(const char *progname, int status) " -m set encoding magic \n" " -z enable image padding to \n" " -b set image , defaults to %u\n" + " -c add capwap header with (e.g. 171101)\n" + " -w firmware version for capwap header (e.g. 3.0.1)\n" + " -x capwap firmware version for capwap header (e.g. 1.8.53)\n" + " -n model name for capwap header (e.g. ENS620EXT)\n" " -h show this screen\n", DEFAULT_BLOCK_SIZE); exit(status); } int main(int argc, char *argv[]) { - int opt; - char *input_file, *output_file, *progname = NULL; - op_mode mode = NONE; - int tmp, i, pad = 0; - int block_size; + static const char period[2] = "."; + struct capwap_header cw_header; img_header header; + struct capwap_header *pcw_header = NULL; + char *output_file = NULL; + char *input_file = NULL; + char *progname = NULL; + char *mod_name = NULL; + char *token; + + op_mode mode = NONE; + int tmp, pad = 0; + int block_size; + size_t i; + int opt; + block_size = DEFAULT_BLOCK_SIZE; progname = basename(argv[0]); - memset(&header, 0, sizeof( img_header )); + memset(&header, 0, sizeof(img_header)); header.magic = DEFAULT_MAGIC; header.head = DEFAULT_HEAD_VALUE; + header.firmware_type = FIRMWARE_TYPE_NONE; + memset(&cw_header, 0, sizeof(struct capwap_header)); + cw_header.mod = MOD_DEFAULT; + cw_header.sku = SKU_DEFAULT; + cw_header.datecode = DATECODE_NONE; strncpy( (char*)&header.version, DEFAULT_VERSION, VERSION_SIZE - 1); - while ((opt = getopt(argc, argv, ":o:e:d:t:v:r:p:m:b:h?z")) != -1) { + while ((opt = getopt(argc, argv, ":o:e:d:t:v:r:p:m:b:c:w:x:n:h?z")) != -1) { switch (opt) { case 'e': input_file = optarg; @@ -344,7 +440,7 @@ int main(int argc, char *argv[]) break; } } - if (header.firmware_type == 0) { + if (header.firmware_type == FIRMWARE_TYPE_NONE) { fprintf(stderr, "Invalid firmware type \"0\"!\n"); usage(progname, EXIT_FAILURE); } @@ -368,6 +464,31 @@ int main(int argc, char *argv[]) case 'b': block_size = strtol(optarg, 0, 10); break; + case 'c': + cw_header.datecode = strtoul(optarg, 0, 10); + break; + case 'w': + token = strtok(optarg, period); + i = 0; + while (token && (i < 3)) { + cw_header.firmware_ver[i++] = + strtoul(token, 0, 10); + token = strtok(NULL, period); + } + break; + case 'x': + token = strtok(optarg, period); + i = 0; + while (token && (i < 3)) { + cw_header.capwap_ver[i++] = + strtoul(token, 0, 10); + token = strtok(NULL, period); + } + break; + case 'n': + mod_name = optarg; + cw_header.model_size = strlen(mod_name); + break; case 'h': usage(progname, EXIT_SUCCESS); break; @@ -403,17 +524,46 @@ int main(int argc, char *argv[]) return EXIT_SUCCESS; } - if (header.firmware_type == 0) { - fprintf(stderr, "Firmware type must be defined\n"); + if ((header.firmware_type == 0) && + (cw_header.datecode == DATECODE_NONE)) { + fprintf(stderr, "Firmware type must be non-zero for non-capwap images\n"); usage(progname, EXIT_FAILURE); } if (header.vendor_id == 0 || header.product_id == 0) { - fprintf(stderr, "Vendor ID and Product ID must be defined and non-zero\n"); + fprintf(stderr, "Vendor ID and Product ID must be defined and non-zero\n"); usage(progname, EXIT_FAILURE); } - if (encode_image(input_file, output_file, &header, pad ? block_size : 0) < 0) + /* Check capwap header specific arguments */ + if (cw_header.datecode != DATECODE_NONE) { + if (!mod_name) { + fprintf(stderr, "Capwap header specified: model name must be specified\n"); + usage(progname, EXIT_FAILURE); + } + if (!cw_header.firmware_ver[0] && !cw_header.firmware_ver[1] && + !cw_header.firmware_ver[2]) { + fprintf(stderr, "Capwap header specified, fw_ver must be non-zero\n"); + } + if (!cw_header.capwap_ver[0] && !cw_header.capwap_ver[1] && + !cw_header.capwap_ver[2]) { + fprintf(stderr, "Capwap header specified, cw_ver must be non-zero\n"); + } + pcw_header = malloc(sizeof(struct capwap_header) + + cw_header.model_size); + if (pcw_header) { + memcpy(pcw_header, &cw_header, + sizeof(struct capwap_header)); + memcpy(&(pcw_header->model), mod_name, + cw_header.model_size); + } else { + fprintf(stderr, "Failed to allocate memory\n"); + return EXIT_FAILURE; + } + } + + if (encode_image(input_file, output_file, &header, pcw_header, + pad ? block_size : 0) < 0) return EXIT_FAILURE; return EXIT_SUCCESS;