diff --git a/modem/tqftpserv/0001-tqftpserv-allow-sending-data-packet-with-0-byte-data.patch b/modem/tqftpserv/0001-tqftpserv-allow-sending-data-packet-with-0-byte-data.patch new file mode 100644 index 000000000..95c7428d9 --- /dev/null +++ b/modem/tqftpserv/0001-tqftpserv-allow-sending-data-packet-with-0-byte-data.patch @@ -0,0 +1,42 @@ +From 891ed4143eada69d031360c214142c8e46222e8a Mon Sep 17 00:00:00 2001 +From: Luca Weiss +Date: Fri, 19 Jan 2024 17:09:17 +0100 +Subject: [PATCH 1/5] tqftpserv: allow sending data packet with 0-byte data + payload + +If the client requests a file that's completely empty, it makes sense to +send a response to that request with - well - 0 bytes of data and just +the 4-byte header. + +But also if the client requests for example a file of rsize=53760 and +blksize=7680, then will send 7 full packets of data in the window, but +afterwards we still need to send an empty packet (just the 4 bytes of +header) to make sure the client understands that we've sent all the +requested data. Otherwise it's going to time out and re-request the +blocks and we're stuck in a loop. + +So consider pread return value of 0 to not be an error and send a +response packet back. +--- + tqftpserv.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/tqftpserv.c b/tqftpserv.c +index 4ba287c..9d1a2b3 100644 +--- a/tqftpserv.c ++++ b/tqftpserv.c +@@ -89,9 +89,8 @@ static ssize_t tftp_send_data(struct tftp_client *client, + *p++ = block & 0xff; + + len = pread(client->fd, p, client->blksize, offset); +- if (len <= 0) { +- if (len < 0) +- printf("[TQFTP] failed to read data\n"); ++ if (len < 0) { ++ printf("[TQFTP] failed to read data\n"); + free(buf); + return len; + } +-- +2.44.0 + diff --git a/modem/tqftpserv/0002-tqftpserv-add-seek-option-parsing.patch b/modem/tqftpserv/0002-tqftpserv-add-seek-option-parsing.patch new file mode 100644 index 000000000..80e21db81 --- /dev/null +++ b/modem/tqftpserv/0002-tqftpserv-add-seek-option-parsing.patch @@ -0,0 +1,148 @@ +From e6fc5c5cabd210317ac6acae185416eeaf2a83d9 Mon Sep 17 00:00:00 2001 +From: Luca Weiss +Date: Fri, 10 Feb 2023 14:23:34 +0100 +Subject: [PATCH 2/5] tqftpserv: add seek option parsing + +Actual handling will be added in follow-up commits as rsize is also not +currently handled, and both are quite interconnected. +--- + tqftpserv.c | 32 ++++++++++++++++++++++++++------ + 1 file changed, 26 insertions(+), 6 deletions(-) + +diff --git a/tqftpserv.c b/tqftpserv.c +index 9d1a2b3..eed99a1 100644 +--- a/tqftpserv.c ++++ b/tqftpserv.c +@@ -67,6 +67,7 @@ struct tftp_client { + size_t rsize; + size_t wsize; + unsigned int timeoutms; ++ off_t seek; + }; + + static struct list_head readers = LIST_INIT(readers); +@@ -117,7 +118,8 @@ static int tftp_send_ack(int sock, int block) + } + + static int tftp_send_oack(int sock, size_t *blocksize, size_t *tsize, +- size_t *wsize, unsigned int *timeoutms, size_t *rsize) ++ size_t *wsize, unsigned int *timeoutms, size_t *rsize, ++ off_t *seek) + { + char buf[512]; + char *p = buf; +@@ -171,6 +173,15 @@ static int tftp_send_oack(int sock, size_t *blocksize, size_t *tsize, + *p++ = '\0'; + } + ++ if (seek) { ++ strcpy(p, "seek"); ++ p += 5; ++ ++ n = sprintf(p, "%zd", *seek); ++ p += n; ++ *p++ = '\0'; ++ } ++ + return send(sock, buf, p - buf, 0); + } + +@@ -197,7 +208,7 @@ static int tftp_send_error(int sock, int code, const char *msg) + + static void parse_options(const char *buf, size_t len, size_t *blksize, + ssize_t *tsize, size_t *wsize, unsigned int *timeoutms, +- size_t *rsize) ++ size_t *rsize, off_t *seek) + { + const char *opt, *value; + const char *p = buf; +@@ -217,6 +228,7 @@ static void parse_options(const char *buf, size_t len, size_t *blksize, + * tsize: total size - request to get file size in bytes + * rsize: read size - how many bytes to send, not full file + * wsize: window size - how many blocks to send without ACK ++ * seek: offset from beginning of file in bytes to start reading + */ + if (!strcmp(opt, "blksize")) { + *blksize = atoi(value); +@@ -228,6 +240,8 @@ static void parse_options(const char *buf, size_t len, size_t *blksize, + *rsize = atoi(value); + } else if (!strcmp(opt, "wsize")) { + *wsize = atoi(value); ++ } else if (!strcmp(opt, "seek")) { ++ *seek = atoi(value); + } else { + printf("[TQFTP] Ignoring unknown option '%s' with value '%s'\n", opt, value); + } +@@ -246,6 +260,7 @@ static void handle_rrq(const char *buf, size_t len, struct sockaddr_qrtr *sq) + unsigned int timeoutms = 1000; + size_t rsize = 0; + size_t wsize = 0; ++ off_t seek = 0; + bool do_oack = false; + int sock; + int ret; +@@ -270,7 +285,7 @@ static void handle_rrq(const char *buf, size_t len, struct sockaddr_qrtr *sq) + if (p < buf + len) { + do_oack = true; + parse_options(p, len - (p - buf), &blksize, &tsize, &wsize, +- &timeoutms, &rsize); ++ &timeoutms, &rsize, &seek); + } + + sock = qrtr_open(0); +@@ -307,6 +322,7 @@ static void handle_rrq(const char *buf, size_t len, struct sockaddr_qrtr *sq) + client->rsize = rsize; + client->wsize = wsize; + client->timeoutms = timeoutms; ++ client->seek = seek; + + // printf("[TQFTP] new reader added\n"); + +@@ -317,7 +333,8 @@ static void handle_rrq(const char *buf, size_t len, struct sockaddr_qrtr *sq) + tsize ? (size_t*)&tsize : NULL, + wsize ? &wsize : NULL, + &client->timeoutms, +- rsize ? &rsize: NULL); ++ rsize ? &rsize : NULL, ++ seek ? &seek : NULL); + } else { + tftp_send_data(client, 1, 0); + } +@@ -334,6 +351,7 @@ static void handle_wrq(const char *buf, size_t len, struct sockaddr_qrtr *sq) + unsigned int timeoutms = 1000; + size_t rsize = 0; + size_t wsize = 0; ++ off_t seek = 0; + bool do_oack = false; + int sock; + int ret; +@@ -354,7 +372,7 @@ static void handle_wrq(const char *buf, size_t len, struct sockaddr_qrtr *sq) + if (p < buf + len) { + do_oack = true; + parse_options(p, len - (p - buf), &blksize, &tsize, &wsize, +- &timeoutms, &rsize); ++ &timeoutms, &rsize, &seek); + } + + fd = translate_open(filename, O_WRONLY | O_CREAT); +@@ -386,6 +404,7 @@ static void handle_wrq(const char *buf, size_t len, struct sockaddr_qrtr *sq) + client->rsize = rsize; + client->wsize = wsize; + client->timeoutms = timeoutms; ++ client->seek = seek; + + // printf("[TQFTP] new writer added\n"); + +@@ -396,7 +415,8 @@ static void handle_wrq(const char *buf, size_t len, struct sockaddr_qrtr *sq) + tsize ? (size_t*)&tsize : NULL, + wsize ? &wsize : NULL, + &client->timeoutms, +- rsize ? &rsize: NULL); ++ rsize ? &rsize : NULL, ++ seek ? &seek : NULL); + } else { + tftp_send_data(client, 1, 0); + } +-- +2.44.0 + diff --git a/modem/tqftpserv/0003-tqftpserv-handle-rsize-offset-options.patch b/modem/tqftpserv/0003-tqftpserv-handle-rsize-offset-options.patch new file mode 100644 index 000000000..b61fdc3bc --- /dev/null +++ b/modem/tqftpserv/0003-tqftpserv-handle-rsize-offset-options.patch @@ -0,0 +1,117 @@ +From c56fa600c6c94950edafa157843e1891df523084 Mon Sep 17 00:00:00 2001 +From: Luca Weiss +Date: Fri, 19 Jan 2024 14:15:34 +0100 +Subject: [PATCH 3/5] tqftpserv: handle rsize & offset options + +The rsize (number of bytes the client wants to receive) and offset (the +offset in bytes from the start of file) are used on newer modems (such +as SM7225 or QCM6490), so let's support them properly. + +Some examples to illustrate the usage: +* rsize=160 seek=52: we should send 160 bytes starting at byte 52 in the + requested file. With blksize=7680 this is a single 160(+4) sized + packet. +* rsize=313028 seek=81920: we should send in total 313028 bytes, + starting at byte 81920. With blksize=7680 and wsize=10 this spans + multiple windows of 10 packets each, that example would be packed into + 41 packets with an ACK between every 10 windows - and a final ACK at + the end. +* rsize=53760 blksize=7680: We send 7 packets of 7680 bytes each, then + we send 1 packet with 0 bytes of data (only 4 bytes header) and then + get an ACK on packet 8. +--- + tqftpserv.c | 39 +++++++++++++++++++++++++++++++++------ + 1 file changed, 33 insertions(+), 6 deletions(-) + +diff --git a/tqftpserv.c b/tqftpserv.c +index eed99a1..b931346 100644 +--- a/tqftpserv.c ++++ b/tqftpserv.c +@@ -74,9 +74,10 @@ static struct list_head readers = LIST_INIT(readers); + static struct list_head writers = LIST_INIT(writers); + + static ssize_t tftp_send_data(struct tftp_client *client, +- unsigned int block, size_t offset) ++ unsigned int block, size_t offset, size_t rsize) + { + ssize_t len; ++ size_t send_len; + char *buf; + char *p; + +@@ -98,8 +99,21 @@ static ssize_t tftp_send_data(struct tftp_client *client, + + p += len; + +- // printf("[TQFTP] Sending %zd bytes of DATA\n", p - buf); +- len = send(client->sock, buf, p - buf, 0); ++ /* If rsize was set, we should limit the data in the response to n bytes */ ++ if (rsize != 0) { ++ /* Header (4 bytes) + data size */ ++ send_len = 4 + rsize; ++ if (send_len > p - buf) { ++ printf("[TQFTP] requested data of %ld bytes but only read %ld bytes from file, rejecting\n", rsize, len); ++ free(buf); ++ return -EINVAL; ++ } ++ } else { ++ send_len = p - buf; ++ } ++ ++ // printf("[TQFTP] Sending %zd bytes of DATA\n", send_len); ++ len = send(client->sock, buf, send_len, 0); + + free(buf); + +@@ -336,7 +350,7 @@ static void handle_rrq(const char *buf, size_t len, struct sockaddr_qrtr *sq) + rsize ? &rsize : NULL, + seek ? &seek : NULL); + } else { +- tftp_send_data(client, 1, 0); ++ tftp_send_data(client, 1, 0, 0); + } + } + +@@ -418,7 +432,7 @@ static void handle_wrq(const char *buf, size_t len, struct sockaddr_qrtr *sq) + rsize ? &rsize : NULL, + seek ? &seek : NULL); + } else { +- tftp_send_data(client, 1, 0); ++ tftp_send_data(client, 1, 0, 0); + } + } + +@@ -463,9 +477,19 @@ static int handle_reader(struct tftp_client *client) + last = buf[2] << 8 | buf[3]; + // printf("[TQFTP] Got ack for %d\n", last); + ++ /* We've sent enough data for rsize already */ ++ if (last * client->blksize > client->rsize) ++ return 0; ++ + for (block = last; block < last + client->wsize; block++) { ++ size_t offset = client->seek + block * client->blksize; ++ size_t rsize = 0; ++ /* Check if need to limit response size based for requested rsize */ ++ if (block * client->blksize + client->blksize > client->rsize) ++ rsize = client->rsize - (block * client->blksize); ++ + n = tftp_send_data(client, block + 1, +- block * client->blksize); ++ offset, rsize); + if (n < 0) { + printf("[TQFTP] Sent block %d failed: %zd\n", block + 1, n); + break; +@@ -473,6 +497,9 @@ static int handle_reader(struct tftp_client *client) + // printf("[TQFTP] Sent block %d of %zd\n", block + 1, n); + if (n == 0) + break; ++ /* We've sent enough data for rsize already */ ++ if (block * client->blksize + client->blksize > client->rsize) ++ break; + } + + return 1; +-- +2.44.0 + diff --git a/modem/tqftpserv/0004-tqftpserv-add-rsize-offset-options-to-RRQ-print.patch b/modem/tqftpserv/0004-tqftpserv-add-rsize-offset-options-to-RRQ-print.patch new file mode 100644 index 000000000..0d122470c --- /dev/null +++ b/modem/tqftpserv/0004-tqftpserv-add-rsize-offset-options-to-RRQ-print.patch @@ -0,0 +1,35 @@ +From 9febe891d2c98544cea4800561e8f25eb8f1a6a9 Mon Sep 17 00:00:00 2001 +From: Luca Weiss +Date: Fri, 19 Jan 2024 14:16:29 +0100 +Subject: [PATCH 4/5] tqftpserv: add rsize & offset options to RRQ print + +Since new modems send multiple file requests with different rsize and +offset on a single file, it's useful to print those also. +--- + tqftpserv.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tqftpserv.c b/tqftpserv.c +index b931346..95b4824 100644 +--- a/tqftpserv.c ++++ b/tqftpserv.c +@@ -294,14 +294,14 @@ static void handle_rrq(const char *buf, size_t len, struct sockaddr_qrtr *sq) + return; + } + +- printf("[TQFTP] RRQ: %s (%s)\n", filename, mode); +- + if (p < buf + len) { + do_oack = true; + parse_options(p, len - (p - buf), &blksize, &tsize, &wsize, + &timeoutms, &rsize, &seek); + } + ++ printf("[TQFTP] RRQ: %s (mode=%s rsize=%ld seek=%ld)\n", filename, mode, rsize, seek); ++ + sock = qrtr_open(0); + if (sock < 0) { + /* XXX: error */ +-- +2.44.0 + diff --git a/modem/tqftpserv/0005-tqftpserv-don-t-print-End-of-Transfer-as-an-error.patch b/modem/tqftpserv/0005-tqftpserv-don-t-print-End-of-Transfer-as-an-error.patch new file mode 100644 index 000000000..baa4884ab --- /dev/null +++ b/modem/tqftpserv/0005-tqftpserv-don-t-print-End-of-Transfer-as-an-error.patch @@ -0,0 +1,40 @@ +From 0ae406219bce1c93e63f6892efd2e34306131428 Mon Sep 17 00:00:00 2001 +From: Luca Weiss +Date: Fri, 19 Jan 2024 14:25:34 +0100 +Subject: [PATCH 5/5] tqftpserv: don't print "End of Transfer" as an error + +On newer modems, the firmware seems to use a stat-like operation +relatively often which end the transfer with error 9 "End of Transfer". + +In practise we're getting a RRQ with the tsize option set, we'll query +the file size from the filesystem, respond with the updated tsize in +OACK, then the modem will send us OP_ERROR with code 9 "End of +Transfer". + +Since that's expected in this operation, let's not make it look like an +error to not confuse users/developers trying to debug the modem. +--- + tqftpserv.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/tqftpserv.c b/tqftpserv.c +index 95b4824..4a1bd30 100644 +--- a/tqftpserv.c ++++ b/tqftpserv.c +@@ -467,7 +467,12 @@ static int handle_reader(struct tftp_client *client) + opcode = buf[0] << 8 | buf[1]; + if (opcode == OP_ERROR) { + buf[len] = '\0'; +- printf("[TQFTP] Remote returned an error: %d - %s\n", buf[2] << 8 | buf[3], buf + 4); ++ int err = buf[2] << 8 | buf[3]; ++ /* "End of Transfer" is not an error, used with stat(2)-like calls */ ++ if (err == 9) ++ printf("[TQFTP] Remote returned END OF TRANSFER: %d - %s\n", err, buf + 4); ++ else ++ printf("[TQFTP] Remote returned an error: %d - %s\n", err, buf + 4); + return -1; + } else if (opcode != OP_ACK) { + printf("[TQFTP] Expected ACK, got %d\n", opcode); +-- +2.44.0 + diff --git a/modem/tqftpserv/APKBUILD b/modem/tqftpserv/APKBUILD index 6c4ece088..5e2071d63 100644 --- a/modem/tqftpserv/APKBUILD +++ b/modem/tqftpserv/APKBUILD @@ -1,8 +1,8 @@ # Maintainer: Dolphin von Chips pkgname=tqftpserv -pkgver=0_git20200207 -pkgrel=2 -_commit="783425b550de2a359db6aa3b41577c3fbaae5903" +pkgver=0_git20240122 +pkgrel=0 +_commit="289214a5d152c0f2fcd57fcad274d037480d220b" pkgdesc="Trivial File Transfer Protocol server over AF_QIPCRTR" url="https://github.com/andersson/tqftpserv" arch="all" @@ -10,6 +10,11 @@ license="BSD-3-Clause" makedepends="qrtr-dev" source="https://github.com/andersson/tqftpserv/archive/$_commit/tqftpserv-$_commit.tar.gz tqftpserv.initd + 0001-tqftpserv-allow-sending-data-packet-with-0-byte-data.patch + 0002-tqftpserv-add-seek-option-parsing.patch + 0003-tqftpserv-handle-rsize-offset-options.patch + 0004-tqftpserv-add-rsize-offset-options-to-RRQ-print.patch + 0005-tqftpserv-don-t-print-End-of-Transfer-as-an-error.patch " subpackages="$pkgname-doc $pkgname-openrc" builddir="$srcdir/tqftpserv-$_commit" @@ -28,6 +33,11 @@ package() { } sha512sums=" -67673664bfea444da50e7ff5e882e68d60cf8a4cec60ecaea68766ed20f0bd66cbdbbee883e362003d252070f67172512aa06bcc2c94f23df9248bb1bf58b552 tqftpserv-783425b550de2a359db6aa3b41577c3fbaae5903.tar.gz +dd9814bef4fbe6184b70446c3ab0c61f212856c69abace1739ef38efb7077a6112adefe6be26109e67ffb8dc0df95f1e6546a92a1d794a867ad0fd0a1d13f9df tqftpserv-289214a5d152c0f2fcd57fcad274d037480d220b.tar.gz 9fde613a1ed53e633ab676e37245d40598deb4b6896c379054389adad5af9f110fcf95871fe31bad3f0ed9321ba3cee8a2160b95e56873719382f81063a85721 tqftpserv.initd +d392f0554bdba666df8a8d7fc8fcf3a584fe8af950ef53132fff901297b39923264f533f77b49a76a1d474112994b57f742470f588761f9b424cb1bd831b4f91 0001-tqftpserv-allow-sending-data-packet-with-0-byte-data.patch +52cd89af5edd09c648e0f9196357dda3d332be6c071703738a92d76ae0e4b1c331370c4bed0b9403d00fc8512e931c7a355d9865353dcddf2fd2e1cb151cb053 0002-tqftpserv-add-seek-option-parsing.patch +d69716e49ba8727178b132fa24946552f8f2ced3364be379d4deed25d585279274bc15c7a74634a5b1767d54684a2dd3d2d90979dbd3262a44fa21167b101823 0003-tqftpserv-handle-rsize-offset-options.patch +530b138b5525d923a40ab449ea77d32ed14751abbccbfa59e7e3b6e0ace4ba3a6b4abe2eedb6218113a8e4026eefd1df4ec34bfed984fbc8ab6b7f234016ffbb 0004-tqftpserv-add-rsize-offset-options-to-RRQ-print.patch +26812c8120bee7d80f8949015420daf67d243710b83ac79139447ae324d34cc0c5ff36d7f8b26316de0469ad5af3cd855cf7884c0d151ae67c0cf24239df6468 0005-tqftpserv-don-t-print-End-of-Transfer-as-an-error.patch "