@ -5,6 +5,7 @@
# include <unistd.h>
# include <unistd.h>
# include <byteswap.h>
# include <byteswap.h>
# include <endian.h>
# include <endian.h>
# include <getopt.h>
# if !defined(__BYTE_ORDER)
# if !defined(__BYTE_ORDER)
# error "Unknown byte order"
# error "Unknown byte order"
@ -12,14 +13,8 @@
# if __BYTE_ORDER == __BIG_ENDIAN
# if __BYTE_ORDER == __BIG_ENDIAN
# define cpu_to_be32(x) (x)
# define cpu_to_be32(x) (x)
# define be32_to_cpu(x) (x)
# define cpu_to_be16(x) (x)
# define be16_to_cpu(x) (x)
# elif __BYTE_ORDER == __LITTLE_ENDIAN
# elif __BYTE_ORDER == __LITTLE_ENDIAN
# define cpu_to_be32(x) bswap_32(x)
# define cpu_to_be32(x) bswap_32(x)
# define be32_to_cpu(x) bswap_32(x)
# define cpu_to_be16(x) bswap_16(x)
# define be16_to_cpu(x) bswap_16(x)
# else
# else
# error "Unsupported endianness"
# error "Unsupported endianness"
# endif
# endif
@ -33,9 +28,6 @@
# endif
# endif
# define ERR(...) {printf(__VA_ARGS__); }
# define ERR(...) {printf(__VA_ARGS__); }
# define ALIGN(a,b) ((a) + ((b) - ((a) % (b))))
# define ROOTFS_ALIGN 128
# define HEADER_SIZE 71
/*
/*
* Fw Header Layout for Netgear / Sercomm devices ( bytes )
* Fw Header Layout for Netgear / Sercomm devices ( bytes )
@ -51,14 +43,12 @@
* magic : 63 - 69 ASCII
* magic : 63 - 69 ASCII
* ChkSum : 511 Inverse value of the full image checksum while this location is 0x00
* ChkSum : 511 Inverse value of the full image checksum while this location is 0x00
*/
*/
static const char * magic = " sErCoMm " ; /* 7 */
static const char * magic = " sErCoMm " ; /* 7 */
/* 7-11: version control/download control ? */
static const unsigned char version [ 4 ] = { 0x00 , 0x01 , 0x00 , 0x00 } ;
static const unsigned char version [ 4 ] = { 0x00 , 0x01 , 0x00 , 0x00 } ;
static const int header_sz = 512 ;
static const int footer_sz = 71 ;
static int is_header = 1 ;
/* 512 onwards -> ZIP containing rootfs with the same Header */
struct file_info {
struct file_info {
char * file_name ; /* name of the file */
char * file_name ; /* name of the file */
@ -68,23 +58,32 @@ struct file_info {
static u_int8_t getCheckSum ( char * data , int len ) {
static u_int8_t getCheckSum ( char * data , int len ) {
u_int8_t new = 0 ;
u_int8_t new = 0 ;
int i ;
if ( ! data ) {
if ( ! data ) {
ERR ( " Invalid pointer provided! \n " ) ;
ERR ( " Invalid pointer provided! \n " ) ;
return 0 ;
return 0 ;
}
}
for ( int i = 0 ; i < len ; i + + ) {
for ( i = 0 ; i < len ; i + + ) {
new + = data [ i ] ;
new + = data [ i ] ;
}
}
return new ;
return new ;
}
}
static int bufferFile ( struct file_info * finfo ) {
/*
int fs = 0 ;
* read file into buffer
* add space for header / footer
*/
static int copyToOutputBuf ( struct file_info * finfo ) {
FILE * fp = NULL ;
FILE * fp = NULL ;
int file_sz = 0 ;
int extra_sz ;
int hdr_pos ;
int img_pos ;
if ( ! finfo | | ! finfo - > file_name ) {
if ( ! finfo | | ! finfo - > file_name ) {
ERR ( " Invalid pointer provided! \n " ) ;
ERR ( " Invalid pointer provided! \n " ) ;
return - 1 ;
return - 1 ;
@ -100,25 +99,39 @@ static int bufferFile(struct file_info* finfo) {
/* Get filesize */
/* Get filesize */
rewind ( fp ) ;
rewind ( fp ) ;
fseek ( fp , 0L , SEEK_END ) ;
fseek ( fp , 0L , SEEK_END ) ;
f s = ftell ( fp ) ;
f ile_ sz = ftell ( fp ) ;
rewind ( fp ) ;
rewind ( fp ) ;
if ( f s < 0 ) {
if ( f ile_sz < 1 ) {
ERR ( " Error getting filesize: %s \n " , finfo - > file_name ) ;
ERR ( " Error getting filesize: %s \n " , finfo - > file_name ) ;
fclose ( fp ) ;
fclose ( fp ) ;
return - 1 ;
return - 1 ;
}
}
DBG ( " Filesize: %i \n " , fs ) ;
if ( is_header ) {
finfo - > file_size = fs ;
extra_sz = header_sz ;
hdr_pos = 0 ;
img_pos = header_sz ;
} else {
extra_sz = footer_sz ;
hdr_pos = file_sz ;
img_pos = 0 ;
}
DBG ( " Filesize: %i \n " , file_sz ) ;
finfo - > file_size = file_sz + extra_sz ;
if ( ! ( finfo - > file_data = malloc ( fs ) ) ) {
if ( ! ( finfo - > file_data = malloc ( f info- > file_ size ) ) ) {
ERR ( " Out of memory! \n " ) ;
ERR ( " Out of memory! \n " ) ;
fclose ( fp ) ;
fclose ( fp ) ;
return - 1 ;
return - 1 ;
}
}
if ( fread ( finfo - > file_data , 1 , fs , fp ) ! = fs ) {
/* init header/footer bytes */
memset ( finfo - > file_data + hdr_pos , 0 , extra_sz ) ;
/* read file and take care of leading header if exists */
if ( fread ( finfo - > file_data + img_pos , 1 , file_sz , fp ) ! = file_sz ) {
ERR ( " Error reading file %s \n " , finfo - > file_name ) ;
ERR ( " Error reading file %s \n " , finfo - > file_name ) ;
fclose ( fp ) ;
fclose ( fp ) ;
return - 1 ;
return - 1 ;
@ -127,7 +140,7 @@ static int bufferFile(struct file_info* finfo) {
DBG ( " File: read successful \n " ) ;
DBG ( " File: read successful \n " ) ;
fclose ( fp ) ;
fclose ( fp ) ;
return 0 ;
return hdr_pos ;
}
}
static int writeFile ( struct file_info * finfo ) {
static int writeFile ( struct file_info * finfo ) {
@ -157,266 +170,92 @@ static int writeFile(struct file_info* finfo) {
return 0 ;
return 0 ;
}
}
static void fi_clean ( struct file_info * finfo ) {
if ( ! finfo )
return ;
if ( finfo - > file_name ) {
finfo - > file_name = NULL ;
}
if ( finfo - > file_data ) {
free ( finfo - > file_data ) ;
finfo - > file_data = NULL ;
}
finfo - > file_size = 0 ;
}
static void usage ( char * argv [ ] ) {
static void usage ( char * argv [ ] ) {
printf ( " Usage: %s <sysupgradefile> <kernel_offset> <HWID> <HWVER> <SWID> \n "
printf ( " Usage: %s [OPTIONS...] \n "
" All are positional arguments ... \n "
" \n "
" sysupgradefile: File with the kernel uimage at 0 \n "
" Options: \n "
" kernel_offset: Offset where the kernel is located (decimal, hex or octal notation )\n "
" -f add sercom footer (if absent, header) \n "
" HWID: Hardware ID, ASCII \n "
" -b <hwid> use hardware id specified with <hwid> (ASCII) \n "
" HWVER: Hardware Version, ASCII \n "
" -r <hwrev> use hardware revision specified with <hwrev> (ASCII) \n "
" SWID: Software Version (decimal, hex or octal notation)\n "
" -v <version> set image version to <version> (decimal, hex or octal notation) \n "
" \n "
" -i <file> input file \n "
, argv [ 0 ] ) ;
, argv [ 0 ] ) ;
}
}
int main ( int argc , char * argv [ ] ) {
int main ( int argc , char * argv [ ] ) {
int ret = 1 ;
int rootfsname_sz ;
int zipfsname_sz ;
int zipcmd_sz ;
u_int32_t kernel_offset = 0x90000 ; /* offset for the kernel inside the rootfs, default val */
u_int32_t swVer = 0 ;
struct file_info sysupgrade = { 0 } ;
struct file_info header = { 0 } ;
struct file_info rootfs = { 0 } ;
struct file_info zippedfs = { 0 } ;
struct file_info image = { 0 } ;
struct file_info image = { 0 } ;
char * hwID = NULL ;
char * hwID = NULL ;
char * hwVer = NULL ;
char * hwVer = NULL ;
char * rootfsname = NULL ;
u_int32_t swVer = 0 ;
char * zipfsname = NULL ;
char * zipcmd = NULL ;
u_int8_t chkSum ;
u_int8_t chkSum ;
int hdr_offset ;
if ( argc = = 2 ) {
struct file_info myfile = { argv [ 1 ] , 0 , 0 } ;
while ( 1 ) {
int c ;
if ( bufferFile ( & myfile ) )
return 1 ;
c = getopt ( argc , argv , " b:i:r:v:f " ) ;
if ( c = = - 1 )
chkSum = getCheckSum ( myfile . file_data , myfile . file_size ) ;
break ;
printf ( " Checksum for File: 0x%hhX \n " , chkSum ) ;
switch ( c ) {
return 0 ;
case ' b ' :
hwID = optarg ;
break ;
case ' f ' :
is_header = 0 ;
break ;
case ' i ' :
image . file_name = optarg ;
break ;
case ' r ' :
hwVer = optarg ;
break ;
case ' v ' :
swVer = ( u_int32_t ) strtol ( optarg , NULL , 0 ) ;
swVer = cpu_to_be32 ( swVer ) ;
break ;
default :
usage ( argv ) ;
return EXIT_FAILURE ;
}
}
}
if ( argc ! = 6 ) {
if ( ! hwID | | ! hwVer | | ! image . file_name ) {
usage ( argv ) ;
usage ( argv ) ;
return 1 ;
return EXIT_FAILURE ;
}
}
printf ( " Building fw image for sercomm devices .. \n " ) ;
/*
* copy input to buffer , add extra space for header / footer and return
/* process args */
* header position
hwID = argv [ 3 ] ;
*/
hwVer = argv [ 4 ] ;
hdr_offset = copyToOutputBuf ( & image ) ;
if ( hdr_offset < 0 )
sysupgrade . file_name = argv [ 1 ] ;
return EXIT_FAILURE ;
image . file_name = argv [ 1 ] ;
kernel_offset = ( u_int32_t ) strtol ( argv [ 2 ] , NULL , 0 ) ;
DBG ( " Filling header: %s %s %2X %s \n " , hwID , hwVer , swVer , magic ) ;
swVer = ( u_int32_t ) strtol ( argv [ 5 ] , NULL , 0 ) ;
swVer = cpu_to_be32 ( swVer ) ;
strncpy ( image . file_data + hdr_offset + 0 , magic , 7 ) ;
memcpy ( image . file_data + hdr_offset + 7 , version , sizeof ( version ) ) ;
/* Check if files actually exist */
strncpy ( image . file_data + hdr_offset + 11 , hwID , 34 ) ;
if ( access ( sysupgrade . file_name , ( F_OK | R_OK ) ) ) {
strncpy ( image . file_data + hdr_offset + 45 , hwVer , 10 ) ;
/* Error */
memcpy ( image . file_data + hdr_offset + 55 , & swVer , sizeof ( swVer ) ) ;
ERR ( " File not found: %s \n " , sysupgrade . file_name ) ;
strncpy ( image . file_data + hdr_offset + 63 , magic , 7 ) ;
goto cleanup ;
/* calculate checksum and invert checksum */
if ( is_header ) {
chkSum = getCheckSum ( image . file_data , image . file_size ) ;
chkSum = ( chkSum ^ 0xFF ) + 1 ;
DBG ( " Checksum for Image: %hhX \n " , chkSum ) ;
/* write checksum to header */
image . file_data [ 511 ] = ( char ) chkSum ;
}
}
/* Calculate amount of required memory (incl. 0-term) */
/* overwrite input file */
rootfsname_sz = strlen ( sysupgrade . file_name ) + 7 + 1 ;
if ( writeFile ( & image ) )
zipfsname_sz = strlen ( sysupgrade . file_name ) + 7 + 4 + 1 ;
return EXIT_FAILURE ;
/* Allocate required memory */
if ( ! ( rootfsname = ( char * ) malloc ( rootfsname_sz ) ) | | ! ( zipfsname =
( char * ) malloc ( zipfsname_sz ) ) ) {
/* Error */
ERR ( " Out of memory! \n " ) ;
goto cleanup ;
}
/* Create filenames */
if ( snprintf ( rootfsname , rootfsname_sz , " %s.rootfs " , sysupgrade . file_name )
> = rootfsname_sz
| | snprintf ( zipfsname , zipfsname_sz , " %s.rootfs.zip " ,
sysupgrade . file_name ) > = zipfsname_sz ) {
/* Error */
ERR ( " Buffer too small! \n " ) ;
goto cleanup ;
}
/* Buffer all files */
if ( bufferFile ( & sysupgrade ) ) {
/* Error */
goto cleanup ;
}
DBG ( " Building header: %s %s %2X %s \n " , hwID , hwVer , swVer , magic ) ;
/* Construct the firmware header/magic */
header . file_name = NULL ;
header . file_size = HEADER_SIZE ;
if ( ! ( header . file_data = ( char * ) calloc ( 1 , HEADER_SIZE ) ) ) {
/* Error */
ERR ( " Out of memory! \n " ) ;
goto cleanup ;
}
strncpy ( header . file_data + 0 , magic , 7 ) ;
memcpy ( header . file_data + 7 , version , sizeof ( version ) ) ;
strncpy ( header . file_data + 11 , hwID , 34 ) ;
strncpy ( header . file_data + 45 , hwVer , 10 ) ;
memcpy ( header . file_data + 55 , & swVer , sizeof ( swVer ) ) ;
strncpy ( header . file_data + 63 , magic , 7 ) ;
DBG ( " Creating rootfs .. \n " ) ;
/* Construct a rootfs */
rootfs . file_name = rootfsname ;
rootfs . file_size = ALIGN (
sysupgrade . file_size + kernel_offset + header . file_size ,
ROOTFS_ALIGN ) ;
if ( ! ( rootfs . file_data = calloc ( 1 , rootfs . file_size ) ) ) {
/* Error */
ERR ( " Out of memory! \n " ) ;
goto cleanup ;
}
/* copy Owrt image to kernel location */
memcpy ( rootfs . file_data + kernel_offset , sysupgrade . file_data ,
sysupgrade . file_size ) ;
/* Append header after the owrt image. The updater searches for it */
memcpy ( rootfs . file_data + kernel_offset + sysupgrade . file_size ,
header . file_data , header . file_size ) ;
/* Write to file */
if ( writeFile ( & rootfs ) ) {
/* Error */
goto cleanup ;
}
/* Construct a zip */
DBG ( " Preparing to zip .. \n " ) ;
/* now that we got the rootfs, repeat the whole thing again(sorta):
* 1. zip the rootfs */
zipcmd_sz = 3 + 1 + strlen ( zipfsname ) + 1 + strlen ( rootfs . file_name ) + 1 ;
if ( ! ( zipcmd = malloc ( zipcmd_sz ) ) ) {
/* Error */
ERR ( " Out of memory! \n " ) ;
goto cleanup ;
}
if ( snprintf ( zipcmd , zipcmd_sz , " %s %s %s " , " zip " , zipfsname ,
rootfs . file_name ) > = zipcmd_sz ) {
/* Error */
ERR ( " Buffer too small! \n " ) ;
goto cleanup ;
}
if ( system ( zipcmd ) ) {
/* Error */
ERR ( " Error creating a zip file! \n " ) ;
goto cleanup ;
}
/* and load zipped fs */
zippedfs . file_name = zipfsname ;
if ( bufferFile ( & zippedfs ) ) {
/* Error */
goto cleanup ;
}
DBG ( " Creating Image. \n " ) ;
/* 2. create new file 512 + rootfs size */
image . file_size = zippedfs . file_size + 512 ;
if ( ! ( image . file_data = malloc ( zippedfs . file_size + 512 ) ) ) {
/* Error */
ERR ( " Out of memory! \n " ) ;
goto cleanup ;
}
/* 3. add header to file */
memcpy ( image . file_data , header . file_data , header . file_size ) ;
/* 4. clear remaining space */
if ( header . file_size < 512 )
memset ( image . file_data + header . file_size , 0 , 512 - header . file_size ) ;
/* 5. copy zipfile at loc 512 */
memcpy ( image . file_data + 512 , zippedfs . file_data , zippedfs . file_size ) ;
/* 6. do a checksum run, and compute checksum */
chkSum = getCheckSum ( image . file_data , image . file_size ) ;
DBG ( " Checksum for Image: %hhX \n " , chkSum ) ;
/* 7. write the checksum inverted into byte 511 to bring it to 0 on verification */
chkSum = ( chkSum ^ 0xFF ) + 1 ;
image . file_data [ 511 ] = ( char ) chkSum ;
chkSum = getCheckSum ( image . file_data , image . file_size ) ;
DBG ( " Checksum for after fix: %hhX \n " , chkSum ) ;
if ( chkSum ! = 0 ) {
ERR ( " Invalid checksum! \n " )
goto cleanup ;
}
/* 8. pray that the updater will accept the file */
if ( writeFile ( & image ) ) {
/* Error */
goto cleanup ;
}
/* All seems OK */
ret = 0 ;
cleanup :
if ( rootfs . file_name & & ! access ( rootfs . file_name , F_OK | W_OK ) )
remove ( rootfs . file_name ) ;
if ( zippedfs . file_name & & ! access ( zippedfs . file_name , F_OK | W_OK ) )
remove ( zippedfs . file_name ) ;
fi_clean ( & sysupgrade ) ;
fi_clean ( & header ) ;
fi_clean ( & rootfs ) ;
fi_clean ( & zippedfs ) ;
fi_clean ( & image ) ;
if ( rootfsname )
free ( rootfsname ) ;
if ( zipfsname )
free ( zipfsname ) ;
if ( zipcmd )
free ( zipcmd ) ;
return ret ;
return EXIT_SUCCESS ;
}
}