--- /dev/null
+#include <arpa/inet.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+
+#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;
+}
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 <ip[:port]>, --net=<ip[:port]> Flash device through network connection mode with given IP\n"
" -p <pitfile>, --pitfile=<pitfile> Flash new partition table\n"
" -b <busid>, --busid=<busid> Flash device with given busid\n"
" --vendor-id=<vid> Flash device with given Vendor ID\n"
.usb_dev.vid = -1,
.usb_dev.pid = -1,
.usb_dev.serial = NULL,
+ .net_dev.ip_addr = NULL,
+ .net_dev.port = 0,
};
struct option opts[] = {
{"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},
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;
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;