mtdsplit_uimage: more generic header verify function

Some devices have uImage headers after some extra headers (e.g. Edimax
devices). To support such cases our verify callback function should be
allowed to return header offset, not just a boolean value.

Signed-off-by: Rafał Miłecki <zajec5@gmail.com>

SVN-Revision: 44412
This commit is contained in:
Rafał Miłecki 2015-02-12 06:57:24 +00:00
parent 1f3cdb8634
commit 1aed104c80

View file

@ -71,10 +71,16 @@ read_uimage_header(struct mtd_info *mtd, size_t offset,
return 0; return 0;
} }
/**
* __mtdsplit_parse_uimage - scan partition and create kernel + rootfs parts
*
* @find_header: function to call for a block of data that will return offset
* of a valid uImage header if found
*/
static int __mtdsplit_parse_uimage(struct mtd_info *master, static int __mtdsplit_parse_uimage(struct mtd_info *master,
struct mtd_partition **pparts, struct mtd_partition **pparts,
struct mtd_part_parser_data *data, struct mtd_part_parser_data *data,
bool (*verify)(struct uimage_header *hdr)) ssize_t (*find_header)(u_char *buf, size_t len))
{ {
struct mtd_partition *parts; struct mtd_partition *parts;
struct uimage_header *header; struct uimage_header *header;
@ -106,11 +112,16 @@ static int __mtdsplit_parse_uimage(struct mtd_info *master,
if (ret) if (ret)
continue; continue;
if (!verify(header)) { ret = find_header((u_char *)header, sizeof(*header));
if (ret < 0) {
pr_debug("no valid uImage found in \"%s\" at offset %llx\n", pr_debug("no valid uImage found in \"%s\" at offset %llx\n",
master->name, (unsigned long long) offset); master->name, (unsigned long long) offset);
continue; continue;
} }
if (ret > 0) {
pr_warn("extra header offsets are not supported yet\n");
continue;
}
uimage_size = sizeof(*header) + be32_to_cpu(header->ih_size); uimage_size = sizeof(*header) + be32_to_cpu(header->ih_size);
if ((offset + uimage_size) > master->size) { if ((offset + uimage_size) > master->size) {
@ -189,28 +200,30 @@ err_free_parts:
return ret; return ret;
} }
static bool uimage_verify_default(struct uimage_header *header) static ssize_t uimage_verify_default(u_char *buf, size_t len)
{ {
struct uimage_header *header = (struct uimage_header *)buf;
/* default sanity checks */ /* default sanity checks */
if (be32_to_cpu(header->ih_magic) != IH_MAGIC) { if (be32_to_cpu(header->ih_magic) != IH_MAGIC) {
pr_debug("invalid uImage magic: %08x\n", pr_debug("invalid uImage magic: %08x\n",
be32_to_cpu(header->ih_magic)); be32_to_cpu(header->ih_magic));
return false; return -EINVAL;
} }
if (header->ih_os != IH_OS_LINUX) { if (header->ih_os != IH_OS_LINUX) {
pr_debug("invalid uImage OS: %08x\n", pr_debug("invalid uImage OS: %08x\n",
be32_to_cpu(header->ih_os)); be32_to_cpu(header->ih_os));
return false; return -EINVAL;
} }
if (header->ih_type != IH_TYPE_KERNEL) { if (header->ih_type != IH_TYPE_KERNEL) {
pr_debug("invalid uImage type: %08x\n", pr_debug("invalid uImage type: %08x\n",
be32_to_cpu(header->ih_type)); be32_to_cpu(header->ih_type));
return false; return -EINVAL;
} }
return true; return 0;
} }
static int static int
@ -238,9 +251,11 @@ static struct mtd_part_parser uimage_generic_parser = {
#define FW_MAGIC_WNDR3700 0x33373030 #define FW_MAGIC_WNDR3700 0x33373030
#define FW_MAGIC_WNDR3700V2 0x33373031 #define FW_MAGIC_WNDR3700V2 0x33373031
static bool uimage_verify_wndr3700(struct uimage_header *header) static ssize_t uimage_verify_wndr3700(u_char *buf, size_t len)
{ {
struct uimage_header *header = (struct uimage_header *)buf;
uint8_t expected_type = IH_TYPE_FILESYSTEM; uint8_t expected_type = IH_TYPE_FILESYSTEM;
switch be32_to_cpu(header->ih_magic) { switch be32_to_cpu(header->ih_magic) {
case FW_MAGIC_WNR612V2: case FW_MAGIC_WNR612V2:
case FW_MAGIC_WNR1000V2: case FW_MAGIC_WNR1000V2:
@ -254,14 +269,14 @@ static bool uimage_verify_wndr3700(struct uimage_header *header)
expected_type = IH_TYPE_KERNEL; expected_type = IH_TYPE_KERNEL;
break; break;
default: default:
return false; return -EINVAL;
} }
if (header->ih_os != IH_OS_LINUX || if (header->ih_os != IH_OS_LINUX ||
header->ih_type != expected_type) header->ih_type != expected_type)
return false; return -EINVAL;
return true; return 0;
} }
static int static int