summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjørn Mork <bjorn@mork.no>2019-11-09 21:54:07 +0100
committerBjørn Mork <bjorn@mork.no>2019-11-09 21:54:07 +0100
commitf2b36fcd87a99e97f84114f7d69ea10aa2cbab1d (patch)
tree61b0c2fecf891f6e54971cf9427bb610b1154deb
parentd01b355f49cd9e83990ae2c5e82d11bc52dcbc97 (diff)
WiP: initial proxy support - sort of working for MBIMmaster+debian
Signed-off-by: Bjørn Mork <bjorn@mork.no>
-rw-r--r--dev.c99
-rw-r--r--main.c15
-rw-r--r--mbim.c46
-rw-r--r--mbim.h2
-rw-r--r--uqmi.h1
5 files changed, 161 insertions, 2 deletions
diff --git a/dev.c b/dev.c
index bd10207..de7ee55 100644
--- a/dev.c
+++ b/dev.c
@@ -27,7 +27,14 @@
#include "uqmi.h"
#include "qmi-errors.h"
#include "qmi-errors.c"
+
#include "mbim.h"
+#define LIBQMI_QMI_PROXY 1
+
+#ifdef LIBQMI_QMI_PROXY
+#include <sys/socket.h>
+#include <sys/un.h>
+#endif
bool cancel_all_requests = false;
@@ -91,6 +98,22 @@ static void __qmi_request_complete(struct qmi_dev *qmi, struct qmi_request *req,
}
}
+static void __mbim_proxy_request_complete(struct qmi_dev *qmi, struct mbim_command_message *msg)
+{
+ struct qmi_request *req = list_first_entry(&qmi->req, struct qmi_request, list);
+
+ if (!req->pending)
+ return;
+
+ req->pending = false;
+ list_del(&req->list);
+ req->ret = le32_to_cpu(msg->command_type); // actually status
+ if (req->complete) {
+ *req->complete = true;
+ uloop_cancelled = true;
+ }
+}
+
static void qmi_process_msg(struct qmi_dev *qmi, struct qmi_msg *msg)
{
struct qmi_request *req;
@@ -138,6 +161,9 @@ static void qmi_notify_read(struct ustream *us, int bytes)
msg = (struct qmi_msg *) (buf + sizeof(*mbim));
msg_len = le32_to_cpu(mbim->header.length);
if (!is_mbim_qmi(mbim)) {
+ if (is_mbim_proxy(mbim))
+ __mbim_proxy_request_complete(qmi, mbim);
+
/* must consume other MBIM packets */
ustream_consume(us, msg_len);
return;
@@ -368,6 +394,79 @@ int qmi_device_open(struct qmi_dev *qmi, const char *path)
return 0;
}
+#ifdef LIBQMI_QMI_PROXY
+
+static void no_cb(struct qmi_dev *qmi, struct qmi_request *req, struct qmi_msg *msg)
+{
+}
+
+int qmi_device_proxy_open(struct qmi_dev *qmi, const char *path)
+{
+ static struct {
+ struct mbim_command_message mbim;
+ union {
+ char buf[2048];
+ struct qmi_msg msg;
+ } u;
+ } __packed msgbuf;
+ struct ustream *us = &qmi->sf.stream;
+ int fd;
+
+ uloop_init();
+
+ fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0)
+ return -1;
+
+ if (qmi->is_mbim) {
+ struct sockaddr_un addr = { .sun_family = AF_UNIX, .sun_path = "\0mbim-proxy" };
+ fprintf(stderr,"connecting to mbim proxy\n");
+ if (connect(fd, (struct sockaddr *)&addr, 13)) {
+ perror("failed to connect to mbim-proxy: ");
+ return -1;
+ }
+ } else {
+ struct sockaddr_un addr = { .sun_family = AF_UNIX, .sun_path = "\0qmi-proxy" };
+ fprintf(stderr,"connecting to qmi proxy\n");
+ if (connect(fd, (struct sockaddr *)&addr, 12)) {
+ perror("failed to connect to qmi-proxy: ");
+ return -1;
+ }
+ }
+
+ us->notify_read = qmi_notify_read;
+ ustream_fd_init(&qmi->sf, fd);
+ INIT_LIST_HEAD(&qmi->req);
+ qmi->ctl_tid = 1;
+ qmi->buf = msgbuf.u.buf;
+
+ if (qmi->is_mbim) {
+ struct qmi_request req = {};
+ int len = mbim_proxy_cmd(&msgbuf.mbim, path);
+ dump_packet("foo", &msgbuf, 90);
+ ustream_write(&qmi->sf.stream, (void *)&msgbuf, len, false);
+ memset(&req, 0, sizeof(req));
+ req.ret = -1;
+ req.pending = true;
+ list_add(&req.list, &qmi->req);
+ qmi_request_wait(qmi, &req);
+ fprintf(stderr, "got return status 0x%04x\n", req.ret);
+ } else {
+ struct qmi_request req;
+ struct qmi_ctl_internal_proxy_open_request sreq = {
+ QMI_INIT_PTR(device_path, (char *)path)
+ };
+
+ qmi_set_ctl_internal_proxy_open_request(&msgbuf.u.msg, &sreq);
+ dump_packet("foo", &msgbuf.u.msg, 40);
+ qmi_request_start(qmi, &req, no_cb);
+ qmi_request_wait(qmi, &req);
+ }
+
+ return 0;
+}
+#endif
+
void qmi_device_close(struct qmi_dev *qmi)
{
struct qmi_request *req;
diff --git a/main.c b/main.c
index 9b43e5e..c8c7c86 100644
--- a/main.c
+++ b/main.c
@@ -44,6 +44,7 @@ static const struct option uqmi_getopt[] = {
{ "keep-client-id", required_argument, NULL, 'k' },
{ "release-client-id", required_argument, NULL, 'r' },
{ "mbim", no_argument, NULL, 'm' },
+ { "proxy", no_argument, NULL, 'p' },
{ NULL, 0, NULL, 0 }
};
#undef __uqmi_command
@@ -57,6 +58,7 @@ static int usage(const char *progname)
" --keep-client-id <name>: Keep Client ID for service <name>\n"
" --release-client-id <name>: Release Client ID after exiting\n"
" --mbim, -m NAME is an MBIM device with EXT_QMUX support\n"
+ " --proxy, -p Connect via qmi-proxy or mbim-proxy\n"
"\n"
"Services: dms, nas, pds, wds, wms\n"
"\n"
@@ -107,12 +109,13 @@ int main(int argc, char **argv)
{
static struct qmi_dev dev;
int ch, ret;
+ bool use_proxy = false;
uloop_init();
signal(SIGINT, handle_exit_signal);
signal(SIGTERM, handle_exit_signal);
- while ((ch = getopt_long(argc, argv, "d:k:sm", uqmi_getopt, NULL)) != -1) {
+ while ((ch = getopt_long(argc, argv, "d:k:smp", uqmi_getopt, NULL)) != -1) {
int cmd_opt = CMD_OPT(ch);
if (ch < 0 && cmd_opt >= 0 && cmd_opt < __UQMI_COMMAND_LAST) {
@@ -136,6 +139,9 @@ int main(int argc, char **argv)
case 'm':
dev.is_mbim = true;
break;
+ case 'p':
+ use_proxy = true;
+ break;
default:
return usage(argv[0]);
}
@@ -146,7 +152,12 @@ int main(int argc, char **argv)
return usage(argv[0]);
}
- if (qmi_device_open(&dev, device)) {
+ if (use_proxy)
+ ret = qmi_device_proxy_open(&dev, device);
+ else
+ ret = qmi_device_open(&dev, device);
+
+ if (ret) {
fprintf(stderr, "Failed to open device\n");
return 2;
}
diff --git a/mbim.c b/mbim.c
index f5336b1..ccbd979 100644
--- a/mbim.c
+++ b/mbim.c
@@ -27,6 +27,52 @@
static const uint8_t qmiuuid[16] = { 0xd1, 0xa3, 0x0b, 0xc2, 0xf9, 0x7a, 0x6e, 0x43,
0xbf, 0x65, 0xc7, 0xe2, 0x4f, 0xb0, 0xf0, 0xd3 };
+#define LIBQMI_QMI_PROXY 1
+#ifdef LIBQMI_QMI_PROXY
+static const uint8_t proxyuuid[16] = { 0x83, 0x8c, 0xf7, 0xfb, 0x8d, 0x0d, 0x4d, 0x7f,
+ 0x87, 0x1e, 0xd7, 0x1d, 0xbe, 0xfb, 0xb3, 0x9b };
+
+#define MBIM_CMD_PROXY_CONTROL_CONFIGURATION 1
+
+struct mbim_proxy_control {
+ uint32_t dev_off;
+ uint32_t dev_len;
+ uint32_t timeout;
+} __attribute__((packed));
+
+int mbim_proxy_cmd(struct mbim_command_message *msg, const char *path)
+{
+ struct mbim_proxy_control *p = (void *)(msg + 1);
+ int i, pathlen = strlen(path);
+ char *c = (void *)(p + 1);;
+
+ msg->header.type = cpu_to_le32(MBIM_MESSAGE_TYPE_COMMAND);
+ msg->header.length = cpu_to_le32(sizeof(*msg) + 2 * pathlen + sizeof(struct mbim_proxy_control));
+ msg->header.transaction_id = cpu_to_le32(1);
+ msg->fragment_header.total = cpu_to_le32(1);
+ msg->fragment_header.current = 0;
+ memcpy(msg->service_id, proxyuuid, 16);
+ msg->command_id = cpu_to_le32(MBIM_CMD_PROXY_CONTROL_CONFIGURATION);
+ msg->command_type = cpu_to_le32(MBIM_MESSAGE_COMMAND_TYPE_SET);
+ msg->buffer_length = cpu_to_le32(2 * pathlen + sizeof(struct mbim_proxy_control));
+
+ p->timeout = cpu_to_le32(5); // FIXME: hard coded timeout
+ p->dev_off = cpu_to_le32(sizeof(struct mbim_proxy_control));
+ p->dev_len = cpu_to_le32(2 * pathlen);
+ memset(c, 0, 2 * pathlen);
+ for (i = 0; i < pathlen; i++)
+ c[i * 2] = path[i];
+ return sizeof(struct mbim_command_message) + sizeof(struct mbim_proxy_control) + 2 * pathlen;
+}
+
+bool is_mbim_proxy(struct mbim_command_message *msg)
+{
+ return msg->header.type == cpu_to_le32(MBIM_MESSAGE_TYPE_COMMAND_DONE) &&
+ msg->command_id == cpu_to_le32(MBIM_CMD_PROXY_CONTROL_CONFIGURATION) &&
+ !msg->command_type && /* actually 'status' here */
+ !memcmp(msg->service_id, proxyuuid, 16);
+}
+#endif
bool is_mbim_qmi(struct mbim_command_message *msg)
{
diff --git a/mbim.h b/mbim.h
index 13783bf..bdfba0f 100644
--- a/mbim.h
+++ b/mbim.h
@@ -50,6 +50,8 @@ struct mbim_command_message {
uint32_t buffer_length;
} __packed;
+int mbim_proxy_cmd(struct mbim_command_message *msg, const char *path);
+bool is_mbim_proxy(struct mbim_command_message *msg);
bool is_mbim_qmi(struct mbim_command_message *msg);
void mbim_qmi_cmd(struct mbim_command_message *msg, int len, uint16_t tid);
diff --git a/uqmi.h b/uqmi.h
index dd88151..da3ca91 100644
--- a/uqmi.h
+++ b/uqmi.h
@@ -107,6 +107,7 @@ struct qmi_request {
extern bool cancel_all_requests;
int qmi_device_open(struct qmi_dev *qmi, const char *path);
+int qmi_device_proxy_open(struct qmi_dev *qmi, const char *path);
void qmi_device_close(struct qmi_dev *qmi);
int qmi_request_start(struct qmi_dev *qmi, struct qmi_request *req, request_cb cb);