tplink-safeloader: add support to convert factory into sysupgrade
Those converted factory images can be used to regain the original tp-link firmware. Be aware of firmware upgrade which additional require changes of other partition than os-image (kernel) & file-system (rootfs). OEM factory images from tplink can change nearly all partitions. However using those images, OpenWrt's sysupgrade will only modify the partitions os-image and file-system. Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
This commit is contained in:
parent
638e2193fe
commit
068ba612db
1 changed files with 103 additions and 3 deletions
|
@ -1392,7 +1392,8 @@ static void usage(const char *argv0) {
|
||||||
" -S create sysupgrade instead of factory image\n"
|
" -S create sysupgrade instead of factory image\n"
|
||||||
"Extract an old image:\n"
|
"Extract an old image:\n"
|
||||||
" -x <file> extract all oem firmware partition\n"
|
" -x <file> extract all oem firmware partition\n"
|
||||||
" -d <dir> destination to extract the firmware partition\n",
|
" -d <dir> destination to extract the firmware partition\n"
|
||||||
|
" -z <file> convert an oem firmware into a sysupgade file. Use -o for output file\n",
|
||||||
argv0
|
argv0
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1632,9 +1633,100 @@ static int extract_firmware(const char *input, const char *output_directory)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct flash_partition_entry *find_partition(
|
||||||
|
struct flash_partition_entry *entries, size_t max_entries,
|
||||||
|
const char *name, const char *error_msg)
|
||||||
|
{
|
||||||
|
for (int i=0; i<max_entries; i++, entries++) {
|
||||||
|
if (strcmp(entries->name, name) == 0)
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
error(1, 0, "%s", error_msg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_ff(FILE *output_file, size_t size)
|
||||||
|
{
|
||||||
|
char buf[4096];
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
memset(buf, 0xff, sizeof(buf));
|
||||||
|
|
||||||
|
for (offset = 0; offset + sizeof(buf) < size ; offset += sizeof(buf)) {
|
||||||
|
if (fwrite(buf, sizeof(buf), 1, output_file) < 0)
|
||||||
|
error(1, errno, "Can not write 0xff to output_file");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write last chunk smaller than buffer */
|
||||||
|
if (offset < size) {
|
||||||
|
offset = size - offset;
|
||||||
|
if (fwrite(buf, offset, 1, output_file) < 0)
|
||||||
|
error(1, errno, "Can not write partition to output_file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void convert_firmware(const char *input, const char *output)
|
||||||
|
{
|
||||||
|
struct flash_partition_entry fwup[MAX_PARTITIONS] = { 0 };
|
||||||
|
struct flash_partition_entry flash[MAX_PARTITIONS] = { 0 };
|
||||||
|
struct flash_partition_entry *fwup_os_image = NULL, *fwup_file_system = NULL;
|
||||||
|
struct flash_partition_entry *flash_os_image = NULL, *flash_file_system = NULL;
|
||||||
|
struct flash_partition_entry *fwup_partition_table = NULL;
|
||||||
|
size_t firmware_offset = 0x1014;
|
||||||
|
FILE *input_file, *output_file;
|
||||||
|
|
||||||
|
struct stat statbuf;
|
||||||
|
|
||||||
|
/* check input file */
|
||||||
|
if (stat(input, &statbuf)) {
|
||||||
|
error(1, errno, "Can not read input firmware %s", input);
|
||||||
|
}
|
||||||
|
|
||||||
|
input_file = fopen(input, "rb");
|
||||||
|
if (!input_file)
|
||||||
|
error(1, 0, "Can not open input firmware %s", input);
|
||||||
|
|
||||||
|
output_file = fopen(output, "wb");
|
||||||
|
if (!output_file)
|
||||||
|
error(1, 0, "Can not open output firmware %s", output);
|
||||||
|
|
||||||
|
if (read_partition_table(input_file, firmware_offset, fwup, MAX_PARTITIONS, 0) != 0) {
|
||||||
|
error(1, 0, "Error can not read the partition table (fwup-ptn)");
|
||||||
|
}
|
||||||
|
|
||||||
|
fwup_os_image = find_partition(fwup, MAX_PARTITIONS,
|
||||||
|
"os-image", "Error can not find os-image partition (fwup)");
|
||||||
|
fwup_file_system = find_partition(fwup, MAX_PARTITIONS,
|
||||||
|
"file-system", "Error can not find file-system partition (fwup)");
|
||||||
|
fwup_partition_table = find_partition(fwup, MAX_PARTITIONS,
|
||||||
|
"partition-table", "Error can not find partition-table partition");
|
||||||
|
|
||||||
|
/* the flash partition table has a 0x00000004 magic haeder */
|
||||||
|
if (read_partition_table(input_file, firmware_offset + fwup_partition_table->base + 4, flash, MAX_PARTITIONS, 1) != 0)
|
||||||
|
error(1, 0, "Error can not read the partition table (flash)");
|
||||||
|
|
||||||
|
flash_os_image = find_partition(flash, MAX_PARTITIONS,
|
||||||
|
"os-image", "Error can not find os-image partition (flash)");
|
||||||
|
flash_file_system = find_partition(flash, MAX_PARTITIONS,
|
||||||
|
"file-system", "Error can not find file-system partition (flash)");
|
||||||
|
|
||||||
|
/* write os_image to 0x0 */
|
||||||
|
write_partition(input_file, firmware_offset, fwup_os_image, output_file);
|
||||||
|
write_ff(output_file, flash_os_image->size - fwup_os_image->size);
|
||||||
|
|
||||||
|
/* write file-system behind os_image */
|
||||||
|
fseek(output_file, flash_file_system->base - flash_os_image->base, SEEK_SET);
|
||||||
|
write_partition(input_file, firmware_offset, fwup_file_system, output_file);
|
||||||
|
write_ff(output_file, flash_file_system->size - fwup_file_system->size);
|
||||||
|
|
||||||
|
fclose(output_file);
|
||||||
|
fclose(input_file);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
const char *board = NULL, *kernel_image = NULL, *rootfs_image = NULL, *output = NULL;
|
const char *board = NULL, *kernel_image = NULL, *rootfs_image = NULL, *output = NULL;
|
||||||
const char *extract_image = NULL, *output_directory = NULL;
|
const char *extract_image = NULL, *output_directory = NULL, *convert_image = NULL;
|
||||||
bool add_jffs2_eof = false, sysupgrade = false;
|
bool add_jffs2_eof = false, sysupgrade = false;
|
||||||
unsigned rev = 0;
|
unsigned rev = 0;
|
||||||
const struct device_info *info;
|
const struct device_info *info;
|
||||||
|
@ -1643,7 +1735,7 @@ int main(int argc, char *argv[]) {
|
||||||
while (true) {
|
while (true) {
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
c = getopt(argc, argv, "B:k:r:o:V:jSh:x:d:");
|
c = getopt(argc, argv, "B:k:r:o:V:jSh:x:d:z:");
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1688,6 +1780,10 @@ int main(int argc, char *argv[]) {
|
||||||
extract_image = optarg;
|
extract_image = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'z':
|
||||||
|
convert_image = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -1700,6 +1796,10 @@ int main(int argc, char *argv[]) {
|
||||||
if (!output_directory)
|
if (!output_directory)
|
||||||
error(1, 0, "Can not extract an image without output directory. Use -d <dir>");
|
error(1, 0, "Can not extract an image without output directory. Use -d <dir>");
|
||||||
extract_firmware(extract_image, output_directory);
|
extract_firmware(extract_image, output_directory);
|
||||||
|
} else if (convert_image) {
|
||||||
|
if (!output)
|
||||||
|
error(1, 0, "Can not convert a factory/oem image into sysupgrade image without output file. Use -o <file>");
|
||||||
|
convert_firmware(convert_image, output);
|
||||||
} else {
|
} else {
|
||||||
if (!board)
|
if (!board)
|
||||||
error(1, 0, "no board has been specified");
|
error(1, 0, "no board has been specified");
|
||||||
|
|
Loading…
Reference in a new issue