From 00e415f90e602ce21d7f984ebdf303737bd6dd6a Mon Sep 17 00:00:00 2001 From: Dongwoo Lee Date: Wed, 27 Sep 2017 16:17:21 +0900 Subject: [PATCH] Add network transport for image transfer This patch adds network transport which can transfer image via tcp layer. If the option "--net=" is passed, lthor tries to connect the target with given ip and port, or else, it just try to connect via usb. When the port nubmer is not provided for network option, it uses default port. Change-Id: I14bea3523d01e3a4f547e41d40d353790a870460 Signed-off-by: Dongwoo Lee Signed-off-by: Seung-Woo Kim --- CMakeLists.txt | 1 + libthor/thor.h | 9 ++ libthor/thor_net.c | 233 +++++++++++++++++++++++++++++++++++++++++++++++ libthor/thor_transport.c | 5 + libthor/thor_transport.h | 8 ++ lthor.c | 23 ++++- 6 files changed, 277 insertions(+), 2 deletions(-) create mode 100644 libthor/thor_net.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 8528229..4d67887 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,7 @@ SET(LIBTHOR_SRCS libthor/thor_tar.c libthor/thor_transport.c libthor/thor_usb.c + libthor/thor_net.c ) SET(SRCS diff --git a/libthor/thor.h b/libthor/thor.h index 75c918b..e45c7a0 100644 --- a/libthor/thor.h +++ b/libthor/thor.h @@ -28,8 +28,16 @@ struct usb_device_id { const char *serial; }; +#define THOR_NET_PORT (23456) + +struct net_device_id { + const char *ip_addr; + int port; +}; + struct thor_device_id { struct usb_device_id usb_dev; + struct net_device_id net_dev; }; struct thor_device_handle; @@ -71,6 +79,7 @@ typedef void (*thor_next_entry_cb)(thor_device_handle *th, enum thor_transport_type { THOR_TRANSPORT_USB = 0, + THOR_TRANSPORT_NET, THOR_TRANSPORT_MAX, }; diff --git a/libthor/thor_net.c b/libthor/thor_net.c new file mode 100644 index 0000000..08d479f --- /dev/null +++ b/libthor/thor_net.c @@ -0,0 +1,233 @@ +#include +#include +#include +#include +#include +#include + +#include "thor.h" +#include "thor_internal.h" +#include "thor_transport.h" + +#define INVALID_SOCKFD (-1) + +static int thor_net_connect_device(struct net_device_handle *nh, + struct net_device_id *dev_id, + int wait) +{ + struct sockaddr_in server; + int s; + int ret; + +reconnect: + s = socket(AF_INET, SOCK_STREAM, 0); + if (s < 0) + return -EIO; + + memset(&server, 0, sizeof(server)); + + ret = inet_pton(AF_INET, dev_id->ip_addr, &server.sin_addr); + if (ret <= 0) { + fprintf(stderr, "IP addr is not valid:%s\n", dev_id->ip_addr); + close(s); + return -EINVAL; + } + server.sin_family = AF_INET; + server.sin_port = htons(dev_id->port); + + if (connect(s, (struct sockaddr *)&server, sizeof(server)) < 0) { + if (!wait) { + close(s); + return -ENODEV; + } + + sleep(1); + close(s); + goto reconnect; + } + + nh->sock_fd = s; + + return 0; +} + +static int thor_net_open(thor_device_handle *th, + struct thor_device_id *user_dev_id, + int wait) +{ + struct net_device_handle *nh; + struct net_device_id *dev_id = &user_dev_id->net_dev; + int ret; + + if (!dev_id->ip_addr || !dev_id->port) { + fprintf(stderr, "net mode requires --ip-addr and --tcp-port\n"); + return -EINVAL; + } + + nh = calloc(sizeof(*nh), 1); + if (!nh) + return -ENOMEM; + + nh->sock_fd = INVALID_SOCKFD; + + ret = thor_net_connect_device(nh, dev_id, wait); + if (ret) + goto close_dev; + + th->dev_priv = nh; + + return 0; + +close_dev: + th->ops->close(th); + return ret; +} + +static void thor_net_close(thor_device_handle *th) +{ + struct net_device_handle *nh = th->dev_priv; + + if (!nh) + return; + + if (nh->sock_fd >= 0) + close(nh->sock_fd); + + free(nh); + th->dev_priv = NULL; +} + +static int thor_net_send(thor_device_handle *th, unsigned char *buf, + off_t count, int timeout) +{ + struct net_device_handle *nh = th->dev_priv; + ssize_t transferred; + + if (!nh) + return -ENODEV; + + transferred = send(nh->sock_fd, buf, count, 0); + if (transferred < 0) + return transferred; + + if (transferred < (ssize_t)count) + return -EIO; + + return 0; +} + +static int thor_net_recv(thor_device_handle *th, unsigned char *buf, + off_t count, int timeout) +{ + struct net_device_handle *nh = th->dev_priv; + ssize_t transferred; + + if (!nh) + return -ENODEV; + + transferred = recv(nh->sock_fd, buf, count, MSG_WAITALL); + if (transferred < 0) + return transferred; + + if (transferred < (ssize_t)count) + return -EIO; + + return 0; +} + +static int t_thor_net_send_chunk(thor_device_handle *th, unsigned char *chunk, + off_t size, int chunk_number) +{ + struct data_res_pkt resp; + int ret; + + ret = thor_net_send(th, chunk, size, 0); + if (ret < 0) + return ret; + + memset(&resp, 0, DATA_RES_PKT_SIZE); + + ret = thor_net_recv(th, (unsigned char *)&resp, DATA_RES_PKT_SIZE, 0); + if (ret < 0) + return ret; + + if (resp.cnt != chunk_number) + return -EIO; + + return resp.ack; +} + +static int thor_net_send_raw_data(thor_device_handle *th, + struct thor_data_src *data, + off_t trans_unit_size, + thor_progress_cb report_progress, + void *user_data) +{ + struct net_device_handle *nh = th->dev_priv; + unsigned char *chunk; + off_t data_left; + off_t size; + off_t data_sent = 0; + int chunk_number = 1; + int ret; + + if (!nh) + return -ENODEV; + + chunk = malloc(trans_unit_size); + if (!chunk) + return -ENOMEM; + + data_left = data->get_file_length(data); + + while (data_left) { + size = data_left > trans_unit_size ? + trans_unit_size : data_left; + + ret = data->get_block(data, chunk, size); + if (ret < 0 || ret != size) + goto cleanup; + + memset(chunk + size, 0, trans_unit_size - size); + if (th) { + ret = t_thor_net_send_chunk(th, chunk, trans_unit_size, + chunk_number); + if (ret) + goto cleanup; + } + + data_sent += size; + data_left -= size; + ++chunk_number; + if (report_progress) + report_progress(NULL, data, data_sent, data_left, + chunk_number, user_data); + } + + ret = 0; + +cleanup: + free(chunk); + return ret; +} + + +static struct thor_transport_ops thor_net_ops = { + .open = thor_net_open, + .close = thor_net_close, + .send = thor_net_send, + .recv = thor_net_recv, + .send_data = thor_net_send_raw_data, +}; + +int thor_net_init(thor_device_handle *th) +{ + th->ops = &thor_net_ops; + + return 0; +} + +void thor_net_cleanup(thor_device_handle *th) +{ + return; +} diff --git a/libthor/thor_transport.c b/libthor/thor_transport.c index ae8b642..d6817e9 100644 --- a/libthor/thor_transport.c +++ b/libthor/thor_transport.c @@ -28,6 +28,8 @@ int t_thor_init(thor_device_handle *th) switch (th->type) { case THOR_TRANSPORT_USB: return thor_usb_init(th); + case THOR_TRANSPORT_NET: + return thor_net_init(th); default: break; } @@ -41,6 +43,9 @@ void t_thor_cleanup(thor_device_handle *th) case THOR_TRANSPORT_USB: thor_usb_cleanup(th); break; + case THOR_TRANSPORT_NET: + thor_net_cleanup(th); + break; default: break; } diff --git a/libthor/thor_transport.h b/libthor/thor_transport.h index daddc9e..7db1017 100644 --- a/libthor/thor_transport.h +++ b/libthor/thor_transport.h @@ -45,4 +45,12 @@ int thor_usb_init(thor_device_handle *th); void thor_usb_cleanup(thor_device_handle *th); int t_acm_prepare_device(struct usb_device_handle *uh); +/* Net transport */ +struct net_device_handle { + int sock_fd; +}; + +int thor_net_init(thor_device_handle *th); +void thor_net_cleanup(thor_device_handle *th); + #endif /* THOR_TRANSPORT_H__ */ diff --git a/lthor.c b/lthor.c index 964a44e..38a80d4 100644 --- a/lthor.c +++ b/lthor.c @@ -355,11 +355,12 @@ close_dev: static void usage(const char *exename) { fprintf(stderr, - "Usage: %s: [options] [-d port] [-p pitfile] [tar] [tar] ..\n" + "Usage: %s: [options] [-n ip[:port]] [-d port] [-p pitfile] [tar] [tar] ..\n" "Options:\n" " -t, --test Don't flash, just check if given tar files are correct\n" " -v, --verbose Be more verbose\n" " -c, --check Don't flash, just check if given tty port is thor capable\n" + " -n , --net= Flash device through network connection mode with given IP\n" " -p , --pitfile= Flash new partition table\n" " -b , --busid= Flash device with given busid\n" " --vendor-id= Flash device with given Vendor ID\n" @@ -398,6 +399,8 @@ int main(int argc, char **argv) .usb_dev.vid = -1, .usb_dev.pid = -1, .usb_dev.serial = NULL, + .net_dev.ip_addr = NULL, + .net_dev.port = 0, }; struct option opts[] = { @@ -406,6 +409,7 @@ int main(int argc, char **argv) {"check", no_argument, 0, 'c'}, {"port", required_argument, 0, 'd'}, {"pitfile", required_argument, 0, 'p'}, + {"net", required_argument, 0, 'n'}, {"busid", required_argument, 0, 'b'}, {"vendor-id", required_argument, 0, 1}, {"product-id", required_argument, 0, 2}, @@ -422,7 +426,7 @@ int main(int argc, char **argv) exename = argv[0]; while (1) { - opt = getopt_long(argc, argv, "tvcd:p:b:", opts, &optindex); + opt = getopt_long(argc, argv, "tvcd:p:b:n:", opts, &optindex); if (opt == -1) break; @@ -442,6 +446,21 @@ int main(int argc, char **argv) case 'p': pitfile = optarg; break; + case 'n': + { + unsigned long int val; + + type = THOR_TRANSPORT_NET; + dev_id.net_dev.ip_addr = strsep(&optarg, ":"); + + if (optarg) + val = strtoul(optarg, NULL, 0); + else + val = THOR_NET_PORT; + + dev_id.net_dev.port = (int)val; + break; + } case 'b': dev_id.usb_dev.busid = optarg; break; -- 2.7.4