[PATCH 1/2] dfu_file.c: Add parsing of DFU file suffix

Tormod Volden lists.tormod at gmail.com
Sat May 21 01:49:14 CEST 2011


From: Tormod Volden <debian.tormod at gmail.com>

The new dfu_file structure is used to keep track of the download (or
upload) file. parse_dfu_suffix() will parse an (already opened) file and
populate the struct members corresponding to the DFU suffix fields.

The commit also includes some verification of the suffix fields,
but at this point only warns about mismatches, with one exception:
If there is a valid DFU suffix, it must have DFU revision 1.0,
otherwise we abort the download.

Signed-off-by: Tormod Volden <debian.tormod at gmail.com>
---

Hi,

This patch is for the libusb-1.0 branch. I have done some testing, but
since I don't have any really DFU compliant device, more testing is
welcome. Currently the print_dfu_if fix from master must be merged
or cherry-picked as well.

Tormod

 src/Makefile.am |    2 +
 src/dfu_file.c  |   97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/dfu_file.h  |   20 +++++++++++
 src/main.c      |   51 ++++++++++++++++++++--------
 4 files changed, 155 insertions(+), 15 deletions(-)
 create mode 100644 src/dfu_file.c
 create mode 100644 src/dfu_file.h

diff --git a/src/Makefile.am b/src/Makefile.am
index 7f9c211..0674413 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -7,5 +7,7 @@ dfu_util_SOURCES = main.c \
 		dfu.c \
 		dfu.h \
 		usb_dfu.h \
+		dfu_file.c \
+		dfu_file.h \
 		quirks.c \
 		quirks.h
diff --git a/src/dfu_file.c b/src/dfu_file.c
new file mode 100644
index 0000000..a2bbe83
--- /dev/null
+++ b/src/dfu_file.c
@@ -0,0 +1,97 @@
+/*
+ * Checks for and parses a DFU suffix
+ *
+ * (C) 2011 Tormod Volden <debian.tormod at gmail.com>
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include "dfu_file.h"
+
+/* reads the fd and name member, fills in all others */
+/* returns 0 if no DFU suffix */
+/* returns positive if valid DFU suffix */
+/* returns negative on file read error */
+int parse_dfu_suffix(struct dfu_file *file)
+{
+    int ret;
+    struct stat st;
+    /* supported suffices are at least 16 bytes */
+    unsigned char dfusuffix[16];
+
+    file->size = 0;
+    /* default values, if no valid suffix is found */
+    file->dwCRC = 0;
+    file->suffixlen = 0;
+    file->bcdDFU = 0;
+    file->idVendor = 0xffff; /* wildcard value */
+    file->idProduct = 0xffff; /* wildcard value */
+    file->bcdDevice = 0xffff; /* wildcard value */
+
+    ret = fstat(file->fd, &st);
+    if (ret < 0) {
+	perror(file->name);
+	return ret;
+    }
+
+    file->size = st.st_size;
+    if (file->size < sizeof(dfusuffix)) {
+	fprintf(stderr, "File too short for DFU suffix\n");
+	return 0;
+    }
+
+    ret = lseek(file->fd, -sizeof(dfusuffix), SEEK_END);
+    if (ret < 0) {
+	fprintf(stderr, "Could not seek to DFU suffix\n");
+	perror(file->name);
+	goto rewind;
+    }
+
+    ret = read(file->fd, dfusuffix, sizeof(dfusuffix));
+    if (ret < 0) {
+	fprintf(stderr, "Could not read DFU suffix\n");
+	perror(file->name);
+	goto rewind;
+    } else if (ret < sizeof(dfusuffix)) {
+	fprintf(stderr, "Could not read whole DFU suffix\n");
+	ret = -EIO;
+	goto rewind;
+    }
+
+    if (dfusuffix[10] != 'D' ||
+        dfusuffix[9]  != 'F' ||
+        dfusuffix[8]  != 'U') {
+	fprintf(stderr, "No valid DFU suffix signature\n");
+	ret = 0;
+	goto rewind;
+    }
+
+    file->dwCRC = (dfusuffix[15] << 24) +
+		  (dfusuffix[14] << 16) +
+		  (dfusuffix[13] << 8) +
+		   dfusuffix[12];
+
+    file->bcdDFU = (dfusuffix[7] << 8) + dfusuffix[6];
+    printf("Dfu suffix version %x\n", file->bcdDFU);
+
+    file->suffixlen = dfusuffix[11];
+    if (file->suffixlen < sizeof(dfusuffix)) {
+	fprintf(stderr, "Unsupported DFU suffix length %i\n", file->suffixlen);
+	ret = 0;
+	goto rewind;
+    }
+
+    file->idVendor = (dfusuffix[5] << 8) + dfusuffix[4];
+    file->idProduct = (dfusuffix[3] << 8) + dfusuffix[2];
+    file->bcdDevice = (dfusuffix[1] << 8) + dfusuffix[0];
+
+rewind:
+    lseek(file->fd, 0, SEEK_SET);
+    return ret;
+}
+
diff --git a/src/dfu_file.h b/src/dfu_file.h
new file mode 100644
index 0000000..8c33665
--- /dev/null
+++ b/src/dfu_file.h
@@ -0,0 +1,20 @@
+
+#ifndef _DFU_FILE_H
+#define _DFU_FILE_H
+
+struct dfu_file {
+    const char *name;
+    int fd;
+    off_t size;
+    /* From DFU suffix fields */
+    u_int32_t dwCRC;
+    unsigned char suffixlen;
+    u_int16_t bcdDFU;
+    u_int16_t idVendor;
+    u_int16_t idProduct;
+    u_int16_t bcdDevice;
+};
+
+int parse_dfu_suffix(struct dfu_file *file);
+
+#endif
diff --git a/src/main.c b/src/main.c
index e72222e..5e27fc7 100644
--- a/src/main.c
+++ b/src/main.c
@@ -32,6 +32,7 @@
 
 #include "dfu.h"
 #include "usb_dfu.h"
+#include "dfu_file.h"
 #include "dfu_load.h"
 #include "quirks.h"
 #ifdef HAVE_CONFIG_H
@@ -464,8 +465,7 @@ int main(int argc, char **argv)
 	struct dfu_status status;
 	struct usb_dfu_func_descriptor func_dfu;
 	libusb_context *ctx;
-	char *filename = NULL;
-	int fd;
+	struct dfu_file file;
 	char *alt_name = NULL; /* query alt name if non-NULL */
 	char *end;
 	int final_reset = 0;
@@ -478,6 +478,7 @@ int main(int argc, char **argv)
 
 	host_page_size = getpagesize();
 	memset(dif, 0, sizeof(*dif));
+	file.name = NULL;
 
 	ret = libusb_init(&ctx);
 	if (ret) {
@@ -557,11 +558,11 @@ int main(int argc, char **argv)
 			break;
 		case 'U':
 			mode = MODE_UPLOAD;
-			filename = optarg;
+			file.name = optarg;
 			break;
 		case 'D':
 			mode = MODE_DOWNLOAD;
-			filename = optarg;
+			file.name = optarg;
 			break;
 		case 'R':
 			final_reset = 1;
@@ -578,7 +579,7 @@ int main(int argc, char **argv)
 		exit(2);
 	}
 
-	if (!filename) {
+	if (!file.name) {
 		fprintf(stderr, "You need to specify a filename to -D or -U\n");
 		help();
 		exit(2);
@@ -869,24 +870,44 @@ status_again:
 
 	switch (mode) {
 	case MODE_UPLOAD:
-		fd = open(filename, O_WRONLY|O_CREAT|O_EXCL, 0644);
-		if (fd < 0) {
-			perror(filename);
+		file.fd = open(file.name, O_WRONLY|O_CREAT|O_EXCL, 0644);
+		if (file.fd < 0) {
+			perror(file.name);
 			exit(1);
 		}
-		if (dfuload_do_upload(dif, transfer_size, fd) < 0)
+		if (dfuload_do_upload(dif, transfer_size, file.fd) < 0)
 			exit(1);
-		close(fd);
+		close(file.fd);
 		break;
 	case MODE_DOWNLOAD:
-		fd = open(filename, O_RDONLY|O_BINARY);
-		if (fd < 0) {
-			perror(filename);
+		file.fd = open(file.name, O_RDONLY|O_BINARY);
+		if (file.fd < 0) {
+			perror(file.name);
 			exit(1);
 		}
-		if (dfuload_do_dnload(dif, transfer_size, fd) < 0)
+		ret = parse_dfu_suffix(&file);
+		if (ret < 0) {
+			exit(1);
+		} else if (ret == 0) {
+			fprintf(stderr, "Warning: File has no DFU suffix\n");
+		} else if (file.bcdDFU != 0x0100) {
+			fprintf(stderr, "Unsupported DFU file revision "
+				"%04x\n", file.bcdDFU);
+			exit(1);
+		}
+		if (file.idVendor != 0xffff &&
+		    dif->vendor != file.idVendor) {
+			fprintf(stderr, "Warning: File vendor ID %04x does "
+				"not match device\n", file.idVendor);
+		}
+		if (file.idProduct != 0xffff &&
+		    dif->product != file.idProduct) {
+			fprintf(stderr, "Warning: File product ID %04x does "
+				"not match device\n", file.idProduct);
+		}
+		if (dfuload_do_dnload(dif, transfer_size, file.fd) < 0)
 			exit(1);
-		close(fd);
+		close(file.fd);
 		break;
 	default:
 		fprintf(stderr, "Unsupported mode: %u\n", mode);
-- 
1.7.0.4




More information about the devel mailing list