aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTony Garnock-Jones <tonyg@leastfixedpoint.com>2020-09-29 22:03:07 +0200
committerDenis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>2021-09-01 12:28:12 +0200
commitb5722eb0a6a8918e612112e838510900a96c9453 (patch)
treebfad41a59e139de5a66d209bc86de50bba2c1456
parent5ae458efad76a512cae3015381f6f918c22516c2 (diff)
downloadhardware_replicant_libsamsung-ipc-patches-todo/ipc-modem-rfs-from-Tony-Garnock-Jones-v2.tar.gz
hardware_replicant_libsamsung-ipc-patches-todo/ipc-modem-rfs-from-Tony-Garnock-Jones-v2.tar.bz2
hardware_replicant_libsamsung-ipc-patches-todo/ipc-modem-rfs-from-Tony-Garnock-Jones-v2.zip
Cornucopia isn't maintained anymore and depended on libsamsung-ipc's Vala bindings which have been removed by commit ff8032e4c25f ("Deprecated and unmaintained vapi removal"). So beside using oFono patches to or libsamsung-ril through libhybris, tools like ipc-modem, ipc-test are pretty much the only way to test modems under GNU/Linux, and being able to test the RFS support is useful. In addition herolte (a Galaxy S7 variant), has a check in its kernel that prevents ipc-modem to work if the RFS channel is not opened[1]: static bool rild_ready(struct link_device *ld) { [...] fmt_iod = link_get_iod_with_channel(ld, SIPC5_CH_ID_FMT_0); if (!fmt_iod) { mif_err("%s: No FMT io_device\n", ld->name); return false; } rfs_iod = link_get_iod_with_channel(ld, SIPC5_CH_ID_RFS_0); if (!rfs_iod) { mif_err("%s: No RFS io_device\n", ld->name); return false; } [...] } So when adding support for such devices, being able use ipc-modem to easily test if it works is also very useful. [1]drivers/misc/modem_v1/link_device_shmem.c from https://github.com/ivanmeler/android_kernel_samsung_herolte with the lineage-17.0 branch Signed-off-by: Tony Garnock-Jones <tonyg@leastfixedpoint.com> GNUtoo: rewrote the commit message, whitespace fixes. Signed-off-by: Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org> ======================================================================= ======================================================================= ======================================================================= TODO: ===== - Finish addressing all the review concerns - Send it for review again (if possible involve Tony for testing + review) Review things to address: ======================== > + return 0; Thanks a lot: That check wasn't there before as we had that instead: > rc = ipc_client_poll(client, NULL, NULL); > if (rc < 0) > continue; So here when rc was 0, it would then run that: > rc = ipc_client_recv(client, &resp); > if (rc < 0) { > [...] > break; > } This is because for some devices this will call xmm626_kernel_smdk4412_fmt_recv that has the following: > rc = client->handlers->read(client, client->handlers->transport_data, > buffer, length); > if (rc < (int) sizeof(struct ipc_fmt_header)) { > [...] > goto error; > } And client->handlers->read can be xmm626_kernel_smdk4412_read which just wraps a read call. And read can return 0 if there is nothing to read yet. So if I understood correctly, we could have read too soon, and that would make ipc-modem stop due to an error. In any case it's also best to create a separate patch to fix that before this patch as if there is any regression we could easily pinpoint that to this exact change. Do you want me to do this patch? or do you want to do it? %<------------------------------------------------------------------->% > + if (resp.data != NULL) > + free(resp.data); > + > + return 1; > +} If you switch the name of that function to modem_read, you could just return rc (including when there is a timeout). This way it would look like the semantics of the read() function. As read also return -1 in case of errors that would look way better. %<------------------------------------------------------------------->% > +void modem_read_loop(struct ipc_client *client_fmt, struct > ipc_client *client_rfs) +{ > while (1) { > usleep(3000); > > - rc = ipc_client_poll(client, NULL, NULL); > - if (rc < 0) > - continue; > - > - rc = ipc_client_recv(client, &resp); > - if (rc < 0) { > - printf("[E] " > - "Can't RECV from modem: please run > this again" > - "\n"); > - break; > - } > - > - modem_response_handle(client, &resp); > - > - if (resp.data != NULL) > - free(resp.data); > + switch (modem_poll_client(client_fmt, "FMT")) { > + case -1: > + return; This changes the program behavior here: before we had that: > int modem_read_loop(struct ipc_client *client)> { > [...] > while (1) { > usleep(3000); > > rc = ipc_client_poll(client, NULL, NULL); > if (rc < 0) > continue; > [...] > } [...] > } So when the modem crashed for instance, you would simply continue trying to read ipc messages. While there are no comments that indicates why it was done like that, in libsamsung-ril we just restart to bootstrap the modem again when that happens: for instance in xmm626_kernel_smdk4412_poll we have: > rc = select(fd_max + 1, &set, NULL, NULL, timeout); > > if (FD_ISSET(fd, &set)) { > status = ioctl(fd, IOCTL_MODEM_STATUS, 0); > if (status != STATE_ONLINE && status != STATE_BOOTING) > return -1; > } > [...] > return rc; So it's probably safe to assume that the modem is crashed if the is return code is -1 as it's not booting. It would probably be best to split that change somehow, as it could help bisecting the issue in case of problems with that change. For instance the patch to fix that could be applied before this patch and look like that: > int modem_read_loop(struct ipc_client *client) > { > [...] > while (1) { > usleep(3000); > > rc = ipc_client_poll(client, NULL, NULL); > if (rc < 0) > - continue; > + return rc; > [...] > } [...] >} Do you want me to do it or do you prefer doing it? %<------------------------------------------------------------------->% > + case 0: > + if (client_rfs != NULL) { > + switch > (modem_poll_client(client_rfs, "RFS")) { The issue here is that if the IPC channel always has some data, the RFS modem poll is never run. The issue is that, as I understand the following won't work: > switch (modem_poll_client(client_fmt, "FMT")) { > case -1: > return; > case 0: > /* Fall through */ > default: > break; > } > switch (modem_poll_client(client_rfs, "RFS")) { > case -1: > return; > case 0: > /* Fall through */ > default: > break; > } > void modem_log_handler(__attribute__((unused)) void *user_data, > @@ -476,20 +508,24 @@ void print_help(void) > printf("\tpower-off power off the modem\n"); > printf("arguments:\n"); > printf("\t--debug enable debug messages\n"); > + printf("\t--rfs enable RFS client in > addition to FMT client\n"); printf("\t--pin=[PIN] provide > SIM card PIN\n"); } > > int main(int argc, char *argv[]) > { > - struct ipc_client *client_fmt; > + struct ipc_client *client_fmt = 0; > + struct ipc_client *client_rfs = 0; > int c = 0; > int opt_i = 0; > int rc = -1; > int debug = 0; > + int rfs = 0; > > struct option opt_l[] = { > {"help", no_argument, 0, 0 }, > {"debug", no_argument, 0, 0 }, > + {"rfs", no_argument, 0, 0 }, > {"pin", required_argument, 0, 0 }, > {0, 0, 0, 0 } > }; > @@ -512,6 +548,9 @@ int main(int argc, char *argv[]) > } else if (strcmp(opt_l[opt_i].name, > "debug") == 0) { debug = 1; > printf("[I] Debug enabled\n"); > + } else if (strcmp(opt_l[opt_i].name, "rfs") > == 0) { > + rfs = 1; > + printf("[I] RFS enabled\n"); > } else if (strcmp(opt_l[opt_i].name, "pin") > == 0) { if (optarg) { > if (strlen(optarg) < 8) { > @@ -536,12 +575,30 @@ int main(int argc, char *argv[]) > goto modem_quit; > } > > + if (rfs) { > + client_rfs = ipc_client_create(IPC_CLIENT_TYPE_RFS); > + if (client_rfs == 0) { > + printf("[E] Could not create RFS client; > aborting ...\n"); > + goto modem_quit; > + } > + } else { > + client_rfs = 0; > + } > + > if (debug == 0) { > ipc_client_log_callback_register(client_fmt, > modem_log_handler_quiet, > NULL); > + if (rfs) { > + ipc_client_log_callback_register(client_rfs, > + > modem_log_handler_quiet, NULL); > + } > } else { > ipc_client_log_callback_register(client_fmt, > modem_log_handler, NULL); > + if (rfs) { > + ipc_client_log_callback_register(client_rfs, > modem_log_handler, > + NULL); > + } > } > > while (optind < argc) { > @@ -561,18 +618,34 @@ int main(int argc, char *argv[]) > printf("[E] Something went wrong " > "while bootstrapping > modem\n"); } else if (strncmp(argv[optind], "start", 5) == 0) { > - printf("[0] Starting modem on FMT client\n"); > + printf("[0] Starting modem FMT client\n"); > rc = modem_start(client_fmt); > if (rc < 0) { > - printf("[E] Something went wrong\n"); > + printf("[E] Something went wrong > starting FMT client\n"); modem_stop(client_fmt); > return 1; > } > > - printf("[1] Starting modem_read_loop on FMT > client\n"); > - modem_read_loop(client_fmt); > + if (rfs) { > + printf("[1] Starting modem RFS > client\n"); > + ipc_client_data_create(client_rfs); > + rc = ipc_client_open(client_rfs); > + if (rc < 0) { > + printf("[E] Something went > wrong starting RFS client\n"); > + ipc_client_close(client_rfs); > + modem_stop(client_fmt); > + return 1; > + } > + } else { > + printf("[1] Skipping modem RFS > client start\n"); If you use thread and chose not to enable RFS by default for some good reason, it would be a good idea to add a print here as it's probably easy to forget to add --rfs to the command line. It also shows up in logs so the information will appear when copy/pasting logs to get some help. However for someone that didn't read that code, that could be interpreted as an error. To make it more clear you could do something like that for instance: > printf("[1] --rfs not selected, " > "skipping modem RFS client start\n"); Here it explains why it's skipping the RFS client start. Another option would be to enable the RFS handling by default. If there are no downsides here that option would be way better. Otherwise people that have a Galaxy S7 with the herolte codename, and potentially other devices they want to add support for will not necessarily know that --rfs is really required. They could also forget to add it during some tests and draw wrong conclusions. Still, it should probably be safe to enable it by default as we don't write to the nv_data.bin This won't be perfect as ipc-test doesn't have RFS support, but in the worst case people might try both tools and assume that for some unknown reason ipc-test doesn't work while ipc-modem does. > + } > + > + printf("[2] Starting modem_read_loop on FMT > client\n"); > + modem_read_loop(client_fmt, client_rfs); > > modem_stop(client_fmt); > + if (client_rfs != 0) > + ipc_client_close(client_rfs); That could be moved in modem_stop: - That code is also repeated when "Something went wrong starting RFS client". - It's not very consistent to have ipc_client_close(client) in modem_stop for the ipc_client but have the same for the RFS client outside of that function. - The function name (modem_stop) implies that it's generic Signed-off-by: Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org>
-rw-r--r--tools/ipc-modem.c319
1 files changed, 242 insertions, 77 deletions
diff --git a/tools/ipc-modem.c b/tools/ipc-modem.c
index dad95fc..c09d0a8 100644
--- a/tools/ipc-modem.c
+++ b/tools/ipc-modem.c
@@ -19,6 +19,7 @@
*/
#include <assert.h>
+#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <pthread.h>
@@ -58,9 +59,18 @@ enum command {
};
struct cmdline_opts {
- enum command command;
+ uint32_t command;
bool debug;
bool dry_run;
+ bool rfs;
+};
+
+struct ipc_modem_client {
+ char *name;
+ pthread_t thread;
+ pthread_mutex_t mutex;
+ pthread_attr_t attr;
+ struct ipc_client *client;
};
int seq_get(void)
@@ -105,8 +115,6 @@ void modem_snd_audio_path_ctrl(struct ipc_client *client)
IPC_TYPE_SET, (void *) &data, 1);
}
-
-
void modem_exec_call_out(struct ipc_client *client, char *num)
{
struct ipc_call_outgoing_data call_out;
@@ -364,7 +372,8 @@ void modem_response_net(__attribute__((unused)) struct ipc_client *client,
}
}
-void modem_response_handle(struct ipc_client *client, struct ipc_message *resp)
+void modem_response_fmt_handle(struct ipc_client *client,
+ struct ipc_message *resp)
{
switch (IPC_GROUP(resp->command)) {
case IPC_GROUP_NET:
@@ -389,46 +398,79 @@ void modem_response_handle(struct ipc_client *client, struct ipc_message *resp)
}
}
-
-int modem_read_loop(struct ipc_client *client)
+int modem_read(struct ipc_client *client, char const *channel_name)
{
struct ipc_message resp;
+ struct timeval timeout;
int rc;
memset(&resp, 0, sizeof(resp));
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 50000;
+ rc = ipc_client_poll(client, NULL, &timeout);
+ if (rc < 0) {
+ printf("[E] poll of %s client failed\n", channel_name);
+ return -1;
+ }
+
+ if (rc == 0) {
+ /* timeout */
+ return 0;
+ }
+
+ rc = ipc_client_recv(client, &resp);
+ if (rc < 0) {
+ printf("[E] "
+ "Can't RECV from %s channel: please run this again"
+ "\n", channel_name);
+ return -1;
+ }
+
+ /* We have no RFS handler (yet) in ipc-modem */
+ if (!strcmp(channel_name, "FMT"))
+ modem_response_fmt_handle(client, &resp);
+
+ if (resp.data != NULL)
+ free(resp.data);
+
+ return rc;
+}
+
+void modem_read_loop(struct ipc_modem_client *modem_client)
+{
+ int rc;
+
while (1) {
usleep(3000);
- rc = ipc_client_poll(client, NULL, NULL);
- if (rc < 0)
- continue;
+ rc = modem_read(modem_client->client, modem_client->name);
- rc = ipc_client_recv(client, &resp);
- if (rc < 0) {
- printf("[E] "
- "Can't RECV from modem: please run this again"
- "\n");
+ switch (rc) {
+ case -1:
+ return;
+ case 0:
+ break;
+ default:
break;
}
-
- modem_response_handle(client, &resp);
-
- if (resp.data != NULL)
- free(resp.data);
}
- return 0;
+ pthread_exit((void*)rc);
}
-int modem_dummy_read_loop(struct ipc_client *client)
+void modem_dummy_read_loop(struct ipc_modem_client *modem_client)
{
- while (1) {
- printf("[I] %s: looping\n", __FUNCTION__);
+ int rc = 0;
+
+ while (true) {
+ printf("[I] %s: looping for the %s channel\n",
+ __FUNCTION__,
+ modem_client->name);
sleep(1);
}
- return 0;
+ pthread_exit((void*)rc);
}
void modem_log_handler(__attribute__((unused)) void *user_data,
@@ -459,34 +501,100 @@ void modem_log_handler_quiet(__attribute__((unused)) void *user_data,
{
}
-int modem_start(struct ipc_client *client)
+int modem_start(struct ipc_client *client_fmt, struct ipc_client *client_rfs)
{
int rc = -1;
- ipc_client_data_create(client);
- rc = ipc_client_boot(client);
- if (rc < 0)
- return -1;
+ /* We need to boot the modem before opening the channels */
+ ipc_client_data_create(client_fmt);
+ rc = ipc_client_boot(client_fmt);
+ if (rc < 0)
+ return -1;
+ usleep(300);
+
+ /* Then we open the RFS channel as this should be done at the end
+ * of the boot, before opening the FMT channel as at least on
+ * one herolte kernel, the modem kernel drivers requires it.
+ */
+ if (client_rfs) {
+ ipc_client_data_create(client_rfs);
+ rc = ipc_client_open(client_rfs);
+ if (rc < 0) {
+ printf("[E] Something went wrong "
+ "opening the RFS channel\n");
+ return -1;
+ }
+ }
- usleep(300);
+ /* Then we finally open the FMT channel */
+ rc = ipc_client_open(client_fmt);
+ if (rc < 0)
+ return -1;
- rc = ipc_client_open(client);
- if (rc < 0)
- return -1;
+ /* Some modem like aries have power_on callbacks that
+ * need to be called after booting the modem
+ */
+ rc = ipc_client_power_on(client_fmt);
+ if (rc < 0)
+ return -1;
- rc = ipc_client_power_on(client);
- if (rc < 0)
- return -1;
+ return 0;
+}
+
+int modem_stop(struct ipc_client *client_fmt, struct ipc_client *client_rfs)
+{
+ if (client_rfs)
+ ipc_client_close(client_fmt);
+
+ ipc_client_power_off(client_fmt);
+ ipc_client_close(client_fmt);
return 0;
}
-int modem_stop(struct ipc_client *client)
+int modem_create_channel_thread(struct ipc_modem_client *modem_client,
+ struct cmdline_opts *cmdline_opts)
{
- ipc_client_power_off(client);
- ipc_client_close(client);
+ int rc;
- return 0;
+ if (cmdline_opts->dry_run)
+ printf("[2] Starting modem_dummy_read_loop on %s client\n",
+ modem_client->name);
+ else
+ printf("[2] Starting modem_read_loop on %s client\n",
+ modem_client->name);
+
+ rc = pthread_attr_init(&modem_client->attr);
+ if (rc) {
+ printf("[E] %s pthread_attr_init failed with error %d\n",
+ modem_client->name, rc);
+ return rc;
+ }
+
+ if (rc) {
+ printf("[E] %s pthread_attr_setdetachstate failed with error %d\n",
+ modem_client->name, rc);
+ return rc;
+ }
+
+ if (cmdline_opts->dry_run) {
+ rc = pthread_create(&modem_client->thread,
+ &modem_client->attr,
+ (void *) modem_dummy_read_loop,
+ (void *) modem_client);
+ }
+ else
+ rc = pthread_create(&modem_client->thread,
+ &modem_client->attr,
+ (void *) modem_read_loop,
+ (void *) modem_client);
+ if (rc) {
+ printf("[E] %s pthread_create failed with error %d\n",
+ modem_client->name, rc);
+ return rc;
+ }
+
+ return rc;
}
void print_help(void)
@@ -504,37 +612,55 @@ void print_help(void)
"Test the ipc-modem program without talking to the modem.\n");
printf("\t--help print this help message\n");
printf("\t--pin=[PIN] provide SIM card PIN\n");
+ printf("\t--rfs enable RFS client in addition to FMT client\n");
}
-int handle_command(struct cmdline_opts *cmdline_opts)
+int create_client(struct ipc_client **client, int client_type,
+ struct cmdline_opts *cmdline_opts)
{
- struct ipc_client *client_fmt;
- int rc = 0;
-
if (cmdline_opts->dry_run)
- client_fmt = ipc_client_create(IPC_CLIENT_TYPE_DUMMY);
- else
- client_fmt = ipc_client_create(IPC_CLIENT_TYPE_FMT);
+ client_type = IPC_CLIENT_TYPE_DUMMY;
- if (client_fmt == 0) {
- printf("[E] Could not create IPC client; aborting ...\n");
- goto modem_quit;
+ *client = ipc_client_create(client_type);
+ if (*client == 0) {
+ printf("[E] Could not create IPC %s client; aborting ...\n",
+ ipc_client_type_string(client_type));
+ return -1;
}
- if (cmdline_opts->debug == 0) {
- ipc_client_log_callback_register(client_fmt,
- modem_log_handler_quiet, NULL);
- } else {
- ipc_client_log_callback_register(client_fmt, modem_log_handler,
+ if (cmdline_opts->debug)
+ ipc_client_log_callback_register(*client, modem_log_handler,
NULL);
- }
+ else
+ ipc_client_log_callback_register(*client,
+ modem_log_handler_quiet, NULL);
+ return 0;
+}
+
+int handle_command(struct cmdline_opts *cmdline_opts,
+ struct ipc_modem_client *modem_client_fmt,
+ struct ipc_modem_client *modem_client_rfs)
+{
+ int rc = 0;
+
+ modem_client_fmt->name = "FMT";
+ modem_client_rfs->name = "RFS";
+
+ rc = create_client(&modem_client_fmt->client, IPC_CLIENT_TYPE_FMT,
+ cmdline_opts);
+ if (rc)
+ goto modem_quit;
+
+ if (cmdline_opts->rfs)
+ rc = create_client(&modem_client_rfs->client, IPC_CLIENT_TYPE_RFS,
+ cmdline_opts);
switch (cmdline_opts->command) {
case CMD_POWER_ON:
if (cmdline_opts->dry_run)
break;
- rc = ipc_client_power_on(client_fmt);
+ rc = ipc_client_power_on(modem_client_fmt->client);
if (rc < 0)
printf("[E] Something went wrong "
"while powering modem on\n");
@@ -543,7 +669,7 @@ int handle_command(struct cmdline_opts *cmdline_opts)
if (cmdline_opts->dry_run)
break;
- rc = ipc_client_power_off(client_fmt);
+ rc = ipc_client_power_off(modem_client_fmt->client);
if (rc < 0)
printf("[E] Something went wrong "
"while powering modem off\n");
@@ -552,34 +678,61 @@ int handle_command(struct cmdline_opts *cmdline_opts)
if (cmdline_opts->dry_run)
break;
- rc = ipc_client_boot(client_fmt);
+ rc = ipc_client_boot(modem_client_fmt->client);
if (rc < 0)
printf("[E] Something went wrong "
"while bootstrapping modem\n");
break;
case CMD_START:
- if (cmdline_opts->dry_run) {
- printf("[1] "
- "Starting dummy modem_read_loop on %s client\n",
- "FMT");
- modem_dummy_read_loop(client_fmt);
- break;
+
+ printf("[0] Starting modem FMT client\n");
+ if (!cmdline_opts->dry_run) {
+ rc = modem_start(modem_client_fmt->client, modem_client_rfs->client);
+ if (rc < 0) {
+ printf("[E] Something went wrong "
+ "starting FMT client\n");
+ modem_stop(modem_client_fmt->client, modem_client_rfs->client);
+ return 1;
+ }
+ }
+
+ if (cmdline_opts->rfs) {
+ printf("[1] Starting modem RFS thread\n");
+ rc = modem_create_channel_thread(modem_client_rfs,
+ cmdline_opts);
+ if (rc)
+ return rc;
+ } else {
+ printf("[1] Skipping modem RFS client start\n");
}
- printf("[0] Starting modem on FMT client\n");
+ printf("[1] Starting modem FMT thread\n");
+ rc = modem_create_channel_thread(modem_client_fmt, cmdline_opts);
- rc = modem_start(client_fmt);
- if (rc < 0) {
- printf("[E] Something went wrong\n");
- modem_stop(client_fmt);
- return 1;
+ while (true) {
+ int *thread_rc;
+
+ printf("[I] checking threads\n");
+
+ if (0 && cmdline_opts->rfs) {
+ rc = pthread_join(modem_client_rfs->thread, (void**)&thread_rc);
+ if (rc != EINVAL)
+ printf("[E] %s thread exited with error: %d\n",
+ modem_client_rfs->name,
+ *thread_rc);
+ }
+
+ rc = pthread_join(modem_client_fmt->thread, (void**)&thread_rc);
+ if (!rc) {
+ printf("[E] %s: pthread_join = %d\n",
+ modem_client_fmt->name, thread_rc);
+ }
+ sleep(1);
}
- printf("[1] Starting modem_read_loop on FMT client\n");
- modem_read_loop(client_fmt);
- modem_stop(client_fmt);
break;
default:
+ printf("ERROR: unknown CMD %d\n", cmdline_opts->command);
/* We should handle all commands */
printf("[E] %s: Unknown command %d\n", __FUNCTION__,
cmdline_opts->command);
@@ -588,8 +741,10 @@ int handle_command(struct cmdline_opts *cmdline_opts)
}
modem_quit:
- if (client_fmt != 0)
- ipc_client_destroy(client_fmt);
+ if (modem_client_fmt->client != 0)
+ ipc_client_destroy(modem_client_fmt->client);
+ if (modem_client_rfs->client != 0)
+ ipc_client_destroy(modem_client_rfs->client);
return rc;
}
@@ -606,6 +761,8 @@ void print_cmdline_opts(struct cmdline_opts *cmdline_opts)
int main(int argc, char *argv[])
{
struct cmdline_opts cmdline_opts;
+ struct ipc_modem_client modem_client_fmt;
+ struct ipc_modem_client modem_client_rfs;
int c = 0;
int opt_i = 0;
@@ -615,9 +772,12 @@ int main(int argc, char *argv[])
{"dry-run", no_argument, 0, 0 },
{"help", no_argument, 0, 0 },
{"pin", required_argument, 0, 0 },
+ {"rfs", no_argument, 0, 0 },
{0, 0, 0, 0 }
};
+ bzero((void*)&modem_client_fmt, sizeof(modem_client_fmt));
+ bzero((void*)&modem_client_rfs, sizeof(modem_client_rfs));
bzero((void*)&cmdline_opts, sizeof(cmdline_opts));
if (argc < 2) {
@@ -666,6 +826,9 @@ int main(int argc, char *argv[])
printf("[E] SIM PIN is too long!\n");
return 1;
}
+ } else if (strcmp(opt_l[opt_i].name, "rfs") == 0) {
+ cmdline_opts.rfs = true;
+ printf("[I] RFS enabled\n");
}
break;
@@ -705,5 +868,7 @@ int main(int argc, char *argv[])
print_cmdline_opts(&cmdline_opts);
- return handle_command(&cmdline_opts);
+ return handle_command(&cmdline_opts,
+ &modem_client_fmt,
+ &modem_client_rfs);
}