20 Commits
Author SHA1 Message Date
Konrad Dybcio 96f76d8481 treewide: meson 2024-04-23 19:30:30 +02:00
Konrad Dybcio 3a10a7dd6f treewide: use SPDX license IDs 2024-04-08 23:53:19 +02:00
Luca Weiss a09948e5e3 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.
2024-04-08 23:17:36 +02:00
Luca Weiss 588a8d3c8f 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.
2024-04-08 23:17:36 +02:00
Luca Weiss e167336fca 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.
2024-04-08 23:17:36 +02:00
Luca Weiss 69c7cfcf73 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.
2024-04-08 23:17:36 +02:00
Luca Weiss 2dd48a2899 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.
2024-04-08 23:17:36 +02:00
Luca Weiss 98d162c9ff translate: Fix firmware path for 'fallback' case
The dirname() function can and will modify the parameter, so if we call
dirname() twice on the same firmware_value parameter we will get
separate results messing up our names.

Copy the firmware_value value before passing it to dirname(). Also let's
just do this operation once to save copy-pasting some code.

Fixes: a4c755d ("Use firmware path from sysfs")
2024-04-08 22:31:59 +02:00
Konrad Dybcio 37669ab1e2 Merge pull request #12 from minlexx/respect-firmware-sysfs-path
Use firmware path from sysfs
2024-03-27 21:27:08 +01:00
Alexey Minnekhanov a4c755db17 Use firmware path from sysfs
Some linux distributions adjust path fro kernel to load
firmware from using /sys/module/firmware_class/parameters/path.
Kernel supports it, teach tqftpserv to respect it too.

Signed-off-by: Alexey Minnekhanov <alexeymin@postmarketos.org>
2024-03-24 00:00:31 +03:00
Bjorn Andersson 289214a5d1 Merge pull request #11 from z3ntu/misc-improvements
Some improvements for error handling
2024-01-22 09:57:48 -06:00
Luca Weiss 00fe2775de tqftpserv: add docs for options
The explanation is spread throughout various RFCs or the code - or at
least for rsize based on strace'ing the communication.
2024-01-19 11:52:32 +01:00
Luca Weiss fb20008c86 translate: don't try to close already closed class_fd
After calling fdopendir "the file descriptor is under the control of the
system" and calling closedir(class_dir) already closes class_fd, so
let's not try to close it again.

Just close class_fd when fdopendir fails and remove the close call from
the regular exit path.
2024-01-18 15:33:46 +01:00
Luca Weiss a540a1c307 tqftpserv: also print value for unknown options 2023-02-10 13:17:28 +01:00
Luca Weiss 3fa49eafe0 tqftpserv: handle OP_ERROR code
When we get an error from the remote we should print it, for example:

  [TQFTP] received error:  8 - Expected OACK for UNLINK
2023-02-10 12:13:00 +01:00
Luca Weiss aaba76c6ba tqftpserv: also print error code on read error
Along with the error message we also get a uint16 error code that we can
print.
2023-02-10 12:10:46 +01:00
John Stultz de42697a24 translate: Null terminate firmware_value string
Null terminate firmware_value string to prevent
strlen() read past the end of buffer.

Change-Id: I57cd01c4d0c58c6057872bc4b36129f09bc034a3
Signed-off-by: Amit Pundir <amit.pundir@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
2023-01-17 22:57:14 -06:00
Amit Pundir 538efb3096 translate: Use /data/vendor for temporary files
On AOSP, /tmp is not available. Use /data/vendor instead
for temporary files.

Change-Id: I1d6ebd669573b3c3134e6da943ea9355ed83a3fe
Signed-off-by: Amit Pundir <amit.pundir@linaro.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
2023-01-17 22:57:14 -06:00
Sireesh Kodali 48b9e1cbb1 tqftpserv: add support for TFTP options on WRQs 2023-01-17 22:56:21 -06:00
Jami Kettunen 3488007880 Makefile: allow $(CFLAGS), $(LDFLAGS) override
The caller might have specified CFLAGS or LDFLAGS. Let's respect those.
2023-01-17 22:54:25 -06:00
7 changed files with 236 additions and 164 deletions

No files matched your search

-25
View File
@@ -1,25 +0,0 @@
TQFTPSERV := tqftpserv
CFLAGS := -Wall -g -O2
LDFLAGS := -lqrtr
prefix ?= /usr/local
bindir := $(prefix)/bin
servicedir := $(prefix)/lib/systemd/system
SRCS := tqftpserv.c translate.c
OBJS := $(SRCS:.c=.o)
$(TQFTPSERV): $(OBJS)
$(CC) -o $@ $^ $(LDFLAGS)
tqftpserv.service: tqftpserv.service.in
@sed 's+TQFTPSERV_PATH+$(bindir)+g' $< > $@
install: $(TQFTPSERV) tqftpserv.service
@install -D -m 755 $(TQFTPSERV) $(DESTDIR)$(bindir)/$(TQFTPSERV)
@install -D -m 644 tqftpserv.service $(DESTDIR)$(servicedir)/tqftpserv.service
clean:
rm -f $(TQFTPSERV) $(OBJS) tqftpserv.service
+1 -27
View File
@@ -1,32 +1,6 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
* Copyright (c) 2016, Linaro Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __LIST_H__
#define __LIST_H__
+32
View File
@@ -0,0 +1,32 @@
project('tqftpserv',
'c',
default_options: [
'warning_level=1',
'buildtype=release',
])
prefix = get_option('prefix')
systemd = dependency('systemd')
systemd_system_unit_dir = get_option('systemd-unit-prefix')
if systemd_system_unit_dir == ''
systemd_system_unit_dir = systemd.get_variable(
pkgconfig : 'systemdsystemunitdir',
pkgconfig_define: ['prefix', prefix])
endif
qrtr_dep = dependency('qrtr')
tqftpserv_srcs = ['translate.c',
'tqftpserv.c']
executable('tqftpserv',
tqftpserv_srcs,
dependencies : qrtr_dep,
install : true)
systemd_unit_conf = configuration_data()
systemd_unit_conf.set('prefix', prefix)
configure_file(
input : 'tqftpserv.service.in',
output : 'tqftpserv.service',
configuration : systemd_unit_conf,
install_dir : systemd_system_unit_dir)
+4
View File
@@ -0,0 +1,4 @@
option('systemd-unit-prefix',
type: 'string',
description: 'Directory for systemd system unit files'
)
+142 -75
View File
@@ -1,32 +1,6 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
* Copyright (c) 2018, Linaro Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <arpa/inet.h>
#include <sys/stat.h>
@@ -53,6 +27,10 @@ enum {
OP_OACK,
};
enum {
ERROR_END_OF_TRANSFER = 9,
};
struct tftp_client {
struct list_head node;
@@ -67,15 +45,17 @@ struct tftp_client {
size_t rsize;
size_t wsize;
unsigned int timeoutms;
off_t seek;
};
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 response_size)
{
ssize_t len;
size_t send_len;
char *buf;
char *p;
@@ -89,17 +69,29 @@ 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;
}
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 (response_size != 0) {
/* Header (4 bytes) + data size */
send_len = 4 + response_size;
if (send_len > p - buf) {
printf("[TQFTP] requested data of %ld bytes but only read %ld bytes from file, rejecting\n", response_size, 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);
@@ -118,7 +110,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;
@@ -172,6 +165,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);
}
@@ -196,13 +198,53 @@ static int tftp_send_error(int sock, int code, const char *msg)
return rc;
}
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, off_t *seek)
{
const char *opt, *value;
const char *p = buf;
while (p < buf + len) {
/* XXX: ensure we're not running off the end */
opt = p;
p += strlen(p) + 1;
/* XXX: ensure we're not running off the end */
value = p;
p += strlen(p) + 1;
/*
* blksize: block size - how many bytes to send at once
* timeoutms: timeout in milliseconds
* 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);
} else if (!strcmp(opt, "timeoutms")) {
*timeoutms = atoi(value);
} else if (!strcmp(opt, "tsize")) {
*tsize = atoi(value);
} else if (!strcmp(opt, "rsize")) {
*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);
}
}
}
static void handle_rrq(const char *buf, size_t len, struct sockaddr_qrtr *sq)
{
struct tftp_client *client;
const char *filename;
const char *value;
const char *mode;
const char *opt;
struct stat sb;
const char *p;
ssize_t tsize = -1;
@@ -210,6 +252,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;
@@ -229,36 +272,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;
while (p < buf + len) {
/* XXX: ensure we're not running off the end */
opt = p;
p += strlen(p) + 1;
/* XXX: ensure we're not running off the end */
value = p;
p += strlen(p) + 1;
if (!strcmp(opt, "blksize")) {
blksize = atoi(value);
} else if (!strcmp(opt, "timeoutms")) {
timeoutms = atoi(value);
} else if (!strcmp(opt, "tsize")) {
tsize = atoi(value);
} else if (!strcmp(opt, "rsize")) {
rsize = atoi(value);
} else if (!strcmp(opt, "wsize")) {
wsize = atoi(value);
} else {
printf("[TQFTP] Ignoring unknown option '%s'\n", opt);
}
}
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 */
@@ -293,6 +314,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");
@@ -303,9 +325,10 @@ 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);
tftp_send_data(client, 1, 0, 0);
}
}
@@ -314,12 +337,21 @@ static void handle_wrq(const char *buf, size_t len, struct sockaddr_qrtr *sq)
struct tftp_client *client;
const char *filename;
const char *mode;
const char *p;
ssize_t tsize = -1;
size_t blksize = 512;
unsigned int timeoutms = 1000;
size_t rsize = 0;
size_t wsize = 0;
off_t seek = 0;
bool do_oack = false;
int sock;
int ret;
int fd;
filename = buf + 2;
mode = buf + 2 + strlen(filename) + 1;
p = mode + strlen(mode) + 1;
if (strcasecmp(mode, "octet")) {
/* XXX: error */
@@ -329,6 +361,12 @@ static void handle_wrq(const char *buf, size_t len, struct sockaddr_qrtr *sq)
printf("[TQFTP] WRQ: %s (%s)\n", filename, mode);
if (p < buf + len) {
do_oack = true;
parse_options(p, len - (p - buf), &blksize, &tsize, &wsize,
&timeoutms, &rsize, &seek);
}
fd = translate_open(filename, O_WRONLY | O_CREAT);
if (fd < 0) {
/* XXX: error */
@@ -354,19 +392,26 @@ static void handle_wrq(const char *buf, size_t len, struct sockaddr_qrtr *sq)
client->sq = *sq;
client->sock = sock;
client->fd = fd;
ret = tftp_send_ack(client->sock, 0);
if (ret < 0) {
printf("[TQFTP] unable to send ack\n");
close(sock);
close(fd);
free(client);
return;
}
client->blksize = blksize;
client->rsize = rsize;
client->wsize = wsize;
client->timeoutms = timeoutms;
client->seek = seek;
// printf("[TQFTP] new writer added\n");
list_add(&writers, &client->node);
if (do_oack) {
tftp_send_oack(client->sock, &blksize,
tsize ? (size_t*)&tsize : NULL,
wsize ? &wsize : NULL,
&client->timeoutms,
rsize ? &rsize : NULL,
seek ? &seek : NULL);
} else {
tftp_send_data(client, 1, 0, 0);
}
}
static int handle_reader(struct tftp_client *client)
@@ -400,7 +445,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: %s\n", buf + 4);
int err = buf[2] << 8 | buf[3];
/* "End of Transfer" is not an error, used with stat(2)-like calls */
if (err == ERROR_END_OF_TRANSFER)
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);
@@ -410,9 +460,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 response_size = 0;
/* Check if need to limit response size based for requested rsize */
if ((block + 1) * client->blksize > client->rsize)
response_size = client->rsize % client->blksize;
n = tftp_send_data(client, block + 1,
block * client->blksize);
offset, response_size);
if (n < 0) {
printf("[TQFTP] Sent block %d failed: %zd\n", block + 1, n);
break;
@@ -420,6 +480,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 + 1) * client->blksize > client->rsize)
break;
}
return 1;
@@ -595,6 +658,10 @@ int main(int argc, char **argv)
// printf("[TQFTP] write\n");
handle_wrq(buf, len, &sq);
break;
case OP_ERROR:
buf[len] = '\0';
printf("[TQFTP] received error: %d - %s\n", buf[2] << 8 | buf[3], buf + 4);
break;
default:
printf("[TQFTP] unhandled op %d\n", opcode);
break;
+1 -1
View File
@@ -4,7 +4,7 @@ Requires=qrtr-ns.service
After=qrtr-ns.service
[Service]
ExecStart=TQFTPSERV_PATH/tqftpserv
ExecStart=@prefix@/bin/tqftpserv
Restart=always
[Install]
+56 -36
View File
@@ -1,32 +1,6 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
* Copyright (c) 2019, Linaro Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/stat.h>
#include <sys/types.h>
@@ -37,6 +11,7 @@
#include <libgen.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -45,7 +20,27 @@
#define READONLY_PATH "/readonly/firmware/image/"
#define READWRITE_PATH "/readwrite/"
#ifndef ANDROID
#define FIRMWARE_BASE "/lib/firmware/"
#define TQFTPSERV_TMP "/tmp/tqftpserv"
#else
#define FIRMWARE_BASE "/vendor/firmware/"
#define TQFTPSERV_TMP "/data/vendor/tmp/tqftpserv"
#endif
static void read_fw_path_from_sysfs(char *outbuffer, size_t bufsize)
{
size_t pathsize;
FILE *f = fopen("/sys/module/firmware_class/parameters/path", "rt");
if (!f)
return;
pathsize = fread(outbuffer, sizeof(char), bufsize, f);
fclose(f);
if (pathsize == 0)
return;
/* truncate newline */
outbuffer[pathsize - 1] = '\0';
}
/**
* translate_readonly() - open "file" residing with remoteproc firmware
@@ -64,8 +59,11 @@
static int translate_readonly(const char *file)
{
char firmware_value[PATH_MAX];
char *firmware_value_copy = NULL;
char *firmware_path;
char firmware_attr[32];
char path[PATH_MAX];
char fw_sysfs_path[PATH_MAX];
struct dirent *de;
int firmware_fd;
DIR *class_dir;
@@ -73,6 +71,8 @@ static int translate_readonly(const char *file)
ssize_t n;
int fd = -1;
read_fw_path_from_sysfs(fw_sysfs_path, sizeof(fw_sysfs_path));
class_fd = open("/sys/class/remoteproc", O_RDONLY | O_DIRECTORY);
if (class_fd < 0) {
warn("failed to open remoteproc class");
@@ -82,7 +82,8 @@ static int translate_readonly(const char *file)
class_dir = fdopendir(class_fd);
if (!class_dir) {
warn("failed to opendir");
goto close_class;
close(class_fd);
return -1;
}
while ((de = readdir(class_dir)) != NULL) {
@@ -103,13 +104,34 @@ static int translate_readonly(const char *file)
if (n < 0) {
continue;
}
firmware_value[n] = '\0';
firmware_value_copy = strdup(firmware_value);
firmware_path = dirname(firmware_value_copy);
/* first try path from sysfs */
if ((strlen(fw_sysfs_path) > 0) &&
(strlen(fw_sysfs_path) + 1 + strlen(firmware_value) + 1 + strlen(file) + 1 < sizeof(path))) {
strcpy(path, fw_sysfs_path);
strcat(path, "/");
strcat(path, firmware_path);
strcat(path, "/");
strcat(path, file);
fd = open(path, O_RDONLY);
if (fd >= 0)
break;
if (errno != ENOENT)
warn("failed to open %s", path);
}
/* now try with base path */
if (strlen(FIRMWARE_BASE) + strlen(firmware_value) + 1 +
strlen(file) + 1 > sizeof(path))
continue;
strcpy(path, FIRMWARE_BASE);
strcat(path, dirname(firmware_value));
strcat(path, firmware_path);
strcat(path, "/");
strcat(path, file);
@@ -121,11 +143,9 @@ static int translate_readonly(const char *file)
warn("failed to open %s", path);
}
free(firmware_value_copy);
closedir(class_dir);
close_class:
close(class_fd);
return fd;
}
@@ -142,15 +162,15 @@ static int translate_readwrite(const char *file, int flags)
int ret;
int fd;
ret = mkdir("/tmp/tqftpserv", 0700);
ret = mkdir(TQFTPSERV_TMP, 0700);
if (ret < 0 && errno != EEXIST) {
warn("failed to create /tmp/tqftpserv");
warn("failed to create temporary tqftpserv directory");
return -1;
}
base = open("/tmp/tqftpserv", O_RDONLY | O_DIRECTORY);
base = open(TQFTPSERV_TMP, O_RDONLY | O_DIRECTORY);
if (base < 0) {
warn("failed top open /tmp/tqftpserv");
warn("failed top open temporary tqftpserv directory");
return -1;
}