asuswrt-merlin.ng/release/src-rt-5.04axhnd.675x/router-sysdep.rt-ax82u_v2/bcm_flashutil/bcm_imgcombo.c
2023-09-21 00:22:26 +02:00

426 lines
17 KiB
C
Executable file

/***********************************************************************
* <:copyright-BRCM:2016:DUAL/GPL:standard
*
* Copyright (c) 2016 Broadcom
* All Rights Reserved
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed
* to you under the terms of the GNU General Public License version 2
* (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
* with the following added to such license:
*
* As a special exception, the copyright holders of this software give
* you permission to link this software with independent modules, and
* to copy and distribute the resulting executable under terms of your
* choice, provided that you also meet, for each linked independent
* module, the terms and conditions of the license of that module.
* An independent module is a module which is not derived from this
* software. The special exception does not apply to any modifications
* of the software.
*
* Not withstanding the above, under no circumstances may you combine
* this software in any way with any other Broadcom software provided
* under a license other than the GPL, without Broadcom's express prior
* written consent.
*
* :>
************************************************************************/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "bcmTag.h"
#include "genutil_crc.h"
#include "bcm_imgutil.h"
#include "boardparms.h"
#ifdef COMBOIMG_DUMPHEX
#define DUMP_HEX(b, l) dump_hex(b, l)
#else
#define DUMP_HEX(b, l)
#endif
#define COMBOIMG_DEBUG 0
#define comboimg_debug(fmt, ...) \
do { if (COMBOIMG_DEBUG) fprintf(stderr, "%s:%d(): " fmt, \
__func__, __LINE__, ##__VA_ARGS__); } while (0)
#define comboimg_info(fmt, ...) \
do { fprintf(stderr, "%s:%d(): " fmt, \
__func__, __LINE__, ##__VA_ARGS__); } while (0)
void dump_combo_header_tag(Comboimg_header_tag *header_tag)
{
if (!header_tag)
return;
comboimg_info("--------------------------------------------------------------\n");
comboimg_info("Combo image header tag:\n");
comboimg_info("image count %u\n",header_tag->image_count);
comboimg_info("--------------------------------------------------------------\n");
}
void dump_individual_image_tag(Comboimg_individual_img_tag *image_tag_ptr)
{
if (!image_tag_ptr)
return;
comboimg_info("--------------------------------------------------------------\n");
comboimg_info("Combo header, individual image tag:\n");
comboimg_info("\tchip_id 0x%08x\n",image_tag_ptr->chip_id);
image_tag_ptr->board_id[BOARD_ID_LEN-1]='\0';
comboimg_info("\tboard_id %s\n",image_tag_ptr->board_id);
comboimg_info("\timage_len %u\n",image_tag_ptr->image_len);
comboimg_info("\timage_offset %u\n",image_tag_ptr->image_offset);
comboimg_info("\timage_flags %u\n",image_tag_ptr->image_flags);
comboimg_info("\tnext_tag_offset %u\n",image_tag_ptr->next_tag_offset);
comboimg_info("\textended_image_header %u\n",image_tag_ptr->extended_image_header);
comboimg_info("--------------------------------------------------------------\n");
}
void dump_hex(const char *buf, UINT32 len)
{
UINT32 i;
for (i = 0; i < len; i++)
printf("%02X ", (unsigned char)buf[i]);
printf("\n");
}
UINT32 bcmImg_rollToImage(const char *imageBuf __attribute__((unused)),
UINT32 imageLen __attribute__((unused)))
{
return 0;
}
static int combo_parsing_state = 0;
UBOOL8 bcmImg_IsValidCombo(void)
{
return (combo_parsing_state == combo_done);
}
static char board_id[BP_BOARD_ID_LEN+5];
imgutil_ret_e bcmImg_GetBoardId(){
#ifndef DESKTOP_LINUX
FILE * fp = NULL;
fp = fopen("/proc/nvram/boardid","r");
if(fp)
{
imgutil_ret_e ret = IMGUTIL_PROC_OK;
int count;
count = fscanf(fp,"%s",board_id);
if (count <= 0)
{
comboimg_info("could not fscanf board_id\n");
ret = IMGUTIL_PROC_ERR;
}
else
comboimg_debug("boardid is %s\n",board_id);
fclose(fp);
return ret;
}
else
{
comboimg_info("unable to read boardid from procfs %s\n",board_id);
return IMGUTIL_PROC_ERR;
}
#else
return IMGUTIL_PROC_OK;
#endif
}
imgutil_ret_e bcmImg_ComboImageInit(void)
{
combo_parsing_state = combo_init;
return bcmImg_GetBoardId();
}
UBOOL8 bcmImg_ComboImageParsingDone(void)
{
if (combo_parsing_state == combo_done || combo_parsing_state == fail
|| combo_parsing_state == not_combo)
return TRUE;
else
return FALSE;
}
imgutil_ret_e bcmImg_ComboImageIdentify(const char *imageBuf, UINT32 imageLen)
{
const char magicnum[] = COMBOIMG_MAGIC_NUM;
DUMP_HEX(magicnum, COMBOIMG_MAGIC_NUM_LEN);
DUMP_HEX(imageBuf, imageLen);
if (imageLen < COMBOIMG_MAGIC_NUM_LEN)
{
return IMGUTIL_PROC_MORE_DATA;
}
if (!memcmp(imageBuf, magicnum, COMBOIMG_MAGIC_NUM_LEN))
return IMGUTIL_PROC_FOUND;
else
return IMGUTIL_PROC_NOT_FOUND;
}
imgutil_ret_e bcmImg_ComboImageParseHeader(char *imageBuf, UINT32 imageLen,
UINT32 *consumed, UINT32 *image_len, int *parsingState,
Comboimg_header_tag *comboTagP, Comboimg_individual_img_tag *indvTagP,
imgutil_accept_range_ctx_t *ar_ctx)
{
static Comboimg_header_tag header_tag_tmp, *header_tag_ptr;
static Comboimg_individual_img_tag *image_tag_ptr;
static Comboimg_individual_img_tag image_tag_tmp;
UINT32 i = 0;
//state variables must get reset
static UINT32 offset_to_image = 0;
static UINT32 stream_location = 0;
static UINT32 header_len = 0;
static char *combo_rcv_buf = 0;
//todo: fix endianity to support little endian deployment
//todo: what if first packet does not have complete header_tag
// deal with extended header header and image tag
//printf("in function combo parser\n");
*consumed = 0;
while (*consumed < imageLen && combo_parsing_state!=combo_done)
{
switch (combo_parsing_state)
{
case combo_init:
//reset all state variables
stream_location = 0;
offset_to_image = 0;
combo_rcv_buf = 0;
//assuming here that magic_number received in whole
if (bcmImg_ComboImageIdentify(imageBuf, imageLen) != IMGUTIL_PROC_FOUND)
{
combo_parsing_state = not_combo;
*parsingState = combo_parsing_state;
return IMGUTIL_PROC_OK;
}
else
{
comboimg_info("found combo magic number, setting combo parse state: get_header_tag\n");
combo_parsing_state = get_header_tag;
}
//fall-through
case get_header_tag:
{
//copy just what needed to get header tag
UINT32 need = sizeof(Comboimg_header_tag) - stream_location;
comboimg_debug("in combo parse state get_header_tag, need %d more to combo header tag\n",need);
if (need > imageLen)
{
memcpy(&header_tag_tmp,imageBuf, imageLen);
stream_location += imageLen;
*consumed += imageLen;
}
else
{
comboimg_debug("copying %d bytes to header_tmp for imageBuf\n",need);
memcpy(&header_tag_tmp,imageBuf, need);
stream_location += need;
*consumed += need;
header_len = be32toh(header_tag_tmp.header_len);
comboimg_debug("combo header len: %u, allocating rcvbuf\n",header_len);
//allocate memory pad, copy it and whatever remaning in imageBuf
//to pad, move state
combo_rcv_buf = calloc(header_len,1);
memcpy(combo_rcv_buf,&header_tag_tmp,sizeof(Comboimg_header_tag));
//memcpy(combo_rcv_buf + sizeof(Comboimg_header_tag)
// ,imageBuf+need, imageLen-need);
//continue to debug here
comboimg_debug("setting combo parsing state to buffering_complete_header.\n");
combo_parsing_state = buffering_complete_header;
comboimg_debug("got header_tag.\n");
comboimg_debug("stream location %d\n",stream_location);
comboimg_debug("consumed %d\n",*consumed);
header_tag_ptr = (Comboimg_header_tag*)combo_rcv_buf;
DUMP_HEX(combo_rcv_buf,sizeof(Comboimg_header_tag));
}
}
break;
case buffering_complete_header:
{
//must fix endian for reverse singular image header
//buffering is required because receiving is not promised to be
//aligned to combo header structure
UINT32 need = header_len - stream_location;
comboimg_debug("in buffering complete header, need %d\n",need);
if (need > imageLen - *consumed)
{
//need to buffer more
memcpy(combo_rcv_buf + stream_location, imageBuf + *consumed
,imageLen - *consumed);
stream_location += (imageLen - *consumed);
*consumed += (imageLen - *consumed);
}
else
{
memcpy(combo_rcv_buf + stream_location, imageBuf + *consumed
, need);
stream_location += need;
*consumed += need;
//validate CRC
UINT32 calculated_crc = CRC_INITIAL_VALUE;
UINT32 received_crc = be32toh(header_tag_ptr->header_crc);
header_tag_ptr->header_crc = 0 ;
DUMP_HEX(combo_rcv_buf, header_len);
calculated_crc = genUtl_getCrc32((unsigned char*)combo_rcv_buf,
header_len , calculated_crc);
if (calculated_crc != received_crc)
{
comboimg_debug("received CRC is 0x%08X\n", received_crc);
comboimg_debug("calculated CRC is 0x%08X\n", calculated_crc);
combo_parsing_state = fail;
free(combo_rcv_buf);
comboimg_info("Error in combo header CRC\n");
*parsingState = combo_parsing_state;
return IMGUTIL_PROC_INVALID_IMG;
}
else
comboimg_debug("combo header CRC validated\n");
//reverse header endianess
UINT32* curr = 0;
comboimg_debug("flipping header_tag endian\n");
for (curr = &header_tag_ptr->header_len;
curr <= &header_tag_ptr->extended_combo_header; curr++)
{
*curr = be32toh(*curr);
}
//todo: flip the extended header TLV entries
//flip endian for individual image headers
image_tag_ptr = (Comboimg_individual_img_tag*) (
(char*)&header_tag_ptr->extended_combo_header
+ header_tag_ptr->next_tag_offset);
for (i = 0; i < header_tag_ptr->image_count; i++)
{
UINT32* curr = 0;
for(curr = &image_tag_ptr->chip_id;
curr <= &image_tag_ptr->extended_image_header; curr++)
{
*curr = be32toh(*curr);
}
//todo: flip the extended header TLV entries
image_tag_ptr = (Comboimg_individual_img_tag*) (
(char*)&image_tag_ptr->extended_image_header
+ image_tag_ptr->next_tag_offset);
}
// in case of failue set state and free(combo_rcv_buf);
// must deal with extended header here
combo_parsing_state = in_image;
comboimg_debug("finished buffering combo_header, total received %d\n",stream_location);
comboimg_debug("setting combo parsing state to in_image.\n");
dump_combo_header_tag(header_tag_ptr);
}
}
break;
case in_image:
image_tag_ptr = (Comboimg_individual_img_tag*) (
(char*)&header_tag_ptr->extended_combo_header
+ header_tag_ptr->next_tag_offset);
comboimg_info("searching an image for chip: %08X boardid: %s\n", CHIP_FAMILY_ID_HEX, board_id);
for (i = 0; i<header_tag_ptr->image_count; i++)
{
comboimg_debug("image %d\n",i);
dump_individual_image_tag(image_tag_ptr);
DUMP_HEX((char*)image_tag_ptr, sizeof(Comboimg_individual_img_tag));
//todo: need to consider extended header length
//*consumed += sizeof(Comboimg_individual_img_tag);
if (image_tag_ptr->chip_id == CHIP_FAMILY_ID_HEX
&& !strncmp(image_tag_ptr->board_id, board_id, strlen(board_id)))
{
comboimg_info("found chip_id match, calculating offset\n");
comboimg_debug("value of offset in image header: 0x%08x \n", image_tag_ptr->image_offset);
//could be also image_offset -header length
offset_to_image = image_tag_ptr->image_offset - stream_location;
comboimg_debug("offset to image from current stream location: %u\n", offset_to_image);
*image_len = image_tag_ptr->image_len;
comboimg_debug("image len is: %d\n",*image_len);
memcpy(&image_tag_tmp, image_tag_ptr, sizeof(Comboimg_individual_img_tag));
memcpy(comboTagP, combo_rcv_buf, sizeof(Comboimg_header_tag));
memcpy(indvTagP, &image_tag_tmp, sizeof(Comboimg_individual_img_tag));
if(!ar_ctx->accept_ranges)
{
comboimg_info("server does not support Accept-Ranges. setting combo parsing state to rolling.\n");
combo_parsing_state = rolling;
}
else
{
ar_ctx->range_begin = image_tag_ptr->image_offset;
ar_ctx->range_end = ar_ctx->range_begin + image_tag_ptr->image_len - 1;
comboimg_info("Individual image range_begin to %lu range_end %lu\n"
,ar_ctx->range_begin, ar_ctx->range_end);
combo_parsing_state = combo_done;
//free rcv_buffer_here
free(combo_rcv_buf);
}
break;
}
image_tag_ptr = (Comboimg_individual_img_tag*) (
(char*)&image_tag_ptr->extended_image_header + image_tag_ptr->next_tag_offset);
//todo: need to consider extended header length
//dataptr += *used; //(char*)&image_tag[i].extended_image_header + image_tag[i].next_tag_offset;
}
if (combo_parsing_state != rolling && combo_parsing_state != combo_done)
{
comboimg_info("didn't find matching image\n");
combo_parsing_state = fail;
return IMGUTIL_PROC_NOT_FOUND;
}
break;
case rolling:
//comboimg_debug("in rolling, offset %u\n",offset_to_image);
//comboimg_debug("imageLen value: %u\n",imageLen);
//comboimg_debug("consumed value: %u\n",*consumed);
printf("R");
if (offset_to_image > imageLen - *consumed)
{
//comboimg_debug("\nimage starts next packets\n");
offset_to_image -= (imageLen - *consumed);
*consumed += (imageLen - *consumed);
stream_location += (imageLen - *consumed);
}
else
{
comboimg_debug("\nimage starts in this packet, offset to image %u\n",offset_to_image);
*consumed = offset_to_image;
stream_location += offset_to_image;
comboimg_info("\nrolling done. stream_location %d, consumed %d\n",stream_location,*consumed);
combo_parsing_state = combo_done;
//free rcv_buffer_here
free(combo_rcv_buf);
*parsingState = combo_parsing_state;
return IMGUTIL_PROC_OK;
}
break;
}
}
//comboimg_debug("Exiting combo parsing function. state %d\n", combo_parsing_state);
*parsingState = combo_parsing_state;
return IMGUTIL_PROC_OK;
}