From f2b36fcd87a99e97f84114f7d69ea10aa2cbab1d Mon Sep 17 00:00:00 2001 From: Bjørn Mork Date: Sat, 9 Nov 2019 21:54:07 +0100 Subject: WiP: initial proxy support - sort of working for MBIM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bjørn Mork --- dev.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.c | 15 ++++++++-- mbim.c | 46 +++++++++++++++++++++++++++++++ mbim.h | 2 ++ uqmi.h | 1 + 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 +#include +#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 : Keep Client ID for service \n" " --release-client-id : 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); -- cgit v1.2.3