From 012f1419de4506792d148ea28c3365a162e592a2 Mon Sep 17 00:00:00 2001 From: coolsnowwolf Date: Tue, 28 Feb 2023 00:09:36 +0800 Subject: [PATCH] WWAN: add Fibocom linux usb QMI WWAN driver and dial app --- package/wwan/app/fibocom-dial/Makefile | 27 + package/wwan/app/fibocom-dial/src/GobiNetCM.c | 275 ++ package/wwan/app/fibocom-dial/src/MPQCTL.h | 363 ++ package/wwan/app/fibocom-dial/src/MPQMI.h | 287 ++ package/wwan/app/fibocom-dial/src/MPQMUX.c | 437 ++ package/wwan/app/fibocom-dial/src/MPQMUX.h | 3671 +++++++++++++++++ package/wwan/app/fibocom-dial/src/Makefile | 42 + package/wwan/app/fibocom-dial/src/QMIThread.c | 2551 ++++++++++++ package/wwan/app/fibocom-dial/src/QMIThread.h | 260 ++ package/wwan/app/fibocom-dial/src/QmiWwanCM.c | 426 ++ .../fibocom-dial}/src/default.script | 0 .../app/fibocom-dial/src/fibo_qmimsg_server.c | 1331 ++++++ .../wwan/app/fibocom-dial/src/libmnl/README | 28 + .../wwan/app/fibocom-dial/src/libmnl/attr.c | 722 ++++ .../app/fibocom-dial/src/libmnl/callback.c | 167 + .../app/fibocom-dial/src/libmnl/dhcp/dhcp.h | 5 + .../fibocom-dial/src/libmnl/dhcp/dhcpclient.c | 515 +++ .../fibocom-dial/src/libmnl/dhcp/dhcpmsg.c | 100 + .../fibocom-dial/src/libmnl/dhcp/dhcpmsg.h | 106 + .../app/fibocom-dial/src/libmnl/dhcp/packet.c | 247 ++ .../app/fibocom-dial/src/libmnl/dhcp/packet.h | 25 + .../app/fibocom-dial/src/libmnl/ifutils.c | 748 ++++ .../app/fibocom-dial/src/libmnl/ifutils.h | 53 + .../wwan/app/fibocom-dial/src/libmnl/libmnl.h | 202 + .../wwan/app/fibocom-dial/src/libmnl/nlmsg.c | 556 +++ .../wwan/app/fibocom-dial/src/libmnl/socket.c | 351 ++ package/wwan/app/fibocom-dial/src/main.c | 1770 ++++++++ .../app/fibocom-dial/src/multi-pdn-manager.c | 1019 +++++ .../wwan/app/fibocom-dial/src/multi-pdn.ini | 67 + .../app/fibocom-dial/src/qmap_bridge_mode.c | 438 ++ .../app/fibocom-dial/src/query_pcie_mode.c | 160 + .../app/fibocom-dial/src/query_pcie_mode.h | 17 + package/wwan/app/fibocom-dial/src/udhcpc.c | 289 ++ .../app/fibocom-dial/src/udhcpc_netlink.c | 421 ++ package/wwan/app/fibocom-dial/src/util.c | 142 + package/wwan/app/fibocom-dial/src/util.h | 53 + package/wwan/app/luci-proto-3x/Makefile | 6 +- .../{driver => app}/quectel_cm_5G/Makefile | 0 .../{driver => app}/quectel_cm_5G/files/dhcp | 0 .../quectel_cm_5G/files/rmnet.script | 0 .../quectel_cm_5G/files/rmnet.sh | 0 .../quectel_cm_5G/files/rmnet6.script | 0 .../quectel_cm_5G/files/rmnet6.sh | 0 .../quectel_cm_5G/files/rmnet_init.sh | 0 .../quectel_cm_5G/src/CMakeLists.txt | 0 .../quectel_cm_5G/src/GobiNetCM.c | 0 .../quectel_cm_5G/src/MPQCTL.h | 0 .../{driver => app}/quectel_cm_5G/src/MPQMI.h | 0 .../quectel_cm_5G/src/MPQMUX.c | 0 .../quectel_cm_5G/src/MPQMUX.h | 0 .../quectel_cm_5G/src/Makefile | 0 .../quectel_cm_5G/src/Makefile.am | 0 .../{driver => app}/quectel_cm_5G/src/NOTICE | 0 .../quectel_cm_5G/src/QMIThread.c | 0 .../quectel_cm_5G/src/QMIThread.h | 0 .../quectel_cm_5G/src/QmiWwanCM.c | 0 .../quectel_cm_5G/src/ReleaseNote.txt | 0 .../quectel_cm_5G/src/at_tok.c | 0 .../quectel_cm_5G/src/at_tok.h | 0 .../{driver => app}/quectel_cm_5G/src/atc.c | 0 .../quectel_cm_5G/src/atchannel.c | 0 .../quectel_cm_5G/src/atchannel.h | 0 .../quectel_cm_5G/src/configure.ac | 0 .../wwan/app/quectel_cm_5G/src/default.script | 63 + .../quectel_cm_5G/src/default.script_ip | 0 .../quectel_cm_5G/src/device.c | 0 .../quectel_cm_5G/src/ethtool-copy.h | 0 .../quectel_cm_5G/src/log/cdc_mbim.txt | 0 .../quectel_cm_5G/src/log/cdc_mbim_vlan.txt | 0 .../quectel_cm_5G/src/log/ecm_ncm_rndis.txt | 0 .../quectel_cm_5G/src/log/gobinet.txt | 0 .../quectel_cm_5G/src/log/gobinet_bridge.txt | 0 .../quectel_cm_5G/src/log/gobinet_qmap=1.txt | 0 .../src/log/gobinet_qmap=1_bridge.txt | 0 .../quectel_cm_5G/src/log/gobinet_qmap=4.txt | 0 .../src/log/gobinet_qmap=4_bridge.txt | 0 .../quectel_cm_5G/src/log/pcie_mhi_mbim.txt | 0 .../src/log/pcie_mhi_mbim_qmap=4.txt | 0 .../quectel_cm_5G/src/log/pcie_mhi_qmap=1.txt | 0 .../src/log/pcie_mhi_qmap=1_bridge.txt | 0 .../quectel_cm_5G/src/log/pcie_mhi_qmap=4.txt | 0 .../src/log/pcie_mhi_qmap=4_bridge.txt | 0 .../quectel_cm_5G/src/log/qmi_wwan_q.txt | 0 .../src/log/qmi_wwan_q_bridge.txt | 0 .../src/log/qmi_wwan_q_qmap=1.txt | 0 .../src/log/qmi_wwan_q_qmap=1_bridge.txt | 0 .../src/log/qmi_wwan_q_qmap=4.txt | 0 .../src/log/qmi_wwan_q_qmap=4_bridge.txt | 0 .../quectel_cm_5G/src/log/qmi_wwan_qmap=4.txt | 0 .../src/log/usage_of_argument/6.txt | 0 .../src/log/usage_of_argument/m.txt | 0 .../{driver => app}/quectel_cm_5G/src/main.c | 0 .../quectel_cm_5G/src/mbim-cm.c | 0 .../quectel_cm_5G/src/qendian.h | 0 .../{driver => app}/quectel_cm_5G/src/qlist.h | 0 .../quectel_cm_5G/src/qmap_bridge_mode.c | 0 .../{driver => app}/quectel_cm_5G/src/qrtr.c | 0 .../{driver => app}/quectel_cm_5G/src/qrtr.h | 0 .../quectel_cm_5G/src/quectel-atc-proxy.c | 0 .../quectel_cm_5G/src/quectel-mbim-proxy.c | 0 .../quectel_cm_5G/src/quectel-qmi-proxy.c | 0 .../quectel_cm_5G/src/quectel-qrtr-proxy.c | 0 .../quectel_cm_5G/src/rmnetctl.c | 0 .../quectel_cm_5G/src/udhcpc.c | 0 .../quectel_cm_5G/src/udhcpc_netlink.c | 0 .../quectel_cm_5G/src/udhcpc_script.c | 0 .../{driver => app}/quectel_cm_5G/src/util.c | 0 .../{driver => app}/quectel_cm_5G/src/util.h | 0 package/wwan/driver/fibocom_QMI_WWAN/Makefile | 47 + .../wwan/driver/fibocom_QMI_WWAN/src/Makefile | 38 + .../driver/fibocom_QMI_WWAN/src/qmi_wwan_f.c | 2506 +++++++++++ package/wwan/driver/quectel_Gobinet/Makefile | 2 +- package/wwan/driver/quectel_QMI_WWAN/Makefile | 2 +- 113 files changed, 20530 insertions(+), 5 deletions(-) create mode 100755 package/wwan/app/fibocom-dial/Makefile create mode 100755 package/wwan/app/fibocom-dial/src/GobiNetCM.c create mode 100755 package/wwan/app/fibocom-dial/src/MPQCTL.h create mode 100755 package/wwan/app/fibocom-dial/src/MPQMI.h create mode 100755 package/wwan/app/fibocom-dial/src/MPQMUX.c create mode 100755 package/wwan/app/fibocom-dial/src/MPQMUX.h create mode 100755 package/wwan/app/fibocom-dial/src/Makefile create mode 100755 package/wwan/app/fibocom-dial/src/QMIThread.c create mode 100755 package/wwan/app/fibocom-dial/src/QMIThread.h create mode 100755 package/wwan/app/fibocom-dial/src/QmiWwanCM.c rename package/wwan/{driver/quectel_cm_5G => app/fibocom-dial}/src/default.script (100%) mode change 100644 => 100755 create mode 100755 package/wwan/app/fibocom-dial/src/fibo_qmimsg_server.c create mode 100755 package/wwan/app/fibocom-dial/src/libmnl/README create mode 100755 package/wwan/app/fibocom-dial/src/libmnl/attr.c create mode 100755 package/wwan/app/fibocom-dial/src/libmnl/callback.c create mode 100755 package/wwan/app/fibocom-dial/src/libmnl/dhcp/dhcp.h create mode 100755 package/wwan/app/fibocom-dial/src/libmnl/dhcp/dhcpclient.c create mode 100755 package/wwan/app/fibocom-dial/src/libmnl/dhcp/dhcpmsg.c create mode 100755 package/wwan/app/fibocom-dial/src/libmnl/dhcp/dhcpmsg.h create mode 100755 package/wwan/app/fibocom-dial/src/libmnl/dhcp/packet.c create mode 100755 package/wwan/app/fibocom-dial/src/libmnl/dhcp/packet.h create mode 100755 package/wwan/app/fibocom-dial/src/libmnl/ifutils.c create mode 100755 package/wwan/app/fibocom-dial/src/libmnl/ifutils.h create mode 100755 package/wwan/app/fibocom-dial/src/libmnl/libmnl.h create mode 100755 package/wwan/app/fibocom-dial/src/libmnl/nlmsg.c create mode 100755 package/wwan/app/fibocom-dial/src/libmnl/socket.c create mode 100755 package/wwan/app/fibocom-dial/src/main.c create mode 100755 package/wwan/app/fibocom-dial/src/multi-pdn-manager.c create mode 100755 package/wwan/app/fibocom-dial/src/multi-pdn.ini create mode 100755 package/wwan/app/fibocom-dial/src/qmap_bridge_mode.c create mode 100755 package/wwan/app/fibocom-dial/src/query_pcie_mode.c create mode 100755 package/wwan/app/fibocom-dial/src/query_pcie_mode.h create mode 100755 package/wwan/app/fibocom-dial/src/udhcpc.c create mode 100755 package/wwan/app/fibocom-dial/src/udhcpc_netlink.c create mode 100755 package/wwan/app/fibocom-dial/src/util.c create mode 100755 package/wwan/app/fibocom-dial/src/util.h rename package/wwan/{driver => app}/quectel_cm_5G/Makefile (100%) rename package/wwan/{driver => app}/quectel_cm_5G/files/dhcp (100%) rename package/wwan/{driver => app}/quectel_cm_5G/files/rmnet.script (100%) rename package/wwan/{driver => app}/quectel_cm_5G/files/rmnet.sh (100%) rename package/wwan/{driver => app}/quectel_cm_5G/files/rmnet6.script (100%) rename package/wwan/{driver => app}/quectel_cm_5G/files/rmnet6.sh (100%) rename package/wwan/{driver => app}/quectel_cm_5G/files/rmnet_init.sh (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/CMakeLists.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/GobiNetCM.c (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/MPQCTL.h (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/MPQMI.h (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/MPQMUX.c (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/MPQMUX.h (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/Makefile (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/Makefile.am (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/NOTICE (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/QMIThread.c (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/QMIThread.h (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/QmiWwanCM.c (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/ReleaseNote.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/at_tok.c (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/at_tok.h (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/atc.c (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/atchannel.c (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/atchannel.h (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/configure.ac (100%) create mode 100644 package/wwan/app/quectel_cm_5G/src/default.script rename package/wwan/{driver => app}/quectel_cm_5G/src/default.script_ip (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/device.c (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/ethtool-copy.h (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/log/cdc_mbim.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/log/cdc_mbim_vlan.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/log/ecm_ncm_rndis.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/log/gobinet.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/log/gobinet_bridge.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/log/gobinet_qmap=1.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/log/gobinet_qmap=1_bridge.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/log/gobinet_qmap=4.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/log/gobinet_qmap=4_bridge.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/log/pcie_mhi_mbim.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/log/pcie_mhi_mbim_qmap=4.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/log/pcie_mhi_qmap=1.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/log/pcie_mhi_qmap=1_bridge.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/log/pcie_mhi_qmap=4.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/log/pcie_mhi_qmap=4_bridge.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/log/qmi_wwan_q.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/log/qmi_wwan_q_bridge.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/log/qmi_wwan_q_qmap=1.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/log/qmi_wwan_q_qmap=1_bridge.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/log/qmi_wwan_q_qmap=4.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/log/qmi_wwan_q_qmap=4_bridge.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/log/qmi_wwan_qmap=4.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/log/usage_of_argument/6.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/log/usage_of_argument/m.txt (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/main.c (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/mbim-cm.c (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/qendian.h (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/qlist.h (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/qmap_bridge_mode.c (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/qrtr.c (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/qrtr.h (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/quectel-atc-proxy.c (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/quectel-mbim-proxy.c (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/quectel-qmi-proxy.c (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/quectel-qrtr-proxy.c (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/rmnetctl.c (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/udhcpc.c (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/udhcpc_netlink.c (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/udhcpc_script.c (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/util.c (100%) rename package/wwan/{driver => app}/quectel_cm_5G/src/util.h (100%) create mode 100755 package/wwan/driver/fibocom_QMI_WWAN/Makefile create mode 100755 package/wwan/driver/fibocom_QMI_WWAN/src/Makefile create mode 100755 package/wwan/driver/fibocom_QMI_WWAN/src/qmi_wwan_f.c diff --git a/package/wwan/app/fibocom-dial/Makefile b/package/wwan/app/fibocom-dial/Makefile new file mode 100755 index 000000000..e3e7171fd --- /dev/null +++ b/package/wwan/app/fibocom-dial/Makefile @@ -0,0 +1,27 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=fibocom-dial +PKG_RELEASE:=1 +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) + + +include $(INCLUDE_DIR)/package.mk + +define Package/fibocom-dial + SECTION:=utils + CATEGORY:=Utilities + TITLE:=Fibocom Dial +endef + +define Package/fibocom-dial/description + Fibocom Dial (Prints a snarky message) +endef + +define Package/fibocom-dial/install + $(INSTALL_DIR) $(1)/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/fibocom-dial $(1)/bin/ + $(INSTALL_BIN) $(PKG_BUILD_DIR)/fibo_qmimsg_server $(1)/bin/ + $(INSTALL_BIN) $(PKG_BUILD_DIR)/multi-pdn-manager $(1)/bin/ +endef + +$(eval $(call BuildPackage,fibocom-dial)) diff --git a/package/wwan/app/fibocom-dial/src/GobiNetCM.c b/package/wwan/app/fibocom-dial/src/GobiNetCM.c new file mode 100755 index 000000000..aba86244b --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/GobiNetCM.c @@ -0,0 +1,275 @@ +#include +#include +#include +#include + +#include "QMIThread.h" + +#ifdef CONFIG_GOBINET + +// IOCTL to generate a client ID for this service type +#define IOCTL_QMI_GET_SERVICE_FILE 0x8BE0 + 1 + +// IOCTL to get the VIDPID of the device +#define IOCTL_QMI_GET_DEVICE_VIDPID 0x8BE0 + 2 + +// IOCTL to get the MEID of the device +#define IOCTL_QMI_GET_DEVICE_MEID 0x8BE0 + 3 + +static int GobiNetSendQMI(PQCQMIMSG pRequest) +{ + int ret, fd; + + static int send_count = 0; + fd = qmiclientId[pRequest->QMIHdr.QMIType]; + + if (fd <= 0) { + dbg_time("%s QMIType: %d has no clientID", __func__, + pRequest->QMIHdr.QMIType); + return -ENODEV; + } + + // Always ready to write +re_write: + if (1 == 1) { + ssize_t nwrites = + le16_to_cpu(pRequest->QMIHdr.Length) + 1 - sizeof(QCQMI_HDR); + ret = write(fd, &pRequest->MUXMsg, nwrites); + if (ret == nwrites) + { + ret = 0; + send_count = 0; + } + else + { + send_count++; + dbg_time("%s write=%d, errno: %d (%s) send_count %d", __func__, ret, errno, strerror(errno), send_count); + if (send_count < 3) + { + sleep(1); + goto re_write; + } + } + + } else { + dbg_time("%s poll=%d, errno: %d (%s)", __func__, ret, errno, + strerror(errno)); + } + + return ret; +} + +static int GobiNetGetClientID(const char *qcqmi, UCHAR QMIType) +{ + int ClientId; + ClientId = open(qcqmi, O_RDWR | O_NONBLOCK | O_NOCTTY); + if (ClientId == -1) { + dbg_time("failed to open %s, errno: %d (%s)", qcqmi, errno, + strerror(errno)); + return -1; + } + + if (ioctl(ClientId, IOCTL_QMI_GET_SERVICE_FILE, QMIType) != 0) { + dbg_time("failed to get ClientID for 0x%02x errno: %d (%s)", QMIType, + errno, strerror(errno)); + close(ClientId); + ClientId = 0; + } + + dbg_time("%s: QMIType = %d clientid %d", __func__, QMIType, ClientId); + + switch (QMIType) { + case QMUX_TYPE_WDS: + dbg_time("Get clientWDS = %d", ClientId); + break; + case QMUX_TYPE_DMS: + dbg_time("Get clientDMS = %d", ClientId); + break; + case QMUX_TYPE_NAS: + dbg_time("Get clientNAS = %d", ClientId); + break; + case QMUX_TYPE_QOS: + dbg_time("Get clientQOS = %d", ClientId); + break; + case QMUX_TYPE_WMS: + dbg_time("Get clientWMS = %d", ClientId); + break; + case QMUX_TYPE_PDS: + dbg_time("Get clientPDS = %d", ClientId); + break; + case QMUX_TYPE_UIM: + dbg_time("Get clientUIM = %d", ClientId); + break; + case QMUX_TYPE_WDS_ADMIN: + dbg_time("Get clientWDA = %d", ClientId); + break; + default: + break; + } + + return ClientId; +} + +static int GobiNetDeInit(void) +{ + unsigned int i; + for (i = 0; i < sizeof(qmiclientId) / sizeof(qmiclientId[0]); i++) { + if (qmiclientId[i] != 0) { + close(qmiclientId[i]); + qmiclientId[i] = 0; + } + } + + return 0; +} +static void *GobiNetThread(void *pData) +{ + PROFILE_T *profile = (PROFILE_T *)pData; + const char *qcqmi = (const char *)profile->qmichannel; + int wait_for_request_quit = 0; + dbg_time("%s %d", __func__, __LINE__); + if (profile->ipv4_flag) + qmiclientId[QMUX_TYPE_WDS] = GobiNetGetClientID(qcqmi, QMUX_TYPE_WDS); + if (profile->ipv6_flag) + qmiclientId[QMUX_TYPE_WDS_IPV6] = GobiNetGetClientID(qcqmi, QMUX_TYPE_WDS); + qmiclientId[QMUX_TYPE_DMS] = GobiNetGetClientID(qcqmi, QMUX_TYPE_DMS); + qmiclientId[QMUX_TYPE_NAS] = GobiNetGetClientID(qcqmi, QMUX_TYPE_NAS); + qmiclientId[QMUX_TYPE_UIM] = GobiNetGetClientID(qcqmi, QMUX_TYPE_UIM); + // qmiclientId[QMUX_TYPE_WDS_ADMIN] = +// GobiNetGetClientID(qcqmi, QMUX_TYPE_WDS_ADMIN); + + //if ((qmiclientId[QMUX_TYPE_WDS] == 0) && (qmiclientId[QMUX_TYPE_WDS_IPV6] == 0)) /*|| (clientWDA == -1)*/ { + + if ((qmiclientId[QMUX_TYPE_DMS] == 0) || + (qmiclientId[QMUX_TYPE_NAS] == 0) || + (qmiclientId[QMUX_TYPE_UIM] == 0) || + (profile->ipv4_flag ? ((qmiclientId[QMUX_TYPE_WDS] == 0) ? 1 : 0):0)|| + (profile->ipv6_flag ? ((qmiclientId[QMUX_TYPE_WDS_IPV6] == 0) ? 1 : 0):0)) + { + GobiNetDeInit(); + dbg_time("%s Failed to open %s, errno: %d (%s)", __func__, qcqmi, errno,strerror(errno)); + qmidevice_send_event_to_main(RIL_INDICATE_DEVICE_DISCONNECTED); + pthread_exit(NULL); + return NULL; + } + + qmidevice_send_event_to_main(RIL_INDICATE_DEVICE_CONNECTED); + + while (1) { + struct pollfd pollfds[16] = {{qmidevice_control_fd[1], POLLIN, 0}}; + int ne, ret, nevents = 1; + unsigned int i; + for (i = 0; i < sizeof(qmiclientId) / sizeof(qmiclientId[0]); i++) { + if (qmiclientId[i] != 0) { + pollfds[nevents].fd = qmiclientId[i]; + pollfds[nevents].events = POLLIN; + pollfds[nevents].revents = 0; + nevents++; + } + } + + do { + ret = poll(pollfds, nevents, wait_for_request_quit ? 1000 : -1); + } while ((ret < 0) && (errno == EINTR)); + + if (ret == 0 && wait_for_request_quit) { + QmiThreadRecvQMI( + NULL); // main thread may pending on QmiThreadSendQMI() + continue; + } + + if (ret <= 0) { + dbg_time("%s poll=%d, errno: %d (%s)", __func__, ret, errno, + strerror(errno)); + break; + } + + for (ne = 0; ne < nevents; ne++) { + int fd = pollfds[ne].fd; + short revents = pollfds[ne].revents; + + if (revents & (POLLERR | POLLHUP | POLLNVAL)) { + dbg_time("%s poll err/hup/inval", __func__); + dbg_time("epoll fd = %d, events = 0x%04x", fd, revents); + if (fd == qmidevice_control_fd[1]) { + } else { + } + if (revents & (POLLERR | POLLHUP | POLLNVAL)) + goto __GobiNetThread_quit; + } + if ((revents & POLLIN) == 0) + continue; + + if (fd == qmidevice_control_fd[1]) { + int triger_event; + if (read(fd, &triger_event, sizeof(triger_event)) == + sizeof(triger_event)) { + // DBG("triger_event = 0x%x", triger_event); + switch (triger_event) { + case RIL_REQUEST_QUIT: + goto __GobiNetThread_quit; + break; + case SIGTERM: + wait_for_request_quit = 1; + break; + default: + break; + } + } + continue; + } + + { + ssize_t nreads; + static UCHAR QMIBuf[4096]; + PQCQMIMSG pResponse = (PQCQMIMSG)QMIBuf; + + nreads = read(fd, &pResponse->MUXMsg, + sizeof(QMIBuf) - sizeof(QCQMI_HDR)); + if (nreads <= 0) { + dbg_time("%s read=%d errno: %d (%s)", __func__, (int)nreads, + errno, strerror(errno)); + break; + } + + for (i = 0; i < sizeof(qmiclientId) / sizeof(qmiclientId[0]); + i++) { + if (qmiclientId[i] == fd) { + pResponse->QMIHdr.QMIType = i; + } + } + + pResponse->QMIHdr.IFType = USB_CTL_MSG_TYPE_QMI; + pResponse->QMIHdr.Length = + cpu_to_le16(nreads + sizeof(QCQMI_HDR) - 1); + pResponse->QMIHdr.CtlFlags = 0x00; + pResponse->QMIHdr.ClientId = fd & 0xFF; + + QmiThreadRecvQMI(pResponse); + } + } + } + +__GobiNetThread_quit: + GobiNetDeInit(); + qmidevice_send_event_to_main(RIL_INDICATE_DEVICE_DISCONNECTED); + QmiThreadRecvQMI(NULL); // main thread may pending on QmiThreadSendQMI() + dbg_time("%s exit", __func__); + pthread_exit(NULL); + return NULL; +} + +#else +static int GobiNetSendQMI(PQCQMIMSG pRequest) { return -1; } +static void *GobiNetThread(void *pData) +{ + dbg_time("please set CONFIG_GOBINET"); + return NULL; +} +#endif + +const struct qmi_device_ops gobi_qmidev_ops = { + .deinit = GobiNetDeInit, + .send = GobiNetSendQMI, + .read = GobiNetThread, +}; diff --git a/package/wwan/app/fibocom-dial/src/MPQCTL.h b/package/wwan/app/fibocom-dial/src/MPQCTL.h new file mode 100755 index 000000000..42791198d --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/MPQCTL.h @@ -0,0 +1,363 @@ +/*=========================================================================== + + M P Q C T L. H +DESCRIPTION: + + This module contains QMI QCTL module. + +INITIALIZATION AND SEQUENCING REQUIREMENTS: + +Copyright (C) 2011 by Qualcomm Technologies, Incorporated. All Rights Reserved. +===========================================================================*/ + +#ifndef MPQCTL_H +#define MPQCTL_H + +#include "MPQMI.h" + +#pragma pack(push, 1) + +// ================= QMICTL ================== + +// QMICTL Control Flags +#define QMICTL_CTL_FLAG_CMD 0x00 +#define QMICTL_CTL_FLAG_RSP 0x01 +#define QMICTL_CTL_FLAG_IND 0x02 + +#if 0 +typedef struct _QMICTL_TRANSACTION_ITEM +{ + LIST_ENTRY List; + UCHAR TransactionId; // QMICTL transaction id + PVOID Context; // Adapter or IocDev + PIRP Irp; +} QMICTL_TRANSACTION_ITEM, *PQMICTL_TRANSACTION_ITEM; +#endif + +typedef struct _QCQMICTL_MSG_HDR { + UCHAR CtlFlags; // 00-cmd, 01-rsp, 10-ind + UCHAR TransactionId; + USHORT QMICTLType; + USHORT Length; +} __attribute__((packed)) QCQMICTL_MSG_HDR, *PQCQMICTL_MSG_HDR; + +#define QCQMICTL_MSG_HDR_SIZE sizeof(QCQMICTL_MSG_HDR) + +typedef struct _QCQMICTL_MSG_HDR_RESP { + UCHAR CtlFlags; // 00-cmd, 01-rsp, 10-ind + UCHAR TransactionId; + USHORT QMICTLType; + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT +} __attribute__((packed)) QCQMICTL_MSG_HDR_RESP, *PQCQMICTL_MSG_HDR_RESP; + +typedef struct _QCQMICTL_MSG { + UCHAR CtlFlags; // 00-cmd, 01-rsp, 10-ind + UCHAR TransactionId; + USHORT QMICTLType; + USHORT Length; + UCHAR Payload; +} __attribute__((packed)) QCQMICTL_MSG, *PQCQMICTL_MSG; + +// TLV Header +typedef struct _QCQMICTL_TLV_HDR { + UCHAR TLVType; + USHORT TLVLength; +} __attribute__((packed)) QCQMICTL_TLV_HDR, *PQCQMICTL_TLV_HDR; + +#define QCQMICTL_TLV_HDR_SIZE sizeof(QCQMICTL_TLV_HDR) + +// QMICTL Type +#define QMICTL_SET_INSTANCE_ID_REQ 0x0020 +#define QMICTL_SET_INSTANCE_ID_RESP 0x0020 +#define QMICTL_GET_VERSION_REQ 0x0021 +#define QMICTL_GET_VERSION_RESP 0x0021 +#define QMICTL_GET_CLIENT_ID_REQ 0x0022 +#define QMICTL_GET_CLIENT_ID_RESP 0x0022 +#define QMICTL_RELEASE_CLIENT_ID_REQ 0x0023 +#define QMICTL_RELEASE_CLIENT_ID_RESP 0x0023 +#define QMICTL_REVOKE_CLIENT_ID_IND 0x0024 +#define QMICTL_INVALID_CLIENT_ID_IND 0x0025 +#define QMICTL_SET_DATA_FORMAT_REQ 0x0026 +#define QMICTL_SET_DATA_FORMAT_RESP 0x0026 +#define QMICTL_SYNC_REQ 0x0027 +#define QMICTL_SYNC_RESP 0x0027 +#define QMICTL_SYNC_IND 0x0027 + +#define QMICTL_FLAG_REQUEST 0x00 +#define QMICTL_FLAG_RESPONSE 0x01 +#define QMICTL_FLAG_INDICATION 0x02 + +// QMICTL Message Definitions + +typedef struct _QMICTL_SET_INSTANCE_ID_REQ_MSG { + UCHAR CtlFlags; // QMICTL_FLAG_REQUEST + UCHAR TransactionId; + USHORT QMICTLType; // QMICTL_SET_INSTANCE_ID_REQ + USHORT Length; // 4 + UCHAR TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER + USHORT TLVLength; // 1 + UCHAR Value; // Host-unique QMI instance for this device driver +} __attribute__((packed)) QMICTL_SET_INSTANCE_ID_REQ_MSG, + *PQMICTL_SET_INSTANCE_ID_REQ_MSG; + +typedef struct _QMICTL_SET_INSTANCE_ID_RESP_MSG { + UCHAR CtlFlags; // QMICTL_FLAG_RESPONSE + UCHAR TransactionId; + USHORT QMICTLType; // QMICTL_SET_INSTANCE_ID_RESP + USHORT Length; + UCHAR TLVType; // QCTLV_TYPE_RESULT_CODE + USHORT TLVLength; // 0x0004 + USHORT QMIResult; + USHORT QMIError; + UCHAR TLV2Type; // QCTLV_TYPE_REQUIRED_PARAMETER + USHORT TLV2Length; // 0x0002 + USHORT QMI_ID; // Upper byte is assigned by MSM, + // lower assigned by host +} __attribute__((packed)) QMICTL_SET_INSTANCE_ID_RESP_MSG, + *PQMICTL_SET_INSTANCE_ID_RESP_MSG; + +typedef struct _QMICTL_GET_VERSION_REQ_MSG { + UCHAR CtlFlags; // QMICTL_FLAG_REQUEST + UCHAR TransactionId; + USHORT QMICTLType; // QMICTL_GET_VERSION_REQ + USHORT Length; // 0 + UCHAR TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER + USHORT TLVLength; // var + UCHAR QMUXTypes; // List of one byte QMUX_TYPE values + // 0xFF returns a list of versions for all + // QMUX_TYPEs implemented on the device +} __attribute__((packed)) QMICTL_GET_VERSION_REQ_MSG, + *PQMICTL_GET_VERSION_REQ_MSG; + +typedef struct _QMUX_TYPE_VERSION_STRUCT { + UCHAR QMUXType; + USHORT MajorVersion; + USHORT MinorVersion; +} __attribute__((packed)) QMUX_TYPE_VERSION_STRUCT, *PQMUX_TYPE_VERSION_STRUCT; + +typedef struct _ADDENDUM_VERSION_PREAMBLE { + UCHAR LabelLength; + UCHAR Label; +} __attribute__((packed)) ADDENDUM_VERSION_PREAMBLE, + *PADDENDUM_VERSION_PREAMBLE; + +#define QMICTL_GET_VERSION_RSP_TLV_TYPE_VERSION 0x01 +#define QMICTL_GET_VERSION_RSP_TLV_TYPE_ADD_VERSION 0x10 + +typedef struct _QMICTL_GET_VERSION_RESP_MSG { + UCHAR CtlFlags; // QMICTL_FLAG_RESPONSE + UCHAR TransactionId; + USHORT QMICTLType; // QMICTL_GET_VERSION_RESP + USHORT Length; + UCHAR TLVType; // QCTLV_TYPE_RESULT_CODE + USHORT TLVLength; // 0x0004 + USHORT QMIResult; + USHORT QMIError; + UCHAR TLV2Type; // QCTLV_TYPE_REQUIRED_PARAMETER + USHORT TLV2Length; // var + UCHAR NumElements; // Num of QMUX_TYPE_VERSION_STRUCT + QMUX_TYPE_VERSION_STRUCT TypeVersion[0]; +} __attribute__((packed)) QMICTL_GET_VERSION_RESP_MSG, + *PQMICTL_GET_VERSION_RESP_MSG; + +typedef struct _QMICTL_GET_CLIENT_ID_REQ_MSG { + UCHAR CtlFlags; // QMICTL_FLAG_REQUEST + UCHAR TransactionId; + USHORT QMICTLType; // QMICTL_GET_CLIENT_ID_REQ + USHORT Length; + UCHAR TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER + USHORT TLVLength; // 1 + UCHAR QMIType; // QMUX type +} __attribute__((packed)) QMICTL_GET_CLIENT_ID_REQ_MSG, + *PQMICTL_GET_CLIENT_ID_REQ_MSG; + +typedef struct _QMICTL_GET_CLIENT_ID_RESP_MSG { + UCHAR CtlFlags; // QMICTL_FLAG_RESPONSE + UCHAR TransactionId; + USHORT QMICTLType; // QMICTL_GET_CLIENT_ID_RESP + USHORT Length; + UCHAR TLVType; // QCTLV_TYPE_RESULT_CODE + USHORT TLVLength; // 0x0004 + USHORT QMIResult; // result code + USHORT QMIError; // error code + UCHAR TLV2Type; // QCTLV_TYPE_REQUIRED_PARAMETER + USHORT TLV2Length; // 2 + UCHAR QMIType; + UCHAR ClientId; +} __attribute__((packed)) QMICTL_GET_CLIENT_ID_RESP_MSG, + *PQMICTL_GET_CLIENT_ID_RESP_MSG; + +typedef struct _QMICTL_RELEASE_CLIENT_ID_REQ_MSG { + UCHAR CtlFlags; // QMICTL_FLAG_REQUEST + UCHAR TransactionId; + USHORT QMICTLType; // QMICTL_RELEASE_CLIENT_ID_REQ + USHORT Length; + UCHAR TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER + USHORT TLVLength; // 0x0002 + UCHAR QMIType; + UCHAR ClientId; +} __attribute__((packed)) QMICTL_RELEASE_CLIENT_ID_REQ_MSG, + *PQMICTL_RELEASE_CLIENT_ID_REQ_MSG; + +typedef struct _QMICTL_RELEASE_CLIENT_ID_RESP_MSG { + UCHAR CtlFlags; // QMICTL_FLAG_RESPONSE + UCHAR TransactionId; + USHORT QMICTLType; // QMICTL_RELEASE_CLIENT_ID_RESP + USHORT Length; + UCHAR TLVType; // QCTLV_TYPE_RESULT_CODE + USHORT TLVLength; // 0x0004 + USHORT QMIResult; // result code + USHORT QMIError; // error code + UCHAR TLV2Type; // QCTLV_TYPE_REQUIRED_PARAMETER + USHORT TLV2Length; // 2 + UCHAR QMIType; + UCHAR ClientId; +} __attribute__((packed)) QMICTL_RELEASE_CLIENT_ID_RESP_MSG, + *PQMICTL_RELEASE_CLIENT_ID_RESP_MSG; + +typedef struct _QMICTL_REVOKE_CLIENT_ID_IND_MSG { + UCHAR CtlFlags; // QMICTL_FLAG_INDICATION + UCHAR TransactionId; + USHORT QMICTLType; // QMICTL_REVOKE_CLIENT_ID_IND + USHORT Length; + UCHAR TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER + USHORT TLVLength; // 0x0002 + UCHAR QMIType; + UCHAR ClientId; +} __attribute__((packed)) QMICTL_REVOKE_CLIENT_ID_IND_MSG, + *PQMICTL_REVOKE_CLIENT_ID_IND_MSG; + +typedef struct _QMICTL_INVALID_CLIENT_ID_IND_MSG { + UCHAR CtlFlags; // QMICTL_FLAG_INDICATION + UCHAR TransactionId; + USHORT QMICTLType; // QMICTL_REVOKE_CLIENT_ID_IND + USHORT Length; + UCHAR TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER + USHORT TLVLength; // 0x0002 + UCHAR QMIType; + UCHAR ClientId; +} __attribute__((packed)) QMICTL_INVALID_CLIENT_ID_IND_MSG, + *PQMICTL_INVALID_CLIENT_ID_IND_MSG; + +typedef struct _QMICTL_SET_DATA_FORMAT_REQ_MSG { + UCHAR CtlFlags; // QMICTL_FLAG_REQUEST + UCHAR TransactionId; + USHORT QMICTLType; // QMICTL_SET_DATA_FORMAT_REQ + USHORT Length; + UCHAR TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER + USHORT TLVLength; // 1 + UCHAR DataFormat; // 0-default; 1-QoS hdr present +} __attribute__((packed)) QMICTL_SET_DATA_FORMAT_REQ_MSG, + *PQMICTL_SET_DATA_FORMAT_REQ_MSG; + +#ifdef QC_IP_MODE +#define SET_DATA_FORMAT_TLV_TYPE_LINK_PROTO 0x10 +#define SET_DATA_FORMAT_LINK_PROTO_ETH 0x0001 +#define SET_DATA_FORMAT_LINK_PROTO_IP 0x0002 +typedef struct _QMICTL_SET_DATA_FORMAT_TLV_LINK_PROT { + UCHAR TLVType; // Link-Layer Protocol + USHORT TLVLength; // 2 + USHORT LinkProt; // 0x1: ETH; 0x2: IP +} QMICTL_SET_DATA_FORMAT_TLV_LINK_PROT, *PQMICTL_SET_DATA_FORMAT_TLV_LINK_PROT; + +#ifdef QCMP_UL_TLP +#define SET_DATA_FORMAT_TLV_TYPE_UL_TLP 0x11 +typedef struct _QMICTL_SET_DATA_FORMAT_TLV_UL_TLP { + UCHAR TLVType; // 0x11, Uplink TLP Setting + USHORT TLVLength; // 1 + UCHAR UlTlpSetting; // 0x0: Disable; 0x01: Enable +} QMICTL_SET_DATA_FORMAT_TLV_UL_TLP, *PQMICTL_SET_DATA_FORMAT_TLV_UL_TLP; +#endif // QCMP_UL_TLP + +#ifdef QCMP_DL_TLP +#define SET_DATA_FORMAT_TLV_TYPE_DL_TLP 0x13 +typedef struct _QMICTL_SET_DATA_FORMAT_TLV_DL_TLP { + UCHAR TLVType; // 0x11, Uplink TLP Setting + USHORT TLVLength; // 1 + UCHAR DlTlpSetting; // 0x0: Disable; 0x01: Enable +} QMICTL_SET_DATA_FORMAT_TLV_DL_TLP, *PQMICTL_SET_DATA_FORMAT_TLV_DL_TLP; +#endif // QCMP_DL_TLP + +#endif // QC_IP_MODE + +#ifdef MP_QCQOS_ENABLED +#define SET_DATA_FORMAT_TLV_TYPE_QOS_SETTING 0x12 +typedef struct _QMICTL_SET_DATA_FORMAT_TLV_QOS_SETTING { + UCHAR TLVType; // 0x12, QoS setting + USHORT TLVLength; // 1 + UCHAR QosSetting; // 0x0: Disable; 0x01: Enable +} QMICTL_SET_DATA_FORMAT_TLV_QOS_SETTING, + *PQMICTL_SET_DATA_FORMAT_TLV_QOS_SETTING; +#endif // MP_QCQOS_ENABLED + +typedef struct _QMICTL_SET_DATA_FORMAT_RESP_MSG { + UCHAR CtlFlags; // QMICTL_FLAG_RESPONSE + UCHAR TransactionId; + USHORT QMICTLType; // QMICTL_SET_DATA_FORMAT_RESP + USHORT Length; + UCHAR TLVType; // QCTLV_TYPE_RESULT_CODE + USHORT TLVLength; // 0x0004 + USHORT QMIResult; // result code + USHORT QMIError; // error code +} __attribute__((packed)) QMICTL_SET_DATA_FORMAT_RESP_MSG, + *PQMICTL_SET_DATA_FORMAT_RESP_MSG; + +typedef struct _QMICTL_SYNC_REQ_MSG { + UCHAR CtlFlags; // QMICTL_FLAG_REQUEST + UCHAR TransactionId; + USHORT QMICTLType; // QMICTL_CTL_SYNC_REQ + USHORT Length; // 0 +} __attribute__((packed)) QMICTL_SYNC_REQ_MSG, *PQMICTL_SYNC_REQ_MSG; + +typedef struct _QMICTL_SYNC_RESP_MSG { + UCHAR CtlFlags; // QMICTL_FLAG_RESPONSE + UCHAR TransactionId; + USHORT QMICTLType; // QMICTL_CTL_SYNC_RESP + USHORT Length; + UCHAR TLVType; // QCTLV_TYPE_RESULT_CODE + USHORT TLVLength; // 0x0004 + USHORT QMIResult; + USHORT QMIError; +} __attribute__((packed)) QMICTL_SYNC_RESP_MSG, *PQMICTL_SYNC_RESP_MSG; + +typedef struct _QMICTL_SYNC_IND_MSG { + UCHAR CtlFlags; // QMICTL_FLAG_INDICATION + UCHAR TransactionId; + USHORT QMICTLType; // QMICTL_REVOKE_CLIENT_ID_IND + USHORT Length; +} __attribute__((packed)) QMICTL_SYNC_IND_MSG, *PQMICTL_SYNC_IND_MSG; + +typedef struct _QMICTL_MSG { + union { + // Message Header + QCQMICTL_MSG_HDR QMICTLMsgHdr; + QCQMICTL_MSG_HDR_RESP QMICTLMsgHdrRsp; + + // QMICTL Message + QMICTL_SET_INSTANCE_ID_REQ_MSG SetInstanceIdReq; + QMICTL_SET_INSTANCE_ID_RESP_MSG SetInstanceIdRsp; + QMICTL_GET_VERSION_REQ_MSG GetVersionReq; + QMICTL_GET_VERSION_RESP_MSG GetVersionRsp; + QMICTL_GET_CLIENT_ID_REQ_MSG GetClientIdReq; + QMICTL_GET_CLIENT_ID_RESP_MSG GetClientIdRsp; + QMICTL_RELEASE_CLIENT_ID_REQ_MSG ReleaseClientIdReq; + QMICTL_RELEASE_CLIENT_ID_RESP_MSG ReleaseClientIdRsp; + QMICTL_REVOKE_CLIENT_ID_IND_MSG RevokeClientIdInd; + QMICTL_INVALID_CLIENT_ID_IND_MSG InvalidClientIdInd; + QMICTL_SET_DATA_FORMAT_REQ_MSG SetDataFormatReq; + QMICTL_SET_DATA_FORMAT_RESP_MSG SetDataFormatRsp; + QMICTL_SYNC_REQ_MSG SyncReq; + QMICTL_SYNC_RESP_MSG SyncRsp; + QMICTL_SYNC_IND_MSG SyncInd; + }; +} __attribute__((packed)) QMICTL_MSG, *PQMICTL_MSG; + +#endif // MPQCTL_H diff --git a/package/wwan/app/fibocom-dial/src/MPQMI.h b/package/wwan/app/fibocom-dial/src/MPQMI.h new file mode 100755 index 000000000..aa23ced4f --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/MPQMI.h @@ -0,0 +1,287 @@ +/*=========================================================================== + + M P Q M I. H +DESCRIPTION: + + This module contains forward references to the QMI module. + +INITIALIZATION AND SEQUENCING REQUIREMENTS: + +Copyright (C) 2011 by Qualcomm Technologies, Incorporated. All Rights Reserved. +===========================================================================*/ +/*=========================================================================== + + EDIT HISTORY FOR FILE + $Header: //depot/QMI/win/qcdrivers/ndis/MPQMI.h#3 $ + +when who what, where, why +-------- --- ---------------------------------------------------------- +11/20/04 hg Initial version. +===========================================================================*/ + +#ifndef USBQMI_H +#define USBQMI_H + +typedef char CHAR; +typedef unsigned char UCHAR; +typedef unsigned short USHORT; +typedef int INT; +typedef unsigned int UINT; +typedef long LONG; +typedef unsigned int ULONG; +typedef unsigned long long ULONG64; +typedef char *PCHAR; +typedef unsigned char *PUCHAR; +typedef int *PINT; +typedef int BOOL; + +#define TRUE (1 == 1) +#define FALSE (1 != 1) + +#define QMICTL_SUPPORTED_MAJOR_VERSION 1 +#define QMICTL_SUPPORTED_MINOR_VERSION 0 + +#pragma pack(push, 1) + +// ========= USB Control Message ========== + +#define USB_CTL_MSG_TYPE_QMI 0x01 + +// USB Control Message +typedef struct _QCUSB_CTL_MSG_HDR { + UCHAR IFType; +} __attribute__((packed)) QCUSB_CTL_MSG_HDR, *PQCUSB_CTL_MSG_HDR; + +#define QCUSB_CTL_MSG_HDR_SIZE sizeof(QCUSB_CTL_MSG_HDR) + +typedef struct _QCUSB_CTL_MSG { + UCHAR IFType; + UCHAR Message; +} __attribute__((packed)) QCUSB_CTL_MSG, *PQCUSB_CTL_MSG; + +#define QCTLV_TYPE_REQUIRED_PARAMETER 0x01 +#define QCTLV_TYPE_RESULT_CODE 0x02 + +// ================= QMI ================== + +// Define QMI Type +typedef enum _QMI_SERVICE_TYPE { + QMUX_TYPE_CTL = 0x00, + QMUX_TYPE_WDS = 0x01, + QMUX_TYPE_DMS = 0x02, + QMUX_TYPE_NAS = 0x03, + QMUX_TYPE_QOS = 0x04, + QMUX_TYPE_WMS = 0x05, + QMUX_TYPE_PDS = 0x06, + QMUX_TYPE_UIM = 0x0B, + QMUX_TYPE_WDS_IPV6 = 0x11, + QMUX_TYPE_WDS_ADMIN = 0x1A, + QMUX_TYPE_MAX = 0xFF, + QMUX_TYPE_ALL = 0xFF +} QMI_SERVICE_TYPE; + +typedef enum _QMI_RESULT_CODE_TYPE { + QMI_RESULT_SUCCESS = 0x0000, + QMI_RESULT_FAILURE = 0x0001 +} QMI_RESULT_CODE_TYPE; + +typedef enum _QMI_ERROR_CODE_TYPE { + QMI_ERR_NONE = 0x0000, + QMI_ERR_MALFORMED_MSG = 0x0001, + QMI_ERR_NO_MEMORY = 0x0002, + QMI_ERR_INTERNAL = 0x0003, + QMI_ERR_ABORTED = 0x0004, + QMI_ERR_CLIENT_IDS_EXHAUSTED = 0x0005, + QMI_ERR_UNABORTABLE_TRANSACTION = 0x0006, + QMI_ERR_INVALID_CLIENT_ID = 0x0007, + QMI_ERR_NO_THRESHOLDS = 0x0008, + QMI_ERR_INVALID_HANDLE = 0x0009, + QMI_ERR_INVALID_PROFILE = 0x000A, + QMI_ERR_INVALID_PINID = 0x000B, + QMI_ERR_INCORRECT_PIN = 0x000C, + QMI_ERR_NO_NETWORK_FOUND = 0x000D, + QMI_ERR_CALL_FAILED = 0x000E, + QMI_ERR_OUT_OF_CALL = 0x000F, + QMI_ERR_NOT_PROVISIONED = 0x0010, + QMI_ERR_MISSING_ARG = 0x0011, + QMI_ERR_ARG_TOO_LONG = 0x0013, + QMI_ERR_INVALID_TX_ID = 0x0016, + QMI_ERR_DEVICE_IN_USE = 0x0017, + QMI_ERR_OP_NETWORK_UNSUPPORTED = 0x0018, + QMI_ERR_OP_DEVICE_UNSUPPORTED = 0x0019, + QMI_ERR_NO_EFFECT = 0x001A, + QMI_ERR_NO_FREE_PROFILE = 0x001B, + QMI_ERR_INVALID_PDP_TYPE = 0x001C, + QMI_ERR_INVALID_TECH_PREF = 0x001D, + QMI_ERR_INVALID_PROFILE_TYPE = 0x001E, + QMI_ERR_INVALID_SERVICE_TYPE = 0x001F, + QMI_ERR_INVALID_REGISTER_ACTION = 0x0020, + QMI_ERR_INVALID_PS_ATTACH_ACTION = 0x0021, + QMI_ERR_AUTHENTICATION_FAILED = 0x0022, + QMI_ERR_PIN_BLOCKED = 0x0023, + QMI_ERR_PIN_PERM_BLOCKED = 0x0024, + QMI_ERR_SIM_NOT_INITIALIZED = 0x0025, + QMI_ERR_MAX_QOS_REQUESTS_IN_USE = 0x0026, + QMI_ERR_INCORRECT_FLOW_FILTER = 0x0027, + QMI_ERR_NETWORK_QOS_UNAWARE = 0x0028, + QMI_ERR_INVALID_QOS_ID = 0x0029, + QMI_ERR_INVALID_ID = 0x0029, + QMI_ERR_REQUESTED_NUM_UNSUPPORTED = 0x002A, + QMI_ERR_INTERFACE_NOT_FOUND = 0x002B, + QMI_ERR_FLOW_SUSPENDED = 0x002C, + QMI_ERR_INVALID_DATA_FORMAT = 0x002D, + QMI_ERR_GENERAL = 0x002E, + QMI_ERR_UNKNOWN = 0x002F, + QMI_ERR_INVALID_ARG = 0x0030, + QMI_ERR_INVALID_INDEX = 0x0031, + QMI_ERR_NO_ENTRY = 0x0032, + QMI_ERR_DEVICE_STORAGE_FULL = 0x0033, + QMI_ERR_DEVICE_NOT_READY = 0x0034, + QMI_ERR_NETWORK_NOT_READY = 0x0035, + QMI_ERR_CAUSE_CODE = 0x0036, + QMI_ERR_MESSAGE_NOT_SENT = 0x0037, + QMI_ERR_MESSAGE_DELIVERY_FAILURE = 0x0038, + QMI_ERR_INVALID_MESSAGE_ID = 0x0039, + QMI_ERR_ENCODING = 0x003A, + QMI_ERR_AUTHENTICATION_LOCK = 0x003B, + QMI_ERR_INVALID_TRANSITION = 0x003C, + QMI_ERR_NOT_A_MCAST_IFACE = 0x003D, + QMI_ERR_MAX_MCAST_REQUESTS_IN_USE = 0x003E, + QMI_ERR_INVALID_MCAST_HANDLE = 0x003F, + QMI_ERR_INVALID_IP_FAMILY_PREF = 0x0040, + QMI_ERR_SESSION_INACTIVE = 0x0041, + QMI_ERR_SESSION_INVALID = 0x0042, + QMI_ERR_SESSION_OWNERSHIP = 0x0043, + QMI_ERR_INSUFFICIENT_RESOURCES = 0x0044, + QMI_ERR_DISABLED = 0x0045, + QMI_ERR_INVALID_OPERATION = 0x0046, + QMI_ERR_INVALID_QMI_CMD = 0x0047, + QMI_ERR_TPDU_TYPE = 0x0048, + QMI_ERR_SMSC_ADDR = 0x0049, + QMI_ERR_INFO_UNAVAILABLE = 0x004A, + QMI_ERR_SEGMENT_TOO_LONG = 0x004B, + QMI_ERR_SEGMENT_ORDER = 0x004C, + QMI_ERR_BUNDLING_NOT_SUPPORTED = 0x004D, + QMI_ERR_OP_PARTIAL_FAILURE = 0x004E, + QMI_ERR_POLICY_MISMATCH = 0x004F, + QMI_ERR_SIM_FILE_NOT_FOUND = 0x0050, + QMI_ERR_EXTENDED_INTERNAL = 0x0051, + QMI_ERR_ACCESS_DENIED = 0x0052, + QMI_ERR_HARDWARE_RESTRICTED = 0x0053, + QMI_ERR_ACK_NOT_SENT = 0x0054, + QMI_ERR_INJECT_TIMEOUT = 0x0055, + QMI_ERR_INCOMPATIBLE_STATE = 0x005A, + QMI_ERR_FDN_RESTRICT = 0x005B, + QMI_ERR_SUPS_FAILURE_CAUSE = 0x005C, + QMI_ERR_NO_RADIO = 0x005D, + QMI_ERR_NOT_SUPPORTED = 0x005E, + QMI_ERR_NO_SUBSCRIPTION = 0x005F, + QMI_ERR_CARD_CALL_CONTROL_FAILED = 0x0060, + QMI_ERR_NETWORK_ABORTED = 0x0061, + QMI_ERR_MSG_BLOCKED = 0x0062, + QMI_ERR_INVALID_SESSION_TYPE = 0x0064, + QMI_ERR_INVALID_PB_TYPE = 0x0065, + QMI_ERR_NO_SIM = 0x0066, + QMI_ERR_PB_NOT_READY = 0x0067, + QMI_ERR_PIN_RESTRICTION = 0x0068, + QMI_ERR_PIN2_RESTRICTION = 0x0069, + QMI_ERR_PUK_RESTRICTION = 0x006A, + QMI_ERR_PUK2_RESTRICTION = 0x006B, + QMI_ERR_PB_ACCESS_RESTRICTED = 0x006C, + QMI_ERR_PB_DELETE_IN_PROG = 0x006D, + QMI_ERR_PB_TEXT_TOO_LONG = 0x006E, + QMI_ERR_PB_NUMBER_TOO_LONG = 0x006F, + QMI_ERR_PB_HIDDEN_KEY_RESTRICTION = 0x0070 +} QMI_ERROR_CODE_TYPE; + +#define QCQMI_CTL_FLAG_SERVICE 0x80 +#define QCQMI_CTL_FLAG_CTL_POINT 0x00 + +typedef struct _QCQMI_HDR { + UCHAR IFType; + USHORT Length; + UCHAR CtlFlags; // reserved + UCHAR QMIType; + UCHAR ClientId; +} __attribute__((packed)) QCQMI_HDR, *PQCQMI_HDR; + +#define QCQMI_HDR_SIZE (sizeof(QCQMI_HDR) - 1) + +typedef struct _QCQMI { + UCHAR IFType; + USHORT Length; + UCHAR CtlFlags; // reserved + UCHAR QMIType; + UCHAR ClientId; + UCHAR SDU; +} __attribute__((packed)) QCQMI, *PQCQMI; + +typedef struct _QMI_SERVICE_VERSION { + USHORT Major; + USHORT Minor; + USHORT AddendumMajor; + USHORT AddendumMinor; +} __attribute__((packed)) QMI_SERVICE_VERSION, *PQMI_SERVICE_VERSION; + +// ================= QMUX ================== + +#define QMUX_MSG_OVERHEAD_BYTES 4 // Type(USHORT) Length(USHORT) -- header + +#define QMUX_BROADCAST_CID 0xFF + +typedef struct _QCQMUX_HDR { + UCHAR CtlFlags; // 0: single QMUX Msg; 1: + USHORT TransactionId; +} __attribute__((packed)) QCQMUX_HDR, *PQCQMUX_HDR; + +typedef struct _QCQMUX { + UCHAR CtlFlags; // 0: single QMUX Msg; 1: + USHORT TransactionId; + UCHAR Message; // Type(2), Length(2), Value +} __attribute__((packed)) QCQMUX, *PQCQMUX; + +#define QCQMUX_HDR_SIZE sizeof(QCQMUX_HDR) + +typedef struct _QCQMUX_MSG_HDR { + USHORT Type; + USHORT Length; +} __attribute__((packed)) QCQMUX_MSG_HDR, *PQCQMUX_MSG_HDR; + +#define QCQMUX_MSG_HDR_SIZE sizeof(QCQMUX_MSG_HDR) + +typedef struct _QCQMUX_MSG_HDR_RESP { + USHORT Type; + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT +} __attribute__((packed)) QCQMUX_MSG_HDR_RESP, *PQCQMUX_MSG_HDR_RESP; + +typedef struct _QCQMUX_TLV { + UCHAR Type; + USHORT Length; + UCHAR Value; +} __attribute__((packed)) QCQMUX_TLV, *PQCQMUX_TLV; + +typedef struct _QMI_TLV_HDR { + UCHAR TLVType; + USHORT TLVLength; +} __attribute__((packed)) QMI_TLV_HDR, *PQMI_TLV_HDR; + +// QMUX Message Definitions -- QMI SDU +#define QMUX_CTL_FLAG_SINGLE_MSG 0x00 +#define QMUX_CTL_FLAG_COMPOUND_MSG 0x01 +#define QMUX_CTL_FLAG_TYPE_CMD 0x00 +#define QMUX_CTL_FLAG_TYPE_RSP 0x02 +#define QMUX_CTL_FLAG_TYPE_IND 0x04 +#define QMUX_CTL_FLAG_MASK_COMPOUND 0x01 +#define QMUX_CTL_FLAG_MASK_TYPE 0x06 // 00-cmd, 01-rsp, 10-ind + +#pragma pack(pop) + +#endif // USBQMI_H diff --git a/package/wwan/app/fibocom-dial/src/MPQMUX.c b/package/wwan/app/fibocom-dial/src/MPQMUX.c new file mode 100755 index 000000000..724ba9ea7 --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/MPQMUX.c @@ -0,0 +1,437 @@ +#include "QMIThread.h" +static char line[1024]; +static pthread_mutex_t dumpQMIMutex = PTHREAD_MUTEX_INITIALIZER; +#undef dbg +#define dbg(format, arg...) \ + do { \ + if (strlen(line) < sizeof(line)) \ + snprintf(&line[strlen(line)], sizeof(line) - strlen(line), format, \ + ##arg); \ + } while (0) + +PQMI_TLV_HDR GetTLV(PQCQMUX_MSG_HDR pQMUXMsgHdr, int TLVType); + +typedef struct { + UINT type; + const char *name; +} QMI_NAME_T; + +#define qmi_name_item(type) \ + { \ + type, #type \ + } + +static const QMI_NAME_T qmux_ctl_QMICTLType[] = { + // QMICTL Type + qmi_name_item(QMICTL_SET_INSTANCE_ID_REQ), // 0x0020 + qmi_name_item(QMICTL_SET_INSTANCE_ID_RESP), // 0x0020 + qmi_name_item(QMICTL_GET_VERSION_REQ), // 0x0021 + qmi_name_item(QMICTL_GET_VERSION_RESP), // 0x0021 + qmi_name_item(QMICTL_GET_CLIENT_ID_REQ), // 0x0022 + qmi_name_item(QMICTL_GET_CLIENT_ID_RESP), // 0x0022 + qmi_name_item(QMICTL_RELEASE_CLIENT_ID_REQ), // 0x0023 + qmi_name_item(QMICTL_RELEASE_CLIENT_ID_RESP), // 0x0023 + qmi_name_item(QMICTL_REVOKE_CLIENT_ID_IND), // 0x0024 + qmi_name_item(QMICTL_INVALID_CLIENT_ID_IND), // 0x0025 + qmi_name_item(QMICTL_SET_DATA_FORMAT_REQ), // 0x0026 + qmi_name_item(QMICTL_SET_DATA_FORMAT_RESP), // 0x0026 + qmi_name_item(QMICTL_SYNC_REQ), // 0x0027 + qmi_name_item(QMICTL_SYNC_RESP), // 0x0027 + qmi_name_item(QMICTL_SYNC_IND), // 0x0027 +}; + +static const QMI_NAME_T qmux_CtlFlags[] = { + qmi_name_item(QMUX_CTL_FLAG_TYPE_CMD), + qmi_name_item(QMUX_CTL_FLAG_TYPE_RSP), + qmi_name_item(QMUX_CTL_FLAG_TYPE_IND), +}; + +static const QMI_NAME_T qmux_wds_Type[] = { + qmi_name_item(QMIWDS_SET_EVENT_REPORT_REQ), // 0x0001 + qmi_name_item(QMIWDS_SET_EVENT_REPORT_RESP), // 0x0001 + qmi_name_item(QMIWDS_EVENT_REPORT_IND), // 0x0001 + qmi_name_item(QMIWDS_START_NETWORK_INTERFACE_REQ), // 0x0020 + qmi_name_item(QMIWDS_START_NETWORK_INTERFACE_RESP), // 0x0020 + qmi_name_item(QMIWDS_STOP_NETWORK_INTERFACE_REQ), // 0x0021 + qmi_name_item(QMIWDS_STOP_NETWORK_INTERFACE_RESP), // 0x0021 + qmi_name_item(QMIWDS_GET_PKT_SRVC_STATUS_REQ), // 0x0022 + qmi_name_item(QMIWDS_GET_PKT_SRVC_STATUS_RESP), // 0x0022 + qmi_name_item(QMIWDS_GET_PKT_SRVC_STATUS_IND), // 0x0022 + qmi_name_item(QMIWDS_GET_CURRENT_CHANNEL_RATE_REQ), // 0x0023 + qmi_name_item(QMIWDS_GET_CURRENT_CHANNEL_RATE_RESP), // 0x0023 + qmi_name_item(QMIWDS_GET_PKT_STATISTICS_REQ), // 0x0024 + qmi_name_item(QMIWDS_GET_PKT_STATISTICS_RESP), // 0x0024 +//begin modified by zhangkaibo add create profile qmi. mantis 0049137,0048741 20200610 + qmi_name_item(QMIWDS_CREATE_PROFILE_SETTINGS_REQ), // 0x0027 + qmi_name_item(QMIWDS_CREATE_PROFILE_SETTINGS_RESP), // 0x0027 +//end modified by zhangkaibo add create profile qmi. mantis 0049137,0048741 20200610 + qmi_name_item(QMIWDS_MODIFY_PROFILE_SETTINGS_REQ), // 0x0028 + qmi_name_item(QMIWDS_MODIFY_PROFILE_SETTINGS_RESP), // 0x0028 + qmi_name_item(QMIWDS_GET_PROFILE_SETTINGS_REQ), // 0x002B + qmi_name_item(QMIWDS_GET_PROFILE_SETTINGS_RESP), // 0x002BD + qmi_name_item(QMIWDS_GET_DEFAULT_SETTINGS_REQ), // 0x002C + qmi_name_item(QMIWDS_GET_DEFAULT_SETTINGS_RESP), // 0x002C + qmi_name_item(QMIWDS_GET_RUNTIME_SETTINGS_REQ), // 0x002D + qmi_name_item(QMIWDS_GET_RUNTIME_SETTINGS_RESP), // 0x002D + qmi_name_item(QMIWDS_GET_MIP_MODE_REQ), // 0x002F + qmi_name_item(QMIWDS_GET_MIP_MODE_RESP), // 0x002F + qmi_name_item(QMIWDS_GET_DATA_BEARER_REQ), // 0x0037 + qmi_name_item(QMIWDS_GET_DATA_BEARER_RESP), // 0x0037 + qmi_name_item(QMIWDS_DUN_CALL_INFO_REQ), // 0x0038 + qmi_name_item(QMIWDS_DUN_CALL_INFO_RESP), // 0x0038 + qmi_name_item(QMIWDS_DUN_CALL_INFO_IND), // 0x0038 + qmi_name_item(QMIWDS_SET_CLIENT_IP_FAMILY_PREF_REQ), // 0x004D + qmi_name_item(QMIWDS_SET_CLIENT_IP_FAMILY_PREF_RESP), // 0x004D + qmi_name_item(QMIWDS_SET_AUTO_CONNECT_REQ), // 0x0051 + qmi_name_item(QMIWDS_SET_AUTO_CONNECT_RESP), // 0x0051 + qmi_name_item(QMIWDS_BIND_MUX_DATA_PORT_REQ), // 0x00A2 + qmi_name_item(QMIWDS_BIND_MUX_DATA_PORT_RESP), // 0x00A2 +}; + +static const QMI_NAME_T qmux_dms_Type[] = { + // ======================= DMS ============================== + qmi_name_item(QMIDMS_SET_EVENT_REPORT_REQ), // 0x0001 + qmi_name_item(QMIDMS_SET_EVENT_REPORT_RESP), // 0x0001 + qmi_name_item(QMIDMS_EVENT_REPORT_IND), // 0x0001 + qmi_name_item(QMIDMS_GET_DEVICE_CAP_REQ), // 0x0020 + qmi_name_item(QMIDMS_GET_DEVICE_CAP_RESP), // 0x0020 + qmi_name_item(QMIDMS_GET_DEVICE_MFR_REQ), // 0x0021 + qmi_name_item(QMIDMS_GET_DEVICE_MFR_RESP), // 0x0021 + qmi_name_item(QMIDMS_GET_DEVICE_MODEL_ID_REQ), // 0x0022 + qmi_name_item(QMIDMS_GET_DEVICE_MODEL_ID_RESP), // 0x0022 + qmi_name_item(QMIDMS_GET_DEVICE_REV_ID_REQ), // 0x0023 + qmi_name_item(QMIDMS_GET_DEVICE_REV_ID_RESP), // 0x0023 + qmi_name_item(QMIDMS_GET_MSISDN_REQ), // 0x0024 + qmi_name_item(QMIDMS_GET_MSISDN_RESP), // 0x0024 + qmi_name_item(QMIDMS_GET_DEVICE_SERIAL_NUMBERS_REQ), // 0x0025 + qmi_name_item(QMIDMS_GET_DEVICE_SERIAL_NUMBERS_RESP), // 0x0025 + qmi_name_item(QMIDMS_UIM_SET_PIN_PROTECTION_REQ), // 0x0027 + qmi_name_item(QMIDMS_UIM_SET_PIN_PROTECTION_RESP), // 0x0027 + qmi_name_item(QMIDMS_UIM_VERIFY_PIN_REQ), // 0x0028 + qmi_name_item(QMIDMS_UIM_VERIFY_PIN_RESP), // 0x0028 + qmi_name_item(QMIDMS_UIM_UNBLOCK_PIN_REQ), // 0x0029 + qmi_name_item(QMIDMS_UIM_UNBLOCK_PIN_RESP), // 0x0029 + qmi_name_item(QMIDMS_UIM_CHANGE_PIN_REQ), // 0x002A + qmi_name_item(QMIDMS_UIM_CHANGE_PIN_RESP), // 0x002A + qmi_name_item(QMIDMS_UIM_GET_PIN_STATUS_REQ), // 0x002B + qmi_name_item(QMIDMS_UIM_GET_PIN_STATUS_RESP), // 0x002B + qmi_name_item(QMIDMS_GET_DEVICE_HARDWARE_REV_REQ), // 0x002C + qmi_name_item(QMIDMS_GET_DEVICE_HARDWARE_REV_RESP), // 0x002C + qmi_name_item(QMIDMS_GET_OPERATING_MODE_REQ), // 0x002D + qmi_name_item(QMIDMS_GET_OPERATING_MODE_RESP), // 0x002D + qmi_name_item(QMIDMS_SET_OPERATING_MODE_REQ), // 0x002E + qmi_name_item(QMIDMS_SET_OPERATING_MODE_RESP), // 0x002E + qmi_name_item(QMIDMS_GET_ACTIVATED_STATUS_REQ), // 0x0031 + qmi_name_item(QMIDMS_GET_ACTIVATED_STATUS_RESP), // 0x0031 + qmi_name_item(QMIDMS_ACTIVATE_AUTOMATIC_REQ), // 0x0032 + qmi_name_item(QMIDMS_ACTIVATE_AUTOMATIC_RESP), // 0x0032 + qmi_name_item(QMIDMS_ACTIVATE_MANUAL_REQ), // 0x0033 + qmi_name_item(QMIDMS_ACTIVATE_MANUAL_RESP), // 0x0033 + qmi_name_item(QMIDMS_UIM_GET_ICCID_REQ), // 0x003C + qmi_name_item(QMIDMS_UIM_GET_ICCID_RESP), // 0x003C + qmi_name_item(QMIDMS_UIM_GET_CK_STATUS_REQ), // 0x0040 + qmi_name_item(QMIDMS_UIM_GET_CK_STATUS_RESP), // 0x0040 + qmi_name_item(QMIDMS_UIM_SET_CK_PROTECTION_REQ), // 0x0041 + qmi_name_item(QMIDMS_UIM_SET_CK_PROTECTION_RESP), // 0x0041 + qmi_name_item(QMIDMS_UIM_UNBLOCK_CK_REQ), // 0x0042 + qmi_name_item(QMIDMS_UIM_UNBLOCK_CK_RESP), // 0x0042 + qmi_name_item(QMIDMS_UIM_GET_IMSI_REQ), // 0x0043 + qmi_name_item(QMIDMS_UIM_GET_IMSI_RESP), // 0x0043 + qmi_name_item(QMIDMS_UIM_GET_STATE_REQ), // 0x0044 + qmi_name_item(QMIDMS_UIM_GET_STATE_RESP), // 0x0044 + qmi_name_item(QMIDMS_GET_BAND_CAP_REQ), // 0x0045 + qmi_name_item(QMIDMS_GET_BAND_CAP_RESP), // 0x0045 +}; + +static const QMI_NAME_T qmux_nas_Type[] = { + // ======================= NAS ============================== + qmi_name_item(QMINAS_SET_EVENT_REPORT_REQ), // 0x0002 + qmi_name_item(QMINAS_SET_EVENT_REPORT_RESP), // 0x0002 + qmi_name_item(QMINAS_EVENT_REPORT_IND), // 0x0002 + qmi_name_item(QMINAS_GET_SIGNAL_STRENGTH_REQ), // 0x0020 + qmi_name_item(QMINAS_GET_SIGNAL_STRENGTH_RESP), // 0x0020 + qmi_name_item(QMINAS_PERFORM_NETWORK_SCAN_REQ), // 0x0021 + qmi_name_item(QMINAS_PERFORM_NETWORK_SCAN_RESP), // 0x0021 + qmi_name_item(QMINAS_INITIATE_NW_REGISTER_REQ), // 0x0022 + qmi_name_item(QMINAS_INITIATE_NW_REGISTER_RESP), // 0x0022 + qmi_name_item(QMINAS_INITIATE_ATTACH_REQ), // 0x0023 + qmi_name_item(QMINAS_INITIATE_ATTACH_RESP), // 0x0023 + qmi_name_item(QMINAS_GET_SERVING_SYSTEM_REQ), // 0x0024 + qmi_name_item(QMINAS_GET_SERVING_SYSTEM_RESP), // 0x0024 + qmi_name_item(QMINAS_SERVING_SYSTEM_IND), // 0x0024 + qmi_name_item(QMINAS_GET_HOME_NETWORK_REQ), // 0x0025 + qmi_name_item(QMINAS_GET_HOME_NETWORK_RESP), // 0x0025 + qmi_name_item(QMINAS_GET_PREFERRED_NETWORK_REQ), // 0x0026 + qmi_name_item(QMINAS_GET_PREFERRED_NETWORK_RESP), // 0x0026 + qmi_name_item(QMINAS_SET_PREFERRED_NETWORK_REQ), // 0x0027 + qmi_name_item(QMINAS_SET_PREFERRED_NETWORK_RESP), // 0x0027 + qmi_name_item(QMINAS_GET_FORBIDDEN_NETWORK_REQ), // 0x0028 + qmi_name_item(QMINAS_GET_FORBIDDEN_NETWORK_RESP), // 0x0028 + qmi_name_item(QMINAS_SET_FORBIDDEN_NETWORK_REQ), // 0x0029 + qmi_name_item(QMINAS_SET_FORBIDDEN_NETWORK_RESP), // 0x0029 + qmi_name_item(QMINAS_SET_TECHNOLOGY_PREF_REQ), // 0x002A + qmi_name_item(QMINAS_SET_TECHNOLOGY_PREF_RESP), // 0x002A + qmi_name_item(QMINAS_GET_RF_BAND_INFO_REQ), // 0x0031 + qmi_name_item(QMINAS_GET_RF_BAND_INFO_RESP), // 0x0031 + qmi_name_item(QMINAS_GET_PLMN_NAME_REQ), // 0x0044 + qmi_name_item(QMINAS_GET_PLMN_NAME_RESP), // 0x0044 + qmi_name_item(FIBO_PACKET_TRANSFER_START_IND), // 0X100 + qmi_name_item(FIBO_PACKET_TRANSFER_END_IND), // 0X101 + qmi_name_item(QMINAS_GET_SYS_INFO_REQ), // 0x004D + qmi_name_item(QMINAS_GET_SYS_INFO_RESP), // 0x004D + qmi_name_item(QMINAS_SYS_INFO_IND), // 0x004D +}; + +static const QMI_NAME_T qmux_wms_Type[] = { + // ======================= WMS ============================== + qmi_name_item(QMIWMS_SET_EVENT_REPORT_REQ), // 0x0001 + qmi_name_item(QMIWMS_SET_EVENT_REPORT_RESP), // 0x0001 + qmi_name_item(QMIWMS_EVENT_REPORT_IND), // 0x0001 + qmi_name_item(QMIWMS_RAW_SEND_REQ), // 0x0020 + qmi_name_item(QMIWMS_RAW_SEND_RESP), // 0x0020 + qmi_name_item(QMIWMS_RAW_WRITE_REQ), // 0x0021 + qmi_name_item(QMIWMS_RAW_WRITE_RESP), // 0x0021 + qmi_name_item(QMIWMS_RAW_READ_REQ), // 0x0022 + qmi_name_item(QMIWMS_RAW_READ_RESP), // 0x0022 + qmi_name_item(QMIWMS_MODIFY_TAG_REQ), // 0x0023 + qmi_name_item(QMIWMS_MODIFY_TAG_RESP), // 0x0023 + qmi_name_item(QMIWMS_DELETE_REQ), // 0x0024 + qmi_name_item(QMIWMS_DELETE_RESP), // 0x0024 + qmi_name_item(QMIWMS_GET_MESSAGE_PROTOCOL_REQ), // 0x0030 + qmi_name_item(QMIWMS_GET_MESSAGE_PROTOCOL_RESP), // 0x0030 + qmi_name_item(QMIWMS_LIST_MESSAGES_REQ), // 0x0031 + qmi_name_item(QMIWMS_LIST_MESSAGES_RESP), // 0x0031 + qmi_name_item(QMIWMS_GET_SMSC_ADDRESS_REQ), // 0x0034 + qmi_name_item(QMIWMS_GET_SMSC_ADDRESS_RESP), // 0x0034 + qmi_name_item(QMIWMS_SET_SMSC_ADDRESS_REQ), // 0x0035 + qmi_name_item(QMIWMS_SET_SMSC_ADDRESS_RESP), // 0x0035 + qmi_name_item(QMIWMS_GET_STORE_MAX_SIZE_REQ), // 0x0036 + qmi_name_item(QMIWMS_GET_STORE_MAX_SIZE_RESP), // 0x0036 +}; + +static const QMI_NAME_T qmux_wds_admin_Type[] = { + qmi_name_item(QMIWDS_ADMIN_SET_DATA_FORMAT_REQ), // 0x0020 + qmi_name_item(QMIWDS_ADMIN_SET_DATA_FORMAT_RESP), // 0x0020 + qmi_name_item(QMIWDS_ADMIN_GET_DATA_FORMAT_REQ), // 0x0021 + qmi_name_item(QMIWDS_ADMIN_GET_DATA_FORMAT_RESP), // 0x0021 + qmi_name_item(QMIWDS_ADMIN_SET_QMAP_SETTINGS_REQ), // 0x002B + qmi_name_item(QMIWDS_ADMIN_SET_QMAP_SETTINGS_RESP), // 0x002B + qmi_name_item(QMIWDS_ADMIN_GET_QMAP_SETTINGS_REQ), // 0x002C + qmi_name_item(QMIWDS_ADMIN_GET_QMAP_SETTINGS_RESP), // 0x002C +}; + +static const QMI_NAME_T qmux_uim_Type[] = { + qmi_name_item(QMIUIM_READ_TRANSPARENT_REQ), // 0x0020 + qmi_name_item(QMIUIM_READ_TRANSPARENT_RESP), // 0x0020 + qmi_name_item(QMIUIM_READ_TRANSPARENT_IND), // 0x0020 + qmi_name_item(QMIUIM_READ_RECORD_REQ), // 0x0021 + qmi_name_item(QMIUIM_READ_RECORD_RESP), // 0x0021 + qmi_name_item(QMIUIM_READ_RECORD_IND), // 0x0021 + qmi_name_item(QMIUIM_WRITE_TRANSPARENT_REQ), // 0x0022 + qmi_name_item(QMIUIM_WRITE_TRANSPARENT_RESP), // 0x0022 + qmi_name_item(QMIUIM_WRITE_TRANSPARENT_IND), // 0x0022 + qmi_name_item(QMIUIM_WRITE_RECORD_REQ), // 0x0023 + qmi_name_item(QMIUIM_WRITE_RECORD_RESP), // 0x0023 + qmi_name_item(QMIUIM_WRITE_RECORD_IND), // 0x0023 + qmi_name_item(QMIUIM_SET_PIN_PROTECTION_REQ), // 0x0025 + qmi_name_item(QMIUIM_SET_PIN_PROTECTION_RESP), // 0x0025 + qmi_name_item(QMIUIM_SET_PIN_PROTECTION_IND), // 0x0025 + qmi_name_item(QMIUIM_VERIFY_PIN_REQ), // 0x0026 + qmi_name_item(QMIUIM_VERIFY_PIN_RESP), // 0x0026 + qmi_name_item(QMIUIM_VERIFY_PIN_IND), // 0x0026 + qmi_name_item(QMIUIM_UNBLOCK_PIN_REQ), // 0x0027 + qmi_name_item(QMIUIM_UNBLOCK_PIN_RESP), // 0x0027 + qmi_name_item(QMIUIM_UNBLOCK_PIN_IND), // 0x0027 + qmi_name_item(QMIUIM_CHANGE_PIN_REQ), // 0x0028 + qmi_name_item(QMIUIM_CHANGE_PIN_RESP), // 0x0028 + qmi_name_item(QMIUIM_CHANGE_PIN_IND), // 0x0028 + qmi_name_item(QMIUIM_DEPERSONALIZATION_REQ), // 0x0029 + qmi_name_item(QMIUIM_DEPERSONALIZATION_RESP), // 0x0029 + qmi_name_item(QMIUIM_EVENT_REG_REQ), // 0x002E + qmi_name_item(QMIUIM_EVENT_REG_RESP), // 0x002E + qmi_name_item(QMIUIM_GET_CARD_STATUS_REQ), // 0x002F + qmi_name_item(QMIUIM_GET_CARD_STATUS_RESP), // 0x002F + qmi_name_item(QMIUIM_STATUS_CHANGE_IND), // 0x0032 +}; + +static const char *qmi_name_get(const QMI_NAME_T *table, size_t size, int type, + const char *tag) +{ + static char unknow[40]; + size_t i; + + if (qmux_CtlFlags == table) { + if (!strcmp(tag, "_REQ")) + tag = "_CMD"; + else if (!strcmp(tag, "_RESP")) + tag = "_RSP"; + } + + for (i = 0; i < size; i++) { + if (table[i].type == (UINT)type) { + if (!tag || (strstr(table[i].name, tag))) + return table[i].name; + } + } + sprintf(unknow, "unknow_%x", type); + return unknow; +} + +#define QMI_NAME(table, type) \ + qmi_name_get(table, sizeof(table) / sizeof(table[0]), type, 0) +#define QMUX_NAME(table, type, tag) \ + qmi_name_get(table, sizeof(table) / sizeof(table[0]), type, tag) + +void dump_tlv(PQCQMUX_MSG_HDR pQMUXMsgHdr) +{ + int TLVFind = 0; + int i; + // dbg("QCQMUX_TLV-----------------------------------\n"); + // dbg("{Type,\tLength,\tValue}\n"); + + while (1) { + PQMI_TLV_HDR TLVHdr = GetTLV(pQMUXMsgHdr, 0x1000 + (++TLVFind)); + if (TLVHdr == NULL) + break; + + // if ((TLVHdr->TLVType == 0x02) && ((USHORT *)(TLVHdr+1))[0]) + { + dbg("{%02x,\t%04x,\t", TLVHdr->TLVType, + le16_to_cpu(TLVHdr->TLVLength)); + for (i = 0; i < le16_to_cpu(TLVHdr->TLVLength); i++) { + dbg("%02x ", ((UCHAR *)(TLVHdr + 1))[i]); + } + dbg("}\n"); + } + } // while +} + +void dump_ctl(PQCQMICTL_MSG_HDR CTLHdr) +{ + const char *tag; + + // dbg("QCQMICTL_MSG--------------------------------------------\n"); + // dbg("CtlFlags: %02x\t\t%s\n", CTLHdr->CtlFlags, + // QMI_NAME(qmi_ctl_CtlFlags, CTLHdr->CtlFlags)); + dbg("TransactionId: %02x\n", CTLHdr->TransactionId); + switch (CTLHdr->CtlFlags) { + case QMICTL_FLAG_REQUEST: + tag = "_REQ"; + break; + case QMICTL_FLAG_RESPONSE: + tag = "_RESP"; + break; + case QMICTL_FLAG_INDICATION: + tag = "_IND"; + break; + default: + tag = 0; + break; + } + dbg("QMICTLType: %04x\t%s\n", le16_to_cpu(CTLHdr->QMICTLType), + QMUX_NAME(qmux_ctl_QMICTLType, le16_to_cpu(CTLHdr->QMICTLType), tag)); + dbg("Length: %04x\n", le16_to_cpu(CTLHdr->Length)); + + dump_tlv((PQCQMUX_MSG_HDR)(&CTLHdr->QMICTLType)); +} + +int dump_qmux(QMI_SERVICE_TYPE serviceType, PQCQMUX_HDR QMUXHdr) +{ + PQCQMUX_MSG_HDR QMUXMsgHdr = (PQCQMUX_MSG_HDR)(QMUXHdr + 1); + CHAR *tag; + + // dbg("QCQMUX--------------------------------------------\n"); + switch (QMUXHdr->CtlFlags & QMUX_CTL_FLAG_MASK_TYPE) { + case QMUX_CTL_FLAG_TYPE_CMD: + tag = "_REQ"; + break; + case QMUX_CTL_FLAG_TYPE_RSP: + tag = "_RESP"; + break; + case QMUX_CTL_FLAG_TYPE_IND: + tag = "_IND"; + break; + default: + tag = 0; + break; + } + // dbg("CtlFlags: %02x\t\t%s\n", QMUXHdr->CtlFlags, + // QMUX_NAME(qmux_CtlFlags, QMUXHdr->CtlFlags, tag)); + dbg("TransactionId: %04x\n", le16_to_cpu(QMUXHdr->TransactionId)); + + // dbg("QCQMUX_MSG_HDR-----------------------------------\n"); + switch (serviceType) { + case QMUX_TYPE_DMS: + dbg("Type: %04x\t%s\n", le16_to_cpu(QMUXMsgHdr->Type), + QMUX_NAME(qmux_dms_Type, le16_to_cpu(QMUXMsgHdr->Type), tag)); + break; + case QMUX_TYPE_NAS: + dbg("Type: %04x\t%s\n", le16_to_cpu(QMUXMsgHdr->Type), + QMUX_NAME(qmux_nas_Type, le16_to_cpu(QMUXMsgHdr->Type), tag)); + break; + case QMUX_TYPE_WDS: + dbg("Type: %04x\t%s\n", le16_to_cpu(QMUXMsgHdr->Type), + QMUX_NAME(qmux_wds_Type, le16_to_cpu(QMUXMsgHdr->Type), tag)); + break; + case QMUX_TYPE_WMS: + dbg("Type: %04x\t%s\n", le16_to_cpu(QMUXMsgHdr->Type), + QMUX_NAME(qmux_wms_Type, le16_to_cpu(QMUXMsgHdr->Type), tag)); + break; + case QMUX_TYPE_WDS_ADMIN: + dbg("Type: %04x\t%s\n", le16_to_cpu(QMUXMsgHdr->Type), + QMUX_NAME(qmux_wds_admin_Type, le16_to_cpu(QMUXMsgHdr->Type), tag)); + break; + case QMUX_TYPE_UIM: + dbg("Type: %04x\t%s\n", le16_to_cpu(QMUXMsgHdr->Type), + QMUX_NAME(qmux_uim_Type, le16_to_cpu(QMUXMsgHdr->Type), tag)); + break; + case QMUX_TYPE_PDS: + case QMUX_TYPE_QOS: + case QMUX_TYPE_CTL: + default: + dbg("Type: %04x\t%s\n", le16_to_cpu(QMUXMsgHdr->Type), + "PDS/QOS/CTL/unknown!"); + break; + } + dbg("Length: %04x\n", le16_to_cpu(QMUXMsgHdr->Length)); + + dump_tlv(QMUXMsgHdr); + + return 0; +} + +void dump_qmi(void *dataBuffer, int dataLen) +{ + PQCQMI_HDR QMIHdr = (PQCQMI_HDR)dataBuffer; + PQCQMUX_HDR QMUXHdr = (PQCQMUX_HDR)(QMIHdr + 1); + PQCQMICTL_MSG_HDR CTLHdr = (PQCQMICTL_MSG_HDR)(QMIHdr + 1); + + int i; + + if (!debug_qmi) + return; + + pthread_mutex_lock(&dumpQMIMutex); + line[0] = 0; + for (i = 0; i < dataLen; i++) { + dbg("%02x ", ((unsigned char *)dataBuffer)[i]); + } + dbg_time("%s", line); + line[0] = 0; + + // dbg("QCQMI_HDR-----------------------------------------"); + // dbg("IFType: %02x\t\t%s", QMIHdr->IFType, + // QMI_NAME(qmi_IFType, QMIHdr->IFType)); dbg("Length: %04x", + // le16_to_cpu(QMIHdr->Length)); dbg("CtlFlags: %02x\t\t%s", + // QMIHdr->CtlFlags, QMI_NAME(qmi_CtlFlags, QMIHdr->CtlFlags)); + // dbg("QMIType: %02x\t\t%s", QMIHdr->QMIType, QMI_NAME(qmi_QMIType, + // QMIHdr->QMIType)); dbg("ClientId: %02x", QMIHdr->ClientId); + + if (QMIHdr->QMIType == QMUX_TYPE_CTL) { + dump_ctl(CTLHdr); + } else { + dump_qmux(QMIHdr->QMIType, QMUXHdr); + } + dbg_time("%s", line); + pthread_mutex_unlock(&dumpQMIMutex); +} diff --git a/package/wwan/app/fibocom-dial/src/MPQMUX.h b/package/wwan/app/fibocom-dial/src/MPQMUX.h new file mode 100755 index 000000000..72dd00b49 --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/MPQMUX.h @@ -0,0 +1,3671 @@ +/*=========================================================================== + + M P Q M U X. H +DESCRIPTION: + + This file provides support for QMUX. + +INITIALIZATION AND SEQUENCING REQUIREMENTS: + +Copyright (C) 2011 by Qualcomm Technologies, Incorporated. All Rights Reserved. +===========================================================================*/ + +#ifndef MPQMUX_H +#define MPQMUX_H + +#include "MPQMI.h" + +#pragma pack(push, 1) + +#define QMIWDS_SET_EVENT_REPORT_REQ 0x0001 +#define QMIWDS_SET_EVENT_REPORT_RESP 0x0001 +#define QMIWDS_EVENT_REPORT_IND 0x0001 +#define QMIWDS_START_NETWORK_INTERFACE_REQ 0x0020 +#define QMIWDS_START_NETWORK_INTERFACE_RESP 0x0020 +#define QMIWDS_STOP_NETWORK_INTERFACE_REQ 0x0021 +#define QMIWDS_STOP_NETWORK_INTERFACE_RESP 0x0021 +#define QMIWDS_GET_PKT_SRVC_STATUS_REQ 0x0022 +#define QMIWDS_GET_PKT_SRVC_STATUS_RESP 0x0022 +#define QMIWDS_GET_PKT_SRVC_STATUS_IND 0x0022 +#define QMIWDS_GET_CURRENT_CHANNEL_RATE_REQ 0x0023 +#define QMIWDS_GET_CURRENT_CHANNEL_RATE_RESP 0x0023 +#define QMIWDS_GET_PKT_STATISTICS_REQ 0x0024 +#define QMIWDS_GET_PKT_STATISTICS_RESP 0x0024 +//begin modified by zhangkaibo add create profile qmi. mantis 0049137,0048741 20200610 +#define QMIWDS_CREATE_PROFILE_SETTINGS_REQ 0x0027 +#define QMIWDS_CREATE_PROFILE_SETTINGS_RESP 0x0027 +//end modified by zhangkaibo add create profile qmi. mantis 0049137,0048741 20200610 +#define QMIWDS_MODIFY_PROFILE_SETTINGS_REQ 0x0028 +#define QMIWDS_MODIFY_PROFILE_SETTINGS_RESP 0x0028 +#define QMIWDS_GET_PROFILE_SETTINGS_REQ 0x002B +#define QMIWDS_GET_PROFILE_SETTINGS_RESP 0x002B +#define QMIWDS_GET_DEFAULT_SETTINGS_REQ 0x002C +#define QMIWDS_GET_DEFAULT_SETTINGS_RESP 0x002C +#define QMIWDS_GET_RUNTIME_SETTINGS_REQ 0x002D +#define QMIWDS_GET_RUNTIME_SETTINGS_RESP 0x002D +#define QMIWDS_GET_MIP_MODE_REQ 0x002F +#define QMIWDS_GET_MIP_MODE_RESP 0x002F +#define QMIWDS_GET_DATA_BEARER_REQ 0x0037 +#define QMIWDS_GET_DATA_BEARER_RESP 0x0037 +#define QMIWDS_DUN_CALL_INFO_REQ 0x0038 +#define QMIWDS_DUN_CALL_INFO_RESP 0x0038 +#define QMIWDS_DUN_CALL_INFO_IND 0x0038 +#define QMIWDS_SET_CLIENT_IP_FAMILY_PREF_REQ 0x004D +#define QMIWDS_SET_CLIENT_IP_FAMILY_PREF_RESP 0x004D +#define QMIWDS_SET_AUTO_CONNECT_REQ 0x0051 +#define QMIWDS_SET_AUTO_CONNECT_RESP 0x0051 +#define QMIWDS_BIND_MUX_DATA_PORT_REQ 0x00A2 +#define QMIWDS_BIND_MUX_DATA_PORT_RESP 0x00A2 + +// Stats masks +#define QWDS_STAT_MASK_TX_PKT_OK 0x00000001 +#define QWDS_STAT_MASK_RX_PKT_OK 0x00000002 +#define QWDS_STAT_MASK_TX_PKT_ER 0x00000004 +#define QWDS_STAT_MASK_RX_PKT_ER 0x00000008 +#define QWDS_STAT_MASK_TX_PKT_OF 0x00000010 +#define QWDS_STAT_MASK_RX_PKT_OF 0x00000020 + +// TLV Types for xfer statistics +#define TLV_WDS_TX_GOOD_PKTS 0x10 +#define TLV_WDS_RX_GOOD_PKTS 0x11 +#define TLV_WDS_TX_ERROR 0x12 +#define TLV_WDS_RX_ERROR 0x13 +#define TLV_WDS_TX_OVERFLOW 0x14 +#define TLV_WDS_RX_OVERFLOW 0x15 +#define TLV_WDS_CHANNEL_RATE 0x16 +#define TLV_WDS_DATA_BEARER 0x17 +#define TLV_WDS_DORMANCY_STATUS 0x18 + +#define QWDS_PKT_DATA_DISCONNECTED 0x01 +#define QWDS_PKT_DATA_CONNECTED 0x02 +#define QWDS_PKT_DATA_SUSPENDED 0x03 +#define QWDS_PKT_DATA_AUTHENTICATING 0x04 + +#define QMIWDS_ADMIN_SET_DATA_FORMAT_REQ 0x0020 +#define QMIWDS_ADMIN_SET_DATA_FORMAT_RESP 0x0020 +#define QMIWDS_ADMIN_GET_DATA_FORMAT_REQ 0x0021 +#define QMIWDS_ADMIN_GET_DATA_FORMAT_RESP 0x0021 +#define QMIWDS_ADMIN_SET_QMAP_SETTINGS_REQ 0x002B +#define QMIWDS_ADMIN_SET_QMAP_SETTINGS_RESP 0x002B +#define QMIWDS_ADMIN_GET_QMAP_SETTINGS_REQ 0x002C +#define QMIWDS_ADMIN_GET_QMAP_SETTINGS_RESP 0x002C + +#define NETWORK_DESC_ENCODING_OCTET 0x00 +#define NETWORK_DESC_ENCODING_EXTPROTOCOL 0x01 +#define NETWORK_DESC_ENCODING_7BITASCII 0x02 +#define NETWORK_DESC_ENCODING_IA5 0x03 +#define NETWORK_DESC_ENCODING_UNICODE 0x04 +#define NETWORK_DESC_ENCODING_SHIFTJIS 0x05 +#define NETWORK_DESC_ENCODING_KOREAN 0x06 +#define NETWORK_DESC_ENCODING_LATINH 0x07 +#define NETWORK_DESC_ENCODING_LATIN 0x08 +#define NETWORK_DESC_ENCODING_GSM7BIT 0x09 +#define NETWORK_DESC_ENCODING_GSMDATA 0x0A +#define NETWORK_DESC_ENCODING_UNKNOWN 0xFF + +typedef struct _QMIWDS_ADMIN_SET_DATA_FORMAT { + USHORT Type; // QMUX type 0x0000 + USHORT Length; +} __attribute__((packed)) QMIWDS_ADMIN_SET_DATA_FORMAT, + *PQMIWDS_ADMIN_SET_DATA_FORMAT; + +typedef struct _QMIWDS_ADMIN_SET_DATA_FORMAT_TLV_QOS { + UCHAR TLVType; + USHORT TLVLength; + UCHAR QOSSetting; +} __attribute__((packed)) QMIWDS_ADMIN_SET_DATA_FORMAT_TLV_QOS, + *PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV_QOS; + +typedef struct _QMIWDS_ADMIN_SET_DATA_FORMAT_TLV { + UCHAR TLVType; + USHORT TLVLength; + ULONG Value; +} __attribute__((packed)) QMIWDS_ADMIN_SET_DATA_FORMAT_TLV, + *PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV; + +typedef struct _QMIWDS_ENDPOINT_TLV { + UCHAR TLVType; + USHORT TLVLength; + ULONG ep_type; + ULONG iface_id; +} __attribute__((packed)) QMIWDS_ENDPOINT_TLV, *PQMIWDS_ENDPOINT_TLV; + +typedef struct _QMIWDS_ADMIN_SET_DATA_FORMAT_REQ_MSG { + USHORT Type; + USHORT Length; + QMIWDS_ADMIN_SET_DATA_FORMAT_TLV_QOS QosDataFormatTlv; + QMIWDS_ADMIN_SET_DATA_FORMAT_TLV UnderlyingLinkLayerProtocolTlv; + QMIWDS_ADMIN_SET_DATA_FORMAT_TLV UplinkDataAggregationProtocolTlv; + QMIWDS_ADMIN_SET_DATA_FORMAT_TLV DownlinkDataAggregationProtocolTlv; + QMIWDS_ADMIN_SET_DATA_FORMAT_TLV DownlinkDataAggregationMaxDatagramsTlv; + QMIWDS_ADMIN_SET_DATA_FORMAT_TLV DownlinkDataAggregationMaxSizeTlv; +#if 0 + QMIWDS_ADMIN_SET_DATA_FORMAT_TLV UplinkDataAggregationMaxDatagramsTlv; + QMIWDS_ADMIN_SET_DATA_FORMAT_TLV UplinkDataAggregationMaxSizeTlv; +#else + QMIWDS_ENDPOINT_TLV epTlv; +#endif +} __attribute__((packed)) QMIWDS_ADMIN_SET_DATA_FORMAT_REQ_MSG, + *PQMIWDS_ADMIN_SET_DATA_FORMAT_REQ_MSG; + +#if 0 +typedef enum _QMI_RETURN_CODES { + QMI_SUCCESS = 0, + QMI_SUCCESS_NOT_COMPLETE, + QMI_FAILURE +}QMI_RETURN_CODES; + +typedef struct _QMIWDS_GET_PKT_SRVC_STATUS_REQ_MSG +{ + USHORT Type; // 0x0022 + USHORT Length; // 0x0000 +} QMIWDS_GET_PKT_SRVC_STATUS_REQ_MSG, *PQMIWDS_GET_PKT_SRVC_STATUS_REQ_MSG; + +typedef struct _QMIWDS_GET_PKT_SRVC_STATUS_RESP_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; + UCHAR TLVType2; + USHORT TLVLength2; + UCHAR ConnectionStatus; // 0x01: QWDS_PKT_DATAC_DISCONNECTED + // 0x02: QWDS_PKT_DATA_CONNECTED + // 0x03: QWDS_PKT_DATA_SUSPENDED + // 0x04: QWDS_PKT_DATA_AUTHENTICATING +} QMIWDS_GET_PKT_SRVC_STATUS_RESP_MSG, *PQMIWDS_GET_PKT_SRVC_STATUS_RESP_MSG; + +typedef struct _QMIWDS_GET_PKT_SRVC_STATUS_IND_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + UCHAR ConnectionStatus; // 0x01: QWDS_PKT_DATAC_DISCONNECTED + // 0x02: QWDS_PKT_DATA_CONNECTED + // 0x03: QWDS_PKT_DATA_SUSPENDED + UCHAR ReconfigRequired; // 0x00: No need to reconfigure + // 0x01: Reconfiguration required +} QMIWDS_GET_PKT_SRVC_STATUS_IND_MSG, *PQMIWDS_GET_PKT_SRVC_STATUS_IND_MSG; + +typedef struct _WDS_PKT_SRVC_IP_FAMILY_TLV +{ + UCHAR TLVType; // 0x12 + USHORT TLVLength; // 1 + UCHAR IpFamily; // IPV4-0x04, IPV6-0x06 +} WDS_PKT_SRVC_IP_FAMILY_TLV, *PWDS_PKT_SRVC_IP_FAMILY_TLV; + +typedef struct _QMIWDS_DUN_CALL_INFO_REQ_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + ULONG Mask; + UCHAR TLV2Type; + USHORT TLV2Length; + UCHAR ReportConnectionStatus; +} QMIWDS_DUN_CALL_INFO_REQ_MSG, *PQMIWDS_DUN_CALL_INFO_REQ_MSG; + +typedef struct _QMIWDS_DUN_CALL_INFO_RESP_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; +} QMIWDS_DUN_CALL_INFO_RESP_MSG, *PQMIWDS_DUN_CALL_INFO_RESP_MSG; + +typedef struct _QMIWDS_DUN_CALL_INFO_IND_MSG +{ + UCHAR TLVType; + USHORT TLVLength; + UCHAR ConnectionStatus; +} QMIWDS_DUN_CALL_INFO_IND_MSG, *PQMIWDS_DUN_CALL_INFO_IND_MSG; + +typedef struct _QMIWDS_GET_CURRENT_CHANNEL_RATE_REQ_MSG +{ + USHORT Type; // QMUX type 0x0040 + USHORT Length; +} QMIWDS_GET_CURRENT_CHANNEL_RATE_REQ_MSG, *PQMIWDS_GET_CURRENT_CHANNEL_RATE_REQ_MSG; + +typedef struct _QMIWDS_GET_CURRENT_CHANNEL_RATE_RESP_MSG +{ + USHORT Type; // QMUX type 0x0040 + USHORT Length; + UCHAR TLVType; // 0x02 + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT + + UCHAR TLV2Type; // 0x01 + USHORT TLV2Length; // 16 + //ULONG CallHandle; // Context corresponding to reported channel + ULONG CurrentTxRate; // bps + ULONG CurrentRxRate; // bps + ULONG ServingSystemTxRate; // bps + ULONG ServingSystemRxRate; // bps + +} QMIWDS_GET_CURRENT_CHANNEL_RATE_RESP_MSG, *PQMIWDS_GET_CURRENT_CHANNEL_RATE_RESP; + +#define QWDS_EVENT_REPORT_MASK_RATES 0x01 +#define QWDS_EVENT_REPORT_MASK_STATS 0x02 + +#ifdef QCUSB_MUX_PROTOCOL +#error code not present +#endif // QCUSB_MUX_PROTOCOL + +typedef struct _QMIWDS_SET_EVENT_REPORT_REQ_MSG +{ + USHORT Type; // QMUX type 0x0042 + USHORT Length; + + UCHAR TLVType; // 0x10 -- current channel rate indicator + USHORT TLVLength; // 1 + UCHAR Mode; // 0-do not report; 1-report when rate changes + + UCHAR TLV2Type; // 0x11 + USHORT TLV2Length; // 5 + UCHAR StatsPeriod; // seconds between reports; 0-do not report + ULONG StatsMask; // + + UCHAR TLV3Type; // 0x12 -- current data bearer indicator + USHORT TLV3Length; // 1 + UCHAR Mode3; // 0-do not report; 1-report when changes + + UCHAR TLV4Type; // 0x13 -- dormancy status indicator + USHORT TLV4Length; // 1 + UCHAR DormancyStatus; // 0-do not report; 1-report when changes +} QMIWDS_SET_EVENT_REPORT_REQ_MSG, *PQMIWDS_SET_EVENT_REPORT_REQ_MSG; + +typedef struct _QMIWDS_SET_EVENT_REPORT_RESP_MSG +{ + USHORT Type; // QMUX type 0x0042 + USHORT Length; + + UCHAR TLVType; // 0x02 result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_NO_BATTERY + // QMI_ERR_FAULT +} QMIWDS_SET_EVENT_REPORT_RESP_MSG, *PQMIWDS_SET_EVENT_REPORT_RESP_MSG; + +typedef struct _QMIWDS_EVENT_REPORT_IND_MSG +{ + USHORT Type; // QMUX type 0x0001 + USHORT Length; +} QMIWDS_EVENT_REPORT_IND_MSG, *PQMIWDS_EVENT_REPORT_IND_MSG; + +// PQCTLV_PKT_STATISTICS + +typedef struct _QMIWDS_EVENT_REPORT_IND_CHAN_RATE_TLV +{ + UCHAR Type; + USHORT Length; // 8 + ULONG TxRate; + ULONG RxRate; +} QMIWDS_EVENT_REPORT_IND_CHAN_RATE_TLV, *PQMIWDS_EVENT_REPORT_IND_CHAN_RATE_TLV; + +#ifdef QCUSB_MUX_PROTOCOL +#error code not present +#endif // QCUSB_MUX_PROTOCOL + +typedef struct _QMIWDS_GET_PKT_STATISTICS_REQ_MSG +{ + USHORT Type; // QMUX type 0x0041 + USHORT Length; + UCHAR TLVType; // 0x01 + USHORT TLVLength; // 4 + ULONG StateMask; // 0x00000001 tx success packets + // 0x00000002 rx success packets + // 0x00000004 rx packet errors (checksum) + // 0x00000008 rx packets dropped (memory) + +} QMIWDS_GET_PKT_STATISTICS_REQ_MSG, *PQMIWDS_GET_PKT_STATISTICS_REQ_MSG; + +typedef struct _QMIWDS_GET_PKT_STATISTICS_RESP_MSG +{ + USHORT Type; // QMUX type 0x0041 + USHORT Length; + UCHAR TLVType; // 0x02 + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT +} QMIWDS_GET_PKT_STATISTICS_RESP_MSG, *PQMIWDS_GET_PKT_STATISTICS_RESP_MSG; + +// optional TLV for stats +typedef struct _QCTLV_PKT_STATISTICS +{ + UCHAR TLVType; // see above definitions for TLV types + USHORT TLVLength; // 4 + ULONG Count; +} QCTLV_PKT_STATISTICS, *PQCTLV_PKT_STATISTICS; +#endif + +//#ifdef QC_IP_MODE + +#define QMIWDS_GET_RUNTIME_SETTINGS_MASK_IPV4DNS_ADDR 0x0010 +#define QMIWDS_GET_RUNTIME_SETTINGS_MASK_IPV4_ADDR 0x0100 +#define QMIWDS_GET_RUNTIME_SETTINGS_MASK_IPV4GATEWAY_ADDR 0x0200 +#define QMIWDS_GET_RUNTIME_SETTINGS_MASK_MTU 0x2000 + +typedef struct _QMIWDS_GET_RUNTIME_SETTINGS_REQ_MSG { + USHORT Type; // QMIWDS_GET_RUNTIME_SETTINGS_REQ + USHORT Length; + UCHAR TLVType; // 0x10 + USHORT TLVLength; // 0x0004 + ULONG Mask; // mask, bit 8: IP addr -- 0x0100 +} __attribute__((packed)) QMIWDS_GET_RUNTIME_SETTINGS_REQ_MSG, + *PQMIWDS_GET_RUNTIME_SETTINGS_REQ_MSG; + +typedef struct _QMIWDS_BIND_MUX_DATA_PORT_REQ_MSG { + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + ULONG ep_type; + ULONG iface_id; + UCHAR TLV2Type; + USHORT TLV2Length; + UCHAR MuxId; + UCHAR TLV3Type; + USHORT TLV3Length; + ULONG client_type; +} __attribute__((packed)) QMIWDS_BIND_MUX_DATA_PORT_REQ_MSG, + *PQMIWDS_BIND_MUX_DATA_PORT_REQ_MSG; + +#define QMIWDS_GET_RUNTIME_SETTINGS_TLV_TYPE_IPV4PRIMARYDNS 0x15 +#define QMIWDS_GET_RUNTIME_SETTINGS_TLV_TYPE_IPV4SECONDARYDNS 0x16 +#define QMIWDS_GET_RUNTIME_SETTINGS_TLV_TYPE_IPV4 0x1E +#define QMIWDS_GET_RUNTIME_SETTINGS_TLV_TYPE_IPV4GATEWAY 0x20 +#define QMIWDS_GET_RUNTIME_SETTINGS_TLV_TYPE_IPV4SUBNET 0x21 + +#define QMIWDS_GET_RUNTIME_SETTINGS_TLV_TYPE_IPV6 0x25 +#define QMIWDS_GET_RUNTIME_SETTINGS_TLV_TYPE_IPV6GATEWAY 0x26 +#define QMIWDS_GET_RUNTIME_SETTINGS_TLV_TYPE_IPV6PRIMARYDNS 0x27 +#define QMIWDS_GET_RUNTIME_SETTINGS_TLV_TYPE_IPV6SECONDARYDNS 0x28 +#define QMIWDS_GET_RUNTIME_SETTINGS_TLV_TYPE_MTU 0x29 + +typedef struct _QMIWDS_GET_RUNTIME_SETTINGS_TLV_MTU { + UCHAR TLVType; // QMIWDS_GET_RUNTIME_SETTINGS_TLV_TYPE_MTU + USHORT TLVLength; // 4 + ULONG Mtu; // MTU +} __attribute__((packed)) QMIWDS_GET_RUNTIME_SETTINGS_TLV_MTU, + *PQMIWDS_GET_RUNTIME_SETTINGS_TLV_MTU; + +typedef struct _QMIWDS_GET_RUNTIME_SETTINGS_TLV_IPV4_ADDR { + UCHAR TLVType; // QMIWDS_GET_RUNTIME_SETTINGS_TLV_TYPE_IPV4 + USHORT TLVLength; // 4 + ULONG IPV4Address; // address +} __attribute__((packed)) QMIWDS_GET_RUNTIME_SETTINGS_TLV_IPV4_ADDR, + *PQMIWDS_GET_RUNTIME_SETTINGS_TLV_IPV4_ADDR; + +typedef struct _QMIWDS_GET_RUNTIME_SETTINGS_TLV_IPV6_ADDR { + UCHAR TLVType; // QMIWDS_GET_RUNTIME_SETTINGS_TLV_TYPE_IPV6 + USHORT TLVLength; // 16 + UCHAR IPV6Address[16]; // address + UCHAR PrefixLength; // prefix length +} __attribute__((packed)) QMIWDS_GET_RUNTIME_SETTINGS_TLV_IPV6_ADDR, + *PQMIWDS_GET_RUNTIME_SETTINGS_TLV_IPV6_ADDR; + + typedef struct _QMIWDS_GET_RUNTIME_SETTINGS_TLV_IPV6_DNS_ADDR { + UCHAR TLVType; // QMIWDS_GET_RUNTIME_SETTINGS_TLV_TYPE_IPV6 + USHORT TLVLength; // 16 + UCHAR IPV6Address[16]; // address + } __attribute__((packed)) QMIWDS_GET_RUNTIME_SETTINGS_TLV_IPV6_DNS_ADDR, + *PQMIWDS_GET_RUNTIME_SETTINGS_TLV_IPV6_DNS_ADDR; + +typedef struct _QMIWDS_GET_RUNTIME_SETTINGS_RESP_MSG { + USHORT Type; // QMIWDS_GET_RUNTIME_SETTINGS_RESP + USHORT Length; + UCHAR TLVType; // QCTLV_TYPE_RESULT_CODE + USHORT TLVLength; // 0x0004 + USHORT QMUXResult; // result code + USHORT QMUXError; // error code +} __attribute__((packed)) QMIWDS_GET_RUNTIME_SETTINGS_RESP_MSG, + *PQMIWDS_GET_RUNTIME_SETTINGS_RESP_MSG; + +//#endif // QC_IP_MODE + +typedef struct _QMIWDS_IP_FAMILY_TLV { + UCHAR TLVType; // 0x12 + USHORT TLVLength; // 1 + UCHAR IpFamily; // IPV4-0x04, IPV6-0x06 +} __attribute__((packed)) QMIWDS_IP_FAMILY_TLV, *PQMIWDS_IP_FAMILY_TLV; + +typedef struct _QMIWDS_PKT_SRVC_TLV { + UCHAR TLVType; + USHORT TLVLength; + UCHAR ConnectionStatus; + UCHAR ReconfigReqd; +} __attribute__((packed)) QMIWDS_PKT_SRVC_TLV, *PQMIWDS_PKT_SRVC_TLV; + +typedef struct _QMIWDS_CALL_END_REASON_TLV { + UCHAR TLVType; + USHORT TLVLength; + USHORT CallEndReason; +} __attribute__((packed)) QMIWDS_CALL_END_REASON_TLV, + *PQMIWDS_CALL_END_REASON_TLV; + +typedef struct _QMIWDS_CALL_END_REASON_V_TLV { + UCHAR TLVType; + USHORT TLVLength; + USHORT CallEndReasonType; + USHORT CallEndReason; +} __attribute__((packed)) QMIWDS_CALL_END_REASON_V_TLV, + *PQMIWDS_CALL_END_REASON_V_TLV; + +typedef struct _QMIWDS_SET_CLIENT_IP_FAMILY_PREF_REQ_MSG { + USHORT Type; // QMUX type 0x004D + USHORT Length; + UCHAR TLVType; // 0x01 + USHORT TLVLength; // 1 + UCHAR IpPreference; // IPV4-0x04, IPV6-0x06 +} __attribute__((packed)) QMIWDS_SET_CLIENT_IP_FAMILY_PREF_REQ_MSG, + *PQMIWDS_SET_CLIENT_IP_FAMILY_PREF_REQ_MSG; + +typedef struct _QMIWDS_SET_CLIENT_IP_FAMILY_PREF_RESP_MSG { + USHORT Type; // QMUX type 0x0037 + USHORT Length; + UCHAR TLVType; // 0x02 + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS, QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INTERNAL, QMI_ERR_MALFORMED_MSG, + // QMI_ERR_INVALID_ARG +} __attribute__((packed)) QMIWDS_SET_CLIENT_IP_FAMILY_PREF_RESP_MSG, + *PQMIWDS_SET_CLIENT_IP_FAMILY_PREF_RESP_MSG; + +typedef struct _QMIWDS_SET_AUTO_CONNECT_REQ_MSG { + USHORT Type; // QMUX type 0x0051 + USHORT Length; + UCHAR TLVType; // 0x01 + USHORT TLVLength; // 1 + UCHAR autoconnect_setting; // 0x00 ?C Disabled, 0x01 ?C Enabled, 0x02 ?C + // Paused (resume on power cycle) +} __attribute__((packed)) QMIWDS_SET_AUTO_CONNECT_REQ_MSG, + *PQMIWDS_SET_AUTO_CONNECT_REQ_MSG; + +#if 0 +typedef struct _QMIWDS_GET_MIP_MODE_REQ_MSG +{ + USHORT Type; // QMUX type 0x0040 + USHORT Length; +} QMIWDS_GET_MIP_MODE_REQ_MSG, *PQMIWDS_GET_MIP_MODE_REQ_MSG; + +typedef struct _QMIWDS_GET_MIP_MODE_RESP_MSG +{ + USHORT Type; // QMUX type 0x0040 + USHORT Length; + UCHAR TLVType; // 0x02 + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT + + UCHAR TLV2Type; // 0x01 + USHORT TLV2Length; // 20 + UCHAR MipMode; // +} QMIWDS_GET_MIP_MODE_RESP_MSG, *PQMIWDS_GET_MIP_MODE_RESP_MSG; +#endif + +typedef struct _QMIWDS_TECHNOLOGY_PREFERECE { + UCHAR TLVType; + USHORT TLVLength; + UCHAR TechPreference; +} __attribute__((packed)) QMIWDS_TECHNOLOGY_PREFERECE, + *PQMIWDS_TECHNOLOGY_PREFERECE; + +typedef struct _QMIWDS_PROFILE_IDENTIFIER { + UCHAR TLVType; + USHORT TLVLength; + UCHAR ProfileIndex; +} __attribute__((packed)) QMIWDS_PROFILE_IDENTIFIER, + *PQMIWDS_PROFILE_IDENTIFIER; + +#if 0 +typedef struct _QMIWDS_IPADDRESS +{ + UCHAR TLVType; + USHORT TLVLength; + ULONG IPv4Address; +}QMIWDS_IPADDRESS, *PQMIWDS_IPADDRESS; + +/* +typedef struct _QMIWDS_UMTS_QOS +{ + UCHAR TLVType; + USHORT TLVLength; + UCHAR TrafficClass; + ULONG MaxUplinkBitRate; + ULONG MaxDownlinkBitRate; + ULONG GuarUplinkBitRate; + ULONG GuarDownlinkBitRate; + UCHAR QOSDevOrder; + ULONG MAXSDUSize; + UCHAR SDUErrorRatio; + UCHAR ResidualBerRatio; + UCHAR DeliveryErrorSDUs; + ULONG TransferDelay; + ULONG TrafficHndPri; +}QMIWDS_UMTS_QOS, *PQMIWDS_UMTS_QOS; + +typedef struct _QMIWDS_GPRS_QOS +{ + UCHAR TLVType; + USHORT TLVLength; + ULONG PrecedenceClass; + ULONG DelayClass; + ULONG ReliabilityClass; + ULONG PeekThroClass; + ULONG MeanThroClass; +}QMIWDS_GPRS_QOS, *PQMIWDS_GPRS_QOS; +*/ +#endif + +typedef struct _QMIWDS_PROFILENAME { + UCHAR TLVType; + USHORT TLVLength; + UCHAR ProfileName; +} __attribute__((packed)) QMIWDS_PROFILENAME, *PQMIWDS_PROFILENAME; + +typedef struct _QMIWDS_PDPTYPE { + UCHAR TLVType; + USHORT TLVLength; + // 0 ?C PDP-IP (IPv4) + // 1 ?C PDP-PPP + // 2 ?C PDP-IPv6 + // 3 ?C PDP-IPv4v6 + UCHAR PdpType; +} __attribute__((packed)) QMIWDS_PDPTYPE, *PQMIWDS_PDPTYPE; + +typedef struct _QMIWDS_USERNAME { + UCHAR TLVType; + USHORT TLVLength; + UCHAR UserName; +} __attribute__((packed)) QMIWDS_USERNAME, *PQMIWDS_USERNAME; + +typedef struct _QMIWDS_PASSWD { + UCHAR TLVType; + USHORT TLVLength; + UCHAR Passwd; +} __attribute__((packed)) QMIWDS_PASSWD, *PQMIWDS_PASSWD; + +typedef struct _QMIWDS_AUTH_PREFERENCE { + UCHAR TLVType; + USHORT TLVLength; + UCHAR AuthPreference; +} __attribute__((packed)) QMIWDS_AUTH_PREFERENCE, *PQMIWDS_AUTH_PREFERENCE; + +typedef struct _QMIWDS_APNNAME { + UCHAR TLVType; + USHORT TLVLength; + UCHAR ApnName; +} __attribute__((packed)) QMIWDS_APNNAME, *PQMIWDS_APNNAME; + +typedef struct _QMIWDS_AUTOCONNECT { + UCHAR TLVType; + USHORT TLVLength; + UCHAR AutoConnect; +} __attribute__((packed)) QMIWDS_AUTOCONNECT, *PQMIWDS_AUTOCONNECT; + +typedef struct _QMIWDS_START_NETWORK_INTERFACE_REQ_MSG { + USHORT Type; + USHORT Length; +} __attribute__((packed)) QMIWDS_START_NETWORK_INTERFACE_REQ_MSG, + *PQMIWDS_START_NETWORK_INTERFACE_REQ_MSG; + +typedef struct _QMIWDS_CALLENDREASON { + UCHAR TLVType; + USHORT TLVLength; + USHORT Reason; +} __attribute__((packed)) QMIWDS_CALLENDREASON, *PQMIWDS_CALLENDREASON; + +typedef struct _QMIWDS_START_NETWORK_INTERFACE_RESP_MSG { + USHORT Type; // QMUX type 0x0040 + USHORT Length; + UCHAR TLVType; // 0x02 + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT + + UCHAR TLV2Type; // 0x01 + USHORT TLV2Length; // 20 + ULONG Handle; // +} __attribute__((packed)) QMIWDS_START_NETWORK_INTERFACE_RESP_MSG, + *PQMIWDS_START_NETWORK_INTERFACE_RESP_MSG; + +typedef struct _QMIWDS_STOP_NETWORK_INTERFACE_REQ_MSG { + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + ULONG Handle; +} __attribute__((packed)) QMIWDS_STOP_NETWORK_INTERFACE_REQ_MSG, + *PQMIWDS_STOP_NETWORK_INTERFACE_REQ_MSG; + +typedef struct _QMIWDS_STOP_NETWORK_INTERFACE_RESP_MSG { + USHORT Type; // QMUX type 0x0040 + USHORT Length; + UCHAR TLVType; // 0x02 + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT + +} __attribute__((packed)) QMIWDS_STOP_NETWORK_INTERFACE_RESP_MSG, + *PQMIWDS_STOP_NETWORK_INTERFACE_RESP_MSG; + +typedef struct _QMIWDS_GET_DEFAULT_SETTINGS_REQ_MSG { + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + UCHAR ProfileType; +} __attribute__((packed)) QMIWDS_GET_DEFAULT_SETTINGS_REQ_MSG, + *PQMIWDS_GET_DEFAULT_SETTINGS_REQ_MSG; + +typedef struct _QMIWDS_GET_DEFAULT_SETTINGS_RESP_MSG { + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; +} __attribute__((packed)) QMIWDS_GET_DEFAULT_SETTINGS_RESP_MSG, + *PQMIWDS_GET_DEFAULT_SETTINGS_RESP_MSG; +//begin modified by zhangkaibo add create profile qmi. mantis 0049137,0048741 20200610 +typedef struct _QMIWDS_CREATE_PROFILE_SETTINGS_REQ_MSG { + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + UCHAR ProfileType; +} __attribute__((packed)) QMIWDS_CREATE_PROFILE_SETTINGS_REQ_MSG, + *PQMIWDS_CREATE_PROFILE_SETTINGS_REQ_MSG; + + +typedef struct _QMIWDS_CREATE_PROFILE_SETTINGS_RESP_MSG { + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; +} __attribute__((packed)) QMIWDS_CREATE_PROFILE_SETTINGS_RESP_MSG, + *PQMIWDS_CREATE_PROFILE_SETTINGS_RESP_MSG; +//end modified by zhangkaibo add create profile qmi. mantis 0049137,0048741 20200610 +typedef struct _QMIWDS_MODIFY_PROFILE_SETTINGS_REQ_MSG { + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + UCHAR ProfileType; + UCHAR ProfileIndex; +} __attribute__((packed)) QMIWDS_MODIFY_PROFILE_SETTINGS_REQ_MSG, + *PQMIWDS_MODIFY_PROFILE_SETTINGS_REQ_MSG; + +typedef struct _QMIWDS_MODIFY_PROFILE_SETTINGS_RESP_MSG { + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; +} __attribute__((packed)) QMIWDS_MODIFY_PROFILE_SETTINGS_RESP_MSG, + *PQMIWDS_MODIFY_PROFILE_SETTINGS_RESP_MSG; + +typedef struct _QMIWDS_GET_PROFILE_SETTINGS_REQ_MSG { + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + UCHAR ProfileType; + UCHAR ProfileIndex; +} __attribute__((packed)) QMIWDS_GET_PROFILE_SETTINGS_REQ_MSG, + *PQMIWDS_GET_PROFILE_SETTINGS_REQ_MSG; + +#if 0 +typedef struct _QMIWDS_EVENT_REPORT_IND_DATA_BEARER_TLV +{ + UCHAR Type; + USHORT Length; + UCHAR DataBearer; +} QMIWDS_EVENT_REPORT_IND_DATA_BEARER_TLV, *PQMIWDS_EVENT_REPORT_IND_DATA_BEARER_TLV; + +typedef struct _QMIWDS_EVENT_REPORT_IND_DORMANCY_STATUS_TLV +{ + UCHAR Type; + USHORT Length; + UCHAR DormancyStatus; +} QMIWDS_EVENT_REPORT_IND_DORMANCY_STATUS_TLV, *PQMIWDS_EVENT_REPORT_IND_DORMANCY_STATUS_TLV; + + +typedef struct _QMIWDS_GET_DATA_BEARER_REQ_MSG +{ + USHORT Type; // QMUX type 0x0037 + USHORT Length; +} QMIWDS_GET_DATA_BEARER_REQ_MSG, *PQMIWDS_GET_DATA_BEARER_REQ_MSG; + +typedef struct _QMIWDS_GET_DATA_BEARER_RESP_MSG +{ + USHORT Type; // QMUX type 0x0037 + USHORT Length; + UCHAR TLVType; // 0x02 + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INTERNAL + // QMI_ERR_MALFORMED_MSG + // QMI_ERR_NO_MEMORY + // QMI_ERR_OUT_OF_CALL + // QMI_ERR_INFO_UNAVAILABLE + UCHAR TLV2Type; // 0x01 + USHORT TLV2Length; // + UCHAR Technology; // +} QMIWDS_GET_DATA_BEARER_RESP_MSG, *PQMIWDS_GET_DATA_BEARER_RESP_MSG; +#endif + +// ======================= DMS ============================== +#define QMIDMS_SET_EVENT_REPORT_REQ 0x0001 +#define QMIDMS_SET_EVENT_REPORT_RESP 0x0001 +#define QMIDMS_EVENT_REPORT_IND 0x0001 +#define QMIDMS_GET_DEVICE_CAP_REQ 0x0020 +#define QMIDMS_GET_DEVICE_CAP_RESP 0x0020 +#define QMIDMS_GET_DEVICE_MFR_REQ 0x0021 +#define QMIDMS_GET_DEVICE_MFR_RESP 0x0021 +#define QMIDMS_GET_DEVICE_MODEL_ID_REQ 0x0022 +#define QMIDMS_GET_DEVICE_MODEL_ID_RESP 0x0022 +#define QMIDMS_GET_DEVICE_REV_ID_REQ 0x0023 +#define QMIDMS_GET_DEVICE_REV_ID_RESP 0x0023 +#define QMIDMS_GET_MSISDN_REQ 0x0024 +#define QMIDMS_GET_MSISDN_RESP 0x0024 +#define QMIDMS_GET_DEVICE_SERIAL_NUMBERS_REQ 0x0025 +#define QMIDMS_GET_DEVICE_SERIAL_NUMBERS_RESP 0x0025 +#define QMIDMS_UIM_SET_PIN_PROTECTION_REQ 0x0027 +#define QMIDMS_UIM_SET_PIN_PROTECTION_RESP 0x0027 +#define QMIDMS_UIM_VERIFY_PIN_REQ 0x0028 +#define QMIDMS_UIM_VERIFY_PIN_RESP 0x0028 +#define QMIDMS_UIM_UNBLOCK_PIN_REQ 0x0029 +#define QMIDMS_UIM_UNBLOCK_PIN_RESP 0x0029 +#define QMIDMS_UIM_CHANGE_PIN_REQ 0x002A +#define QMIDMS_UIM_CHANGE_PIN_RESP 0x002A +#define QMIDMS_UIM_GET_PIN_STATUS_REQ 0x002B +#define QMIDMS_UIM_GET_PIN_STATUS_RESP 0x002B +#define QMIDMS_GET_DEVICE_HARDWARE_REV_REQ 0x002C +#define QMIDMS_GET_DEVICE_HARDWARE_REV_RESP 0x002C +#define QMIDMS_GET_OPERATING_MODE_REQ 0x002D +#define QMIDMS_GET_OPERATING_MODE_RESP 0x002D +#define QMIDMS_SET_OPERATING_MODE_REQ 0x002E +#define QMIDMS_SET_OPERATING_MODE_RESP 0x002E +#define QMIDMS_GET_ACTIVATED_STATUS_REQ 0x0031 +#define QMIDMS_GET_ACTIVATED_STATUS_RESP 0x0031 +#define QMIDMS_ACTIVATE_AUTOMATIC_REQ 0x0032 +#define QMIDMS_ACTIVATE_AUTOMATIC_RESP 0x0032 +#define QMIDMS_ACTIVATE_MANUAL_REQ 0x0033 +#define QMIDMS_ACTIVATE_MANUAL_RESP 0x0033 +#define QMIDMS_UIM_GET_ICCID_REQ 0x003C +#define QMIDMS_UIM_GET_ICCID_RESP 0x003C +#define QMIDMS_UIM_GET_CK_STATUS_REQ 0x0040 +#define QMIDMS_UIM_GET_CK_STATUS_RESP 0x0040 +#define QMIDMS_UIM_SET_CK_PROTECTION_REQ 0x0041 +#define QMIDMS_UIM_SET_CK_PROTECTION_RESP 0x0041 +#define QMIDMS_UIM_UNBLOCK_CK_REQ 0x0042 +#define QMIDMS_UIM_UNBLOCK_CK_RESP 0x0042 +#define QMIDMS_UIM_GET_IMSI_REQ 0x0043 +#define QMIDMS_UIM_GET_IMSI_RESP 0x0043 +#define QMIDMS_UIM_GET_STATE_REQ 0x0044 +#define QMIDMS_UIM_GET_STATE_RESP 0x0044 +#define QMIDMS_GET_BAND_CAP_REQ 0x0045 +#define QMIDMS_GET_BAND_CAP_RESP 0x0045 + +#if 0 +typedef struct _QMIDMS_GET_DEVICE_MFR_REQ_MSG +{ + USHORT Type; // QMUX type 0x0003 + USHORT Length; +} QMIDMS_GET_DEVICE_MFR_REQ_MSG, *PQMIDMS_GET_DEVICE_MFR_REQ_MSG; + +typedef struct _QMIDMS_GET_DEVICE_MFR_RESP_MSG +{ + USHORT Type; // QMUX type 0x0003 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT + UCHAR TLV2Type; // 0x01 - required parameter + USHORT TLV2Length; // length of the mfr string + UCHAR DeviceManufacturer; // first byte of string +} QMIDMS_GET_DEVICE_MFR_RESP_MSG, *PQMIDMS_GET_DEVICE_MFR_RESP_MSG; + +typedef struct _QMIDMS_GET_DEVICE_MODEL_ID_REQ_MSG +{ + USHORT Type; // QMUX type 0x0004 + USHORT Length; +} QMIDMS_GET_DEVICE_MODEL_ID_REQ_MSG, *PQMIDMS_GET_DEVICE_MODEL_ID_REQ_MSG; + +typedef struct _QMIDMS_GET_DEVICE_MODEL_ID_RESP_MSG +{ + USHORT Type; // QMUX type 0x0004 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT + UCHAR TLV2Type; // 0x01 - required parameter + USHORT TLV2Length; // length of the modem id string + UCHAR DeviceModelID; // device model id +} QMIDMS_GET_DEVICE_MODEL_ID_RESP_MSG, *PQMIDMS_GET_DEVICE_MODEL_ID_RESP_MSG; +#endif + +typedef struct _QMIDMS_GET_DEVICE_REV_ID_REQ_MSG { + USHORT Type; // QMUX type 0x0005 + USHORT Length; +} __attribute__((packed)) QMIDMS_GET_DEVICE_REV_ID_REQ_MSG, + *PQMIDMS_GET_DEVICE_REV_ID_REQ_MSG; + +typedef struct _DEVICE_REV_ID { + UCHAR TLVType; + USHORT TLVLength; + UCHAR RevisionID; +} __attribute__((packed)) DEVICE_REV_ID, *PDEVICE_REV_ID; + +#if 0 +typedef struct _QMIDMS_GET_DEVICE_REV_ID_RESP_MSG +{ + USHORT Type; // QMUX type 0x0023 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT +} QMIDMS_GET_DEVICE_REV_ID_RESP_MSG, *PQMIDMS_GET_DEVICE_REV_ID_RESP_MSG; + +typedef struct _QMIDMS_GET_MSISDN_REQ_MSG +{ + USHORT Type; // QMUX type 0x0024 + USHORT Length; +} QMIDMS_GET_MSISDN_REQ_MSG, *PQMIDMS_GET_MSISDN_REQ_MSG; + +typedef struct _QCTLV_DEVICE_VOICE_NUMBERS +{ + UCHAR TLVType; // as defined above + USHORT TLVLength; // 4/7/7 + UCHAR VoideNumberString; // ESN, IMEI, or MEID + +} QCTLV_DEVICE_VOICE_NUMBERS, *PQCTLV_DEVICE_VOICE_NUMBERS; + + +typedef struct _QMIDMS_GET_MSISDN_RESP_MSG +{ + USHORT Type; // QMUX type 0x0024 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG +} QMIDMS_GET_MSISDN_RESP_MSG, *PQMIDMS_GET_MSISDN_RESP_MSG; +#endif + +typedef struct _QMIDMS_UIM_GET_IMSI_REQ_MSG { + USHORT Type; + USHORT Length; +} __attribute__((packed)) QMIDMS_UIM_GET_IMSI_REQ_MSG, + *PQMIDMS_UIM_GET_IMSI_REQ_MSG; + +typedef struct _QMIDMS_UIM_GET_IMSI_RESP_MSG { + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; + UCHAR TLV2Type; + USHORT TLV2Length; + UCHAR IMSI; +} __attribute__((packed)) QMIDMS_UIM_GET_IMSI_RESP_MSG, + *PQMIDMS_UIM_GET_IMSI_RESP_MSG; + +#if 0 +typedef struct _QMIDMS_GET_DEVICE_SERIAL_NUMBERS_REQ_MSG +{ + USHORT Type; // QMUX type 0x0007 + USHORT Length; +} QMIDMS_GET_DEVICE_SERIAL_NUMBERS_REQ_MSG, *PQMIDMS_GET_DEVICE_SERIAL_NUMBERS_REQ_MSG; + +#define QCTLV_TYPE_SER_NUM_ESN 0x10 +#define QCTLV_TYPE_SER_NUM_IMEI 0x11 +#define QCTLV_TYPE_SER_NUM_MEID 0x12 + +typedef struct _QCTLV_DEVICE_SERIAL_NUMBER +{ + UCHAR TLVType; // as defined above + USHORT TLVLength; // 4/7/7 + UCHAR SerialNumberString; // ESN, IMEI, or MEID + +} QCTLV_DEVICE_SERIAL_NUMBER, *PQCTLV_DEVICE_SERIAL_NUMBER; + +typedef struct _QMIDMS_GET_DEVICE_SERIAL_NUMBERS_RESP_MSG +{ + USHORT Type; // QMUX type 0x0007 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT + // followed by optional TLV +} QMIDMS_GET_DEVICE_SERIAL_NUMBERS_RESP_MSG, *PQMIDMS_GET_DEVICE_SERIAL_NUMBERS_RESP; + +typedef struct _QMIDMS_GET_DMS_BAND_CAP +{ + USHORT Type; + USHORT Length; +} QMIDMS_GET_BAND_CAP_REQ_MSG, *PQMIDMS_GET_BAND_CAP_REQ_MSG; + +typedef struct _QMIDMS_GET_BAND_CAP_RESP_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_NONE + // QMI_ERR_INTERNAL + // QMI_ERR_MALFORMED_MSG + // QMI_ERR_NO_MEMORY + + UCHAR TLV2Type; // 0x01 + USHORT TLV2Length; // 2 + ULONG64 BandCap; +} QMIDMS_GET_BAND_CAP_RESP_MSG, *PQMIDMS_GET_BAND_CAP_RESP; + +typedef struct _QMIDMS_GET_DEVICE_CAP_REQ_MSG +{ + USHORT Type; // QMUX type 0x0002 + USHORT Length; +} QMIDMS_GET_DEVICE_CAP_REQ_MSG, *PQMIDMS_GET_DEVICE_CAP_REQ_MSG; + +typedef struct _QMIDMS_GET_DEVICE_CAP_RESP_MSG +{ + USHORT Type; // QMUX type 0x0002 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMUX_RESULT_SUCCESS + // QMUX_RESULT_FAILURE + USHORT QMUXError; // QMUX_ERR_INVALID_ARG + // QMUX_ERR_NO_MEMORY + // QMUX_ERR_INTERNAL + // QMUX_ERR_FAULT + UCHAR TLV2Type; // 0x01 + USHORT TLV2Length; // 2 + + ULONG MaxTxChannelRate; + ULONG MaxRxChannelRate; + UCHAR VoiceCap; + UCHAR SimCap; + + UCHAR RadioIfListCnt; // #elements in radio interface list + UCHAR RadioIfList; // N 1-byte elements +} QMIDMS_GET_DEVICE_CAP_RESP_MSG, *PQMIDMS_GET_DEVICE_CAP_RESP_MSG; + +typedef struct _QMIDMS_GET_ACTIVATED_STATUS_REQ_MSG +{ + USHORT Type; // QMUX type 0x0002 + USHORT Length; +} QMIDMS_GET_ACTIVATED_STATUS_REQ_MSG, *PQMIDMS_GET_ACTIVATES_STATUD_REQ_MSG; + +typedef struct _QMIDMS_GET_ACTIVATED_STATUS_RESP_MSG +{ + USHORT Type; // QMUX type 0x0002 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMUX_RESULT_SUCCESS + // QMUX_RESULT_FAILURE + USHORT QMUXError; // QMUX_ERR_INVALID_ARG + // QMUX_ERR_NO_MEMORY + // QMUX_ERR_INTERNAL + // QMUX_ERR_FAULT + UCHAR TLV2Type; // 0x01 + USHORT TLV2Length; // 2 + + USHORT ActivatedStatus; +} QMIDMS_GET_ACTIVATED_STATUS_RESP_MSG, *PQMIDMS_GET_ACTIVATED_STATUS_RESP_MSG; + +typedef struct _QMIDMS_GET_OPERATING_MODE_REQ_MSG +{ + USHORT Type; // QMUX type 0x0002 + USHORT Length; +} QMIDMS_GET_OPERATING_MODE_REQ_MSG, *PQMIDMS_GET_OPERATING_MODE_REQ_MSG; + +typedef struct _OFFLINE_REASON +{ + UCHAR TLVType; + USHORT TLVLength; + USHORT OfflineReason; +} OFFLINE_REASON, *POFFLINE_REASON; + +typedef struct _HARDWARE_RESTRICTED_MODE +{ + UCHAR TLVType; + USHORT TLVLength; + UCHAR HardwareControlledMode; +} HARDWARE_RESTRICTED_MODE, *PHARDWARE_RESTRICTED_MODE; + +typedef struct _QMIDMS_GET_OPERATING_MODE_RESP_MSG +{ + USHORT Type; // QMUX type 0x0002 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMUX_RESULT_SUCCESS + // QMUX_RESULT_FAILURE + USHORT QMUXError; // QMUX_ERR_INVALID_ARG + // QMUX_ERR_NO_MEMORY + // QMUX_ERR_INTERNAL + // QMUX_ERR_FAULT + UCHAR TLV2Type; // 0x01 + USHORT TLV2Length; // 2 + + UCHAR OperatingMode; +} QMIDMS_GET_OPERATING_MODE_RESP_MSG, *PQMIDMS_GET_OPERATING_MODE_RESP_MSG; + +typedef struct _QMIDMS_UIM_GET_ICCID_REQ_MSG +{ + USHORT Type; // QMUX type 0x0024 + USHORT Length; +} QMIDMS_UIM_GET_ICCID_REQ_MSG, *PQMIDMS_UIM_GET_ICCID_REQ_MSG; + +typedef struct _QMIDMS_UIM_GET_ICCID_RESP_MSG +{ + USHORT Type; // QMUX type 0x0024 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT + UCHAR TLV2Type; // 0x01 - required parameter + USHORT TLV2Length; // var + UCHAR ICCID; // String of voice number +} QMIDMS_UIM_GET_ICCID_RESP_MSG, *PQMIDMS_UIM_GET_ICCID_RESP_MSG; +#endif + +typedef struct _QMIDMS_SET_OPERATING_MODE_REQ_MSG { + USHORT Type; // QMUX type 0x0002 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + UCHAR OperatingMode; +} __attribute__((packed)) QMIDMS_SET_OPERATING_MODE_REQ_MSG, + *PQMIDMS_SET_OPERATING_MODE_REQ_MSG; + +typedef struct _QMIDMS_SET_OPERATING_MODE_RESP_MSG { + USHORT Type; // QMUX type 0x0002 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMUX_RESULT_SUCCESS + // QMUX_RESULT_FAILURE + USHORT QMUXError; // QMUX_ERR_INVALID_ARG + // QMUX_ERR_NO_MEMORY + // QMUX_ERR_INTERNAL + // QMUX_ERR_FAULT +} __attribute__((packed)) QMIDMS_SET_OPERATING_MODE_RESP_MSG, + *PQMIDMS_SET_OPERATING_MODE_RESP_MSG; + +#if 0 +typedef struct _QMIDMS_ACTIVATE_AUTOMATIC_REQ_MSG +{ + USHORT Type; // QMUX type 0x0024 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // + UCHAR ActivateCodelen; + UCHAR ActivateCode; +} QMIDMS_ACTIVATE_AUTOMATIC_REQ_MSG, *PQMIDMS_ACTIVATE_AUTOMATIC_REQ_MSG; + +typedef struct _QMIDMS_ACTIVATE_AUTOMATIC_RESP_MSG +{ + USHORT Type; // QMUX type 0x0024 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT +} QMIDMS_ACTIVATE_AUTOMATIC_RESP_MSG, *PQMIDMS_ACTIVATE_AUTOMATIC_RESP_MSG; + + +typedef struct _SPC_MSG +{ + UCHAR SPC[6]; + USHORT SID; +} SPC_MSG, *PSPC_MSG; + +typedef struct _MDN_MSG +{ + UCHAR MDNLEN; + UCHAR MDN; +} MDN_MSG, *PMDN_MSG; + +typedef struct _MIN_MSG +{ + UCHAR MINLEN; + UCHAR MIN; +} MIN_MSG, *PMIN_MSG; + +typedef struct _PRL_MSG +{ + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // + USHORT PRLLEN; + UCHAR PRL; +} PRL_MSG, *PPRL_MSG; + +typedef struct _MN_HA_KEY_MSG +{ + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // + UCHAR MN_HA_KEY_LEN; + UCHAR MN_HA_KEY; +} MN_HA_KEY_MSG, *PMN_HA_KEY_MSG; + +typedef struct _MN_AAA_KEY_MSG +{ + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // + UCHAR MN_AAA_KEY_LEN; + UCHAR MN_AAA_KEY; +} MN_AAA_KEY_MSG, *PMN_AAA_KEY_MSG; + +typedef struct _QMIDMS_ACTIVATE_MANUAL_REQ_MSG +{ + USHORT Type; // QMUX type 0x0024 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // + UCHAR Value; +} QMIDMS_ACTIVATE_MANUAL_REQ_MSG, *PQMIDMS_ACTIVATE_MANUAL_REQ_MSG; + +typedef struct _QMIDMS_ACTIVATE_MANUAL_RESP_MSG +{ + USHORT Type; // QMUX type 0x0024 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT +} QMIDMS_ACTIVATE_MANUAL_RESP_MSG, *PQMIDMS_ACTIVATE_MANUAL_RESP_MSG; +#endif + +typedef struct _QMIDMS_UIM_GET_STATE_REQ_MSG { + USHORT Type; + USHORT Length; +} __attribute__((packed)) QMIDMS_UIM_GET_STATE_REQ_MSG, + *PQMIDMS_UIM_GET_STATE_REQ_MSG; + +typedef struct _QMIDMS_UIM_GET_STATE_RESP_MSG { + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; + UCHAR TLV2Type; + USHORT TLV2Length; + UCHAR UIMState; +} __attribute__((packed)) QMIDMS_UIM_GET_STATE_RESP_MSG, + *PQMIDMS_UIM_GET_STATE_RESP_MSG; + +typedef struct _QMIDMS_UIM_GET_PIN_STATUS_REQ_MSG { + USHORT Type; // QMUX type 0x0024 + USHORT Length; +} __attribute__((packed)) QMIDMS_UIM_GET_PIN_STATUS_REQ_MSG, + *PQMIDMS_UIM_GET_PIN_STATUS_REQ_MSG; + +typedef struct _QMIDMS_UIM_PIN_STATUS { + UCHAR TLVType; + USHORT TLVLength; + UCHAR PINStatus; + UCHAR PINVerifyRetriesLeft; + UCHAR PINUnblockRetriesLeft; +} __attribute__((packed)) QMIDMS_UIM_PIN_STATUS, *PQMIDMS_UIM_PIN_STATUS; + +#define QMI_PIN_STATUS_NOT_INIT 0 +#define QMI_PIN_STATUS_NOT_VERIF 1 +#define QMI_PIN_STATUS_VERIFIED 2 +#define QMI_PIN_STATUS_DISABLED 3 +#define QMI_PIN_STATUS_BLOCKED 4 +#define QMI_PIN_STATUS_PERM_BLOCKED 5 +#define QMI_PIN_STATUS_UNBLOCKED 6 +#define QMI_PIN_STATUS_CHANGED 7 + +typedef struct _QMIDMS_UIM_GET_PIN_STATUS_RESP_MSG { + USHORT Type; // QMUX type 0x0024 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT + UCHAR PinStatus; +} __attribute__((packed)) QMIDMS_UIM_GET_PIN_STATUS_RESP_MSG, + *PQMIDMS_UIM_GET_PIN_STATUS_RESP_MSG; + +#if 0 +typedef struct _QMIDMS_UIM_GET_CK_STATUS_REQ_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + UCHAR Facility; +} QMIDMS_UIM_GET_CK_STATUS_REQ_MSG, *PQMIDMS_UIM_GET_CK_STATUS_REQ_MSG; + + +typedef struct _QMIDMS_UIM_CK_STATUS +{ + UCHAR TLVType; + USHORT TLVLength; + UCHAR FacilityStatus; + UCHAR FacilityVerifyRetriesLeft; + UCHAR FacilityUnblockRetriesLeft; +} QMIDMS_UIM_CK_STATUS, *PQMIDMS_UIM_CK_STATUS; + +typedef struct _QMIDMS_UIM_CK_OPERATION_STATUS +{ + UCHAR TLVType; + USHORT TLVLength; + UCHAR OperationBlocking; +} QMIDMS_UIM_CK_OPERATION_STATUS, *PQMIDMS_UIM_CK_OPERATION_STATUS; + +typedef struct _QMIDMS_UIM_GET_CK_STATUS_RESP_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; + UCHAR CkStatus; +} QMIDMS_UIM_GET_CK_STATUS_RESP_MSG, *PQMIDMS_UIM_GET_CK_STATUS_RESP_MSG; +#endif + +typedef struct _QMIDMS_UIM_VERIFY_PIN_REQ_MSG { + USHORT Type; // QMUX type 0x0024 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + UCHAR PINID; + UCHAR PINLen; + UCHAR PINValue; +} __attribute__((packed)) QMIDMS_UIM_VERIFY_PIN_REQ_MSG, + *PQMIDMS_UIM_VERIFY_PIN_REQ_MSG; + +typedef struct _QMIDMS_UIM_VERIFY_PIN_RESP_MSG { + USHORT Type; // QMUX type 0x0024 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT + UCHAR TLV2Type; + USHORT TLV2Length; + UCHAR PINVerifyRetriesLeft; + UCHAR PINUnblockRetriesLeft; +} __attribute__((packed)) QMIDMS_UIM_VERIFY_PIN_RESP_MSG, + *PQMIDMS_UIM_VERIFY_PIN_RESP_MSG; + +#if 0 +typedef struct _QMIDMS_UIM_SET_PIN_PROTECTION_REQ_MSG +{ + USHORT Type; // QMUX type 0x0024 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + UCHAR PINID; + UCHAR ProtectionSetting; + UCHAR PINLen; + UCHAR PINValue; +} QMIDMS_UIM_SET_PIN_PROTECTION_REQ_MSG, *PQMIDMS_UIM_SET_PIN_PROTECTION_REQ_MSG; + +typedef struct _QMIDMS_UIM_SET_PIN_PROTECTION_RESP_MSG +{ + USHORT Type; // QMUX type 0x0024 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT + UCHAR TLV2Type; + USHORT TLV2Length; + UCHAR PINVerifyRetriesLeft; + UCHAR PINUnblockRetriesLeft; +} QMIDMS_UIM_SET_PIN_PROTECTION_RESP_MSG, *PQMIDMS_UIM_SET_PIN_PROTECTION_RESP_MSG; + +typedef struct _QMIDMS_UIM_SET_CK_PROTECTION_REQ_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + UCHAR Facility; + UCHAR FacilityState; + UCHAR FacliltyLen; + UCHAR FacliltyValue; +} QMIDMS_UIM_SET_CK_PROTECTION_REQ_MSG, *PQMIDMS_UIM_SET_CK_PROTECTION_REQ_MSG; + +typedef struct _QMIDMS_UIM_SET_CK_PROTECTION_RESP_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; + UCHAR TLV2Type; + USHORT TLV2Length; + UCHAR FacilityRetriesLeft; +} QMIDMS_UIM_SET_CK_PROTECTION_RESP_MSG, *PQMIDMS_UIM_SET_CK_PROTECTION_RESP_MSG; + + +typedef struct _UIM_PIN +{ + UCHAR PinLength; + UCHAR PinValue; +} UIM_PIN, *PUIM_PIN; + +typedef struct _QMIDMS_UIM_CHANGE_PIN_REQ_MSG +{ + USHORT Type; // QMUX type 0x0024 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + UCHAR PINID; + UCHAR PinDetails; +} QMIDMS_UIM_CHANGE_PIN_REQ_MSG, *PQMIDMS_UIM_CHANGE_PIN_REQ_MSG; + +typedef struct QMIDMS_UIM_CHANGE_PIN_RESP_MSG +{ + USHORT Type; // QMUX type 0x0024 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT + UCHAR TLV2Type; + USHORT TLV2Length; + UCHAR PINVerifyRetriesLeft; + UCHAR PINUnblockRetriesLeft; +} QMIDMS_UIM_CHANGE_PIN_RESP_MSG, *PQMIDMS_UIM_CHANGE_PIN_RESP_MSG; + +typedef struct _UIM_PUK +{ + UCHAR PukLength; + UCHAR PukValue; +} UIM_PUK, *PUIM_PUK; + +typedef struct _QMIDMS_UIM_UNBLOCK_PIN_REQ_MSG +{ + USHORT Type; // QMUX type 0x0024 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + UCHAR PINID; + UCHAR PinDetails; +} QMIDMS_UIM_UNBLOCK_PIN_REQ_MSG, *PQMIDMS_UIM_BLOCK_PIN_REQ_MSG; + +typedef struct QMIDMS_UIM_UNBLOCK_PIN_RESP_MSG +{ + USHORT Type; // QMUX type 0x0024 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT + UCHAR TLV2Type; + USHORT TLV2Length; + UCHAR PINVerifyRetriesLeft; + UCHAR PINUnblockRetriesLeft; +} QMIDMS_UIM_UNBLOCK_PIN_RESP_MSG, *PQMIDMS_UIM_UNBLOCK_PIN_RESP_MSG; + +typedef struct _QMIDMS_UIM_UNBLOCK_CK_REQ_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + UCHAR Facility; + UCHAR FacliltyUnblockLen; + UCHAR FacliltyUnblockValue; +} QMIDMS_UIM_UNBLOCK_CK_REQ_MSG, *PQMIDMS_UIM_BLOCK_CK_REQ_MSG; + +typedef struct QMIDMS_UIM_UNBLOCK_CK_RESP_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; + UCHAR TLV2Type; + USHORT TLV2Length; + UCHAR FacilityUnblockRetriesLeft; +} QMIDMS_UIM_UNBLOCK_CK_RESP_MSG, *PQMIDMS_UIM_UNBLOCK_CK_RESP_MSG; + +typedef struct _QMIDMS_SET_EVENT_REPORT_REQ_MSG +{ + USHORT Type; + USHORT Length; +} QMIDMS_SET_EVENT_REPORT_REQ_MSG, *PQMIDMS_SET_EVENT_REPORT_REQ_MSG; + +typedef struct _QMIDMS_SET_EVENT_REPORT_RESP_MSG +{ + USHORT Type; // QMUX type 0x0003 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG +} QMIDMS_SET_EVENT_REPORT_RESP_MSG, *PQMIDMS_SET_EVENT_REPORT_RESP_MSG; + +typedef struct _PIN_STATUS +{ + UCHAR TLVType; + USHORT TLVLength; + UCHAR ReportPinState; +} PIN_STATUS, *PPIN_STATUS; + +typedef struct _POWER_STATUS +{ + UCHAR TLVType; + USHORT TLVLength; + UCHAR PowerStatus; + UCHAR BatteryLvl; +} POWER_STATUS, *PPOWER_STATUS; + +typedef struct _ACTIVATION_STATE +{ + UCHAR TLVType; + USHORT TLVLength; + USHORT ActivationState; +} ACTIVATION_STATE, *PACTIVATION_STATE; + +typedef struct _ACTIVATION_STATE_REQ +{ + UCHAR TLVType; + USHORT TLVLength; + UCHAR ActivationState; +} ACTIVATION_STATE_REQ, *PACTIVATION_STATE_REQ; + +typedef struct _OPERATING_MODE +{ + UCHAR TLVType; + USHORT TLVLength; + UCHAR OperatingMode; +} OPERATING_MODE, *POPERATING_MODE; + +typedef struct _UIM_STATE +{ + UCHAR TLVType; + USHORT TLVLength; + UCHAR UIMState; +} UIM_STATE, *PUIM_STATE; + +typedef struct _WIRELESS_DISABLE_STATE +{ + UCHAR TLVType; + USHORT TLVLength; + UCHAR WirelessDisableState; +} WIRELESS_DISABLE_STATE, *PWIRELESS_DISABLE_STATE; + +typedef struct _QMIDMS_EVENT_REPORT_IND_MSG +{ + USHORT Type; + USHORT Length; +} QMIDMS_EVENT_REPORT_IND_MSG, *PQMIDMS_EVENT_REPORT_IND_MSG; +#endif + +// ============================ END OF DMS =============================== + +// ======================= QOS ============================== +typedef struct _MPIOC_DEV_INFO MPIOC_DEV_INFO, *PMPIOC_DEV_INFO; + +#define QMI_QOS_SET_EVENT_REPORT_REQ 0x0001 +#define QMI_QOS_SET_EVENT_REPORT_RESP 0x0001 +#define QMI_QOS_EVENT_REPORT_IND 0x0001 + +#if 0 +typedef struct _QMI_QOS_SET_EVENT_REPORT_REQ_MSG +{ + USHORT Type; // QMUX type 0x0001 + USHORT Length; + // UCHAR TLVType; // 0x01 - physical link state + // USHORT TLVLength; // 1 + // UCHAR PhyLinkStatusRpt; // 0-enable; 1-disable + UCHAR TLVType2; // 0x02 = global flow reporting + USHORT TLVLength2; // 1 + UCHAR GlobalFlowRpt; // 1-enable; 0-disable +} QMI_QOS_SET_EVENT_REPORT_REQ_MSG, *PQMI_QOS_SET_EVENT_REPORT_REQ_MSG; + +typedef struct _QMI_QOS_SET_EVENT_REPORT_RESP_MSG +{ + USHORT Type; // QMUX type 0x0010 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMUX_RESULT_SUCCESS + // QMUX_RESULT_FAILURE + USHORT QMUXError; // QMUX_ERR_INVALID_ARG + // QMUX_ERR_NO_MEMORY + // QMUX_ERR_INTERNAL + // QMUX_ERR_FAULT +} QMI_QOS_SET_EVENT_REPORT_RESP_MSG, *PQMI_QOS_SET_EVENT_REPORT_RESP_MSG; + +typedef struct _QMI_QOS_EVENT_REPORT_IND_MSG +{ + USHORT Type; // QMUX type 0x0001 + USHORT Length; + UCHAR TLVs; +} QMI_QOS_EVENT_REPORT_IND_MSG, *PQMI_QOS_EVENT_REPORT_IND_MSG; + +#define QOS_EVENT_RPT_IND_FLOW_ACTIVATED 0x01 +#define QOS_EVENT_RPT_IND_FLOW_MODIFIED 0x02 +#define QOS_EVENT_RPT_IND_FLOW_DELETED 0x03 +#define QOS_EVENT_RPT_IND_FLOW_SUSPENDED 0x04 +#define QOS_EVENT_RPT_IND_FLOW_ENABLED 0x05 +#define QOS_EVENT_RPT_IND_FLOW_DISABLED 0x06 + +#define QOS_EVENT_RPT_IND_TLV_PHY_LINK_STATE_TYPE 0x01 +#define QOS_EVENT_RPT_IND_TLV_GLOBAL_FL_RPT_STATE 0x10 +#define QOS_EVENT_RPT_IND_TLV_GLOBAL_FL_RPT_TYPE 0x10 +#define QOS_EVENT_RPT_IND_TLV_TX_FLOW_TYPE 0x11 +#define QOS_EVENT_RPT_IND_TLV_RX_FLOW_TYPE 0x12 +#define QOS_EVENT_RPT_IND_TLV_TX_FILTER_TYPE 0x13 +#define QOS_EVENT_RPT_IND_TLV_RX_FILTER_TYPE 0x14 +#define QOS_EVENT_RPT_IND_TLV_FLOW_SPEC 0x10 +#define QOS_EVENT_RPT_IND_TLV_FILTER_SPEC 0x10 + +typedef struct _QOS_EVENT_RPT_IND_TLV_PHY_LINK_STATE +{ + UCHAR TLVType; // 0x01 + USHORT TLVLength; // 1 + UCHAR PhyLinkState; // 0-dormant, 1-active +} QOS_EVENT_RPT_IND_TLV_PHY_LINK_STATE, *PQOS_EVENT_RPT_IND_TLV_PHY_LINK_STATE; + +typedef struct _QOS_EVENT_RPT_IND_TLV_GLOBAL_FL_RPT +{ + UCHAR TLVType; // 0x10 + USHORT TLVLength; // 6 + ULONG QosId; + UCHAR NewFlow; // 1: newly added flow; 0: existing flow + UCHAR StateChange; // 1: activated; 2: modified; 3: deleted; + // 4: suspended(delete); 5: enabled; 6: disabled +} QOS_EVENT_RPT_IND_TLV_GLOBAL_FL_RPT, *PQOS_EVENT_RPT_IND_TLV_GLOBAL_FL_RPT; + +// QOS Flow + +typedef struct _QOS_EVENT_RPT_IND_TLV_FLOW +{ + UCHAR TLVType; // 0x10-TX flow; 0x11-RX flow + USHORT TLVLength; // var + // embedded TLV's +} QOS_EVENT_RPT_IND_TLV_TX_FLOW, *PQOS_EVENT_RPT_IND_TLV_TX_FLOW; + +#define QOS_FLOW_TLV_IP_FLOW_IDX_TYPE 0x10 +#define QOS_FLOW_TLV_IP_FLOW_TRAFFIC_CLASS_TYPE 0x11 +#define QOS_FLOW_TLV_IP_FLOW_DATA_RATE_MIN_MAX_TYPE 0x12 +#define QOS_FLOW_TLV_IP_FLOW_DATA_RATE_TOKEN_BUCKET_TYPE 0x13 +#define QOS_FLOW_TLV_IP_FLOW_LATENCY_TYPE 0x14 +#define QOS_FLOW_TLV_IP_FLOW_JITTER_TYPE 0x15 +#define QOS_FLOW_TLV_IP_FLOW_PKT_ERR_RATE_TYPE 0x16 +#define QOS_FLOW_TLV_IP_FLOW_MIN_PKT_SIZE_TYPE 0x17 +#define QOS_FLOW_TLV_IP_FLOW_MAX_PKT_SIZE_TYPE 0x18 +#define QOS_FLOW_TLV_IP_FLOW_3GPP_BIT_ERR_RATE_TYPE 0x19 +#define QOS_FLOW_TLV_IP_FLOW_3GPP_TRAF_PRIORITY_TYPE 0x1A +#define QOS_FLOW_TLV_IP_FLOW_3GPP2_PROFILE_ID_TYPE 0x1B + +typedef struct _QOS_FLOW_TLV_IP_FLOW_IDX +{ + UCHAR TLVType; // 0x10 + USHORT TLVLength; // 1 + UCHAR IpFlowIndex; +} QOS_FLOW_TLV_IP_FLOW_IDX, *PQOS_FLOW_TLV_IP_FLOW_IDX; + +typedef struct _QOS_FLOW_TLV_IP_FLOW_TRAFFIC_CLASS +{ + UCHAR TLVType; // 0x11 + USHORT TLVLength; // 1 + UCHAR TrafficClass; +} QOS_FLOW_TLV_IP_FLOW_TRAFFIC_CLASS, *PQOS_FLOW_TLV_IP_FLOW_TRAFFIC_CLASS; + +typedef struct _QOS_FLOW_TLV_IP_FLOW_DATA_RATE_MIN_MAX +{ + UCHAR TLVType; // 0x12 + USHORT TLVLength; // 8 + ULONG DataRateMax; + ULONG GuaranteedRate; +} QOS_FLOW_TLV_IP_FLOW_DATA_RATE_MIN_MAX, *PQOS_FLOW_TLV_IP_FLOW_DATA_RATE_MIN_MAX; + +typedef struct _QOS_FLOW_TLV_IP_FLOW_DATA_RATE_TOKEN_BUCKET +{ + UCHAR TLVType; // 0x13 + USHORT TLVLength; // 12 + ULONG PeakRate; + ULONG TokenRate; + ULONG BucketSize; +} QOS_FLOW_TLV_IP_FLOW_DATA_RATE_TOKEN_BUCKET, *PQOS_FLOW_TLV_IP_FLOW_DATA_RATE_TOKEN_BUCKET; + +typedef struct _QOS_FLOW_TLV_IP_FLOW_LATENCY +{ + UCHAR TLVType; // 0x14 + USHORT TLVLength; // 4 + ULONG IpFlowLatency; +} QOS_FLOW_TLV_IP_FLOW_LATENCY, *PQOS_FLOW_TLV_IP_FLOW_LATENCY; + +typedef struct _QOS_FLOW_TLV_IP_FLOW_JITTER +{ + UCHAR TLVType; // 0x15 + USHORT TLVLength; // 4 + ULONG IpFlowJitter; +} QOS_FLOW_TLV_IP_FLOW_JITTER, *PQOS_FLOW_TLV_IP_FLOW_JITTER; + +typedef struct _QOS_FLOW_TLV_IP_FLOW_PKT_ERR_RATE +{ + UCHAR TLVType; // 0x16 + USHORT TLVLength; // 4 + USHORT ErrRateMultiplier; + USHORT ErrRateExponent; +} QOS_FLOW_TLV_IP_FLOW_PKT_ERR_RATE, *PQOS_FLOW_TLV_IP_FLOW_PKT_ERR_RATE; + +typedef struct _QOS_FLOW_TLV_IP_FLOW_MIN_PKT_SIZE +{ + UCHAR TLVType; // 0x17 + USHORT TLVLength; // 4 + ULONG MinPolicedPktSize; +} QOS_FLOW_TLV_IP_FLOW_MIN_PKT_SIZE, *PQOS_FLOW_TLV_IP_FLOW_MIN_PKT_SIZE; + +typedef struct _QOS_FLOW_TLV_IP_FLOW_MAX_PKT_SIZE +{ + UCHAR TLVType; // 0x18 + USHORT TLVLength; // 4 + ULONG MaxAllowedPktSize; +} QOS_FLOW_TLV_IP_FLOW_MAX_PKT_SIZE, *PQOS_FLOW_TLV_IP_FLOW_MAX_PKT_SIZE; + +typedef struct _QOS_FLOW_TLV_IP_FLOW_3GPP_BIT_ERR_RATE +{ + UCHAR TLVType; // 0x19 + USHORT TLVLength; // 1 + UCHAR ResidualBitErrorRate; +} QOS_FLOW_TLV_IP_FLOW_3GPP_BIT_ERR_RATE, *PQOS_FLOW_TLV_IP_FLOW_3GPP_BIT_ERR_RATE; + +typedef struct _QOS_FLOW_TLV_IP_FLOW_3GPP_TRAF_PRIORITY +{ + UCHAR TLVType; // 0x1A + USHORT TLVLength; // 1 + UCHAR TrafficHandlingPriority; +} QOS_FLOW_TLV_IP_FLOW_3GPP_TRAF_PRIORITY, *PQOS_FLOW_TLV_IP_FLOW_3GPP_TRAF_PRIORITY; + +typedef struct _QOS_FLOW_TLV_IP_FLOW_3GPP2_PROFILE_ID +{ + UCHAR TLVType; // 0x1B + USHORT TLVLength; // 2 + USHORT ProfileId; +} QOS_FLOW_TLV_IP_FLOW_3GPP2_PROFILE_ID, *PQOS_FLOW_TLV_IP_FLOW_3GPP2_PROFILE_ID; + +// QOS Filter + +#define QOS_FILTER_TLV_IP_FILTER_IDX_TYPE 0x10 +#define QOS_FILTER_TLV_IP_VERSION_TYPE 0x11 +#define QOS_FILTER_TLV_IPV4_SRC_ADDR_TYPE 0x12 +#define QOS_FILTER_TLV_IPV4_DEST_ADDR_TYPE 0x13 +#define QOS_FILTER_TLV_NEXT_HDR_PROTOCOL_TYPE 0x14 +#define QOS_FILTER_TLV_IPV4_TYPE_OF_SERVICE_TYPE 0x15 +#define QOS_FILTER_TLV_TCP_UDP_PORT_SRC_TCP_TYPE 0x1B +#define QOS_FILTER_TLV_TCP_UDP_PORT_DEST_TCP_TYPE 0x1C +#define QOS_FILTER_TLV_TCP_UDP_PORT_SRC_UDP_TYPE 0x1D +#define QOS_FILTER_TLV_TCP_UDP_PORT_DEST_UDP_TYPE 0x1E +#define QOS_FILTER_TLV_ICMP_FILTER_MSG_TYPE_TYPE 0x1F +#define QOS_FILTER_TLV_ICMP_FILTER_MSG_CODE_TYPE 0x20 +#define QOS_FILTER_TLV_TCP_UDP_PORT_SRC_TYPE 0x24 +#define QOS_FILTER_TLV_TCP_UDP_PORT_DEST_TYPE 0x25 + +typedef struct _QOS_EVENT_RPT_IND_TLV_FILTER +{ + UCHAR TLVType; // 0x12-TX filter; 0x13-RX filter + USHORT TLVLength; // var + // embedded TLV's +} QOS_EVENT_RPT_IND_TLV_RX_FILTER, *PQOS_EVENT_RPT_IND_TLV_RX_FILTER; + +typedef struct _QOS_FILTER_TLV_IP_FILTER_IDX +{ + UCHAR TLVType; // 0x10 + USHORT TLVLength; // 1 + UCHAR IpFilterIndex; +} QOS_FILTER_TLV_IP_FILTER_IDX, *PQOS_FILTER_TLV_IP_FILTER_IDX; + +typedef struct _QOS_FILTER_TLV_IP_VERSION +{ + UCHAR TLVType; // 0x11 + USHORT TLVLength; // 1 + UCHAR IpVersion; +} QOS_FILTER_TLV_IP_VERSION, *PQOS_FILTER_TLV_IP_VERSION; + +typedef struct _QOS_FILTER_TLV_IPV4_SRC_ADDR +{ + UCHAR TLVType; // 0x12 + USHORT TLVLength; // 8 + ULONG IpSrcAddr; + ULONG IpSrcSubnetMask; +} QOS_FILTER_TLV_IPV4_SRC_ADDR, *PQOS_FILTER_TLV_IPV4_SRC_ADDR; + +typedef struct _QOS_FILTER_TLV_IPV4_DEST_ADDR +{ + UCHAR TLVType; // 0x13 + USHORT TLVLength; // 8 + ULONG IpDestAddr; + ULONG IpDestSubnetMask; +} QOS_FILTER_TLV_IPV4_DEST_ADDR, *PQOS_FILTER_TLV_IPV4_DEST_ADDR; + +typedef struct _QOS_FILTER_TLV_NEXT_HDR_PROTOCOL +{ + UCHAR TLVType; // 0x14 + USHORT TLVLength; // 1 + UCHAR NextHdrProtocol; +} QOS_FILTER_TLV_NEXT_HDR_PROTOCOL, *PQOS_FILTER_TLV_NEXT_HDR_PROTOCOL; + +typedef struct _QOS_FILTER_TLV_IPV4_TYPE_OF_SERVICE +{ + UCHAR TLVType; // 0x15 + USHORT TLVLength; // 2 + UCHAR Ipv4TypeOfService; + UCHAR Ipv4TypeOfServiceMask; +} QOS_FILTER_TLV_IPV4_TYPE_OF_SERVICE, *PQOS_FILTER_TLV_IPV4_TYPE_OF_SERVICE; + +typedef struct _QOS_FILTER_TLV_TCP_UDP_PORT +{ + UCHAR TLVType; // source port: 0x1B-TCP; 0x1D-UDP + // dest port: 0x1C-TCP; 0x1E-UDP + USHORT TLVLength; // 4 + USHORT FilterPort; + USHORT FilterPortRange; +} QOS_FILTER_TLV_TCP_UDP_PORT, *PQOS_FILTER_TLV_TCP_UDP_PORT; + +typedef struct _QOS_FILTER_TLV_ICMP_FILTER_MSG_TYPE +{ + UCHAR TLVType; // 0x1F + USHORT TLVLength; // 1 + UCHAR IcmpFilterMsgType; +} QOS_FILTER_TLV_ICMP_FILTER_MSG_TYPE, *PQOS_FILTER_TLV_ICMP_FILTER_MSG_TYPE; + +typedef struct _QOS_FILTER_TLV_ICMP_FILTER_MSG_CODE +{ + UCHAR TLVType; // 0x20 + USHORT TLVLength; // 1 + UCHAR IcmpFilterMsgCode; +} QOS_FILTER_TLV_ICMP_FILTER_MSG_CODE, *PQOS_FILTER_TLV_ICMP_FILTER_MSG_CODE; + +#define QOS_FILTER_PRECEDENCE_INVALID 256 +#define QOS_FILTER_TLV_PRECEDENCE_TYPE 0x22 +#define QOS_FILTER_TLV_ID_TYPE 0x23 + +typedef struct _QOS_FILTER_TLV_PRECEDENCE +{ + UCHAR TLVType; // 0x22 + USHORT TLVLength; // 2 + USHORT Precedence; // precedence of the filter +} QOS_FILTER_TLV_PRECEDENCE, *PQOS_FILTER_TLV_PRECEDENCE; + +typedef struct _QOS_FILTER_TLV_ID +{ + UCHAR TLVType; // 0x23 + USHORT TLVLength; // 2 + USHORT FilterId; // filter ID +} QOS_FILTER_TLV_ID, *PQOS_FILTER_TLV_ID; + +#ifdef QCQOS_IPV6 + +#define QOS_FILTER_TLV_IPV6_SRC_ADDR_TYPE 0x16 +#define QOS_FILTER_TLV_IPV6_DEST_ADDR_TYPE 0x17 +#define QOS_FILTER_TLV_IPV6_NEXT_HDR_PROTOCOL_TYPE 0x14 // same as IPV4 +#define QOS_FILTER_TLV_IPV6_TRAFFIC_CLASS_TYPE 0x19 +#define QOS_FILTER_TLV_IPV6_FLOW_LABEL_TYPE 0x1A + +typedef struct _QOS_FILTER_TLV_IPV6_SRC_ADDR +{ + UCHAR TLVType; // 0x16 + USHORT TLVLength; // 17 + UCHAR IpSrcAddr[16]; + UCHAR IpSrcAddrPrefixLen; // [0..128] +} QOS_FILTER_TLV_IPV6_SRC_ADDR, *PQOS_FILTER_TLV_IPV6_SRC_ADDR; + +typedef struct _QOS_FILTER_TLV_IPV6_DEST_ADDR +{ + UCHAR TLVType; // 0x17 + USHORT TLVLength; // 17 + UCHAR IpDestAddr[16]; + UCHAR IpDestAddrPrefixLen; // [0..128] +} QOS_FILTER_TLV_IPV6_DEST_ADDR, *PQOS_FILTER_TLV_IPV6_DEST_ADDR; + +#define QOS_FILTER_IPV6_NEXT_HDR_PROTOCOL_TCP 0x06 +#define QOS_FILTER_IPV6_NEXT_HDR_PROTOCOL_UDP 0x11 + +typedef struct _QOS_FILTER_TLV_IPV6_TRAFFIC_CLASS +{ + UCHAR TLVType; // 0x19 + USHORT TLVLength; // 2 + UCHAR TrafficClass; + UCHAR TrafficClassMask; // compare the first 6 bits only +} QOS_FILTER_TLV_IPV6_TRAFFIC_CLASS, *PQOS_FILTER_TLV_IPV6_TRAFFIC_CLASS; + +typedef struct _QOS_FILTER_TLV_IPV6_FLOW_LABEL +{ + UCHAR TLVType; // 0x1A + USHORT TLVLength; // 4 + ULONG FlowLabel; +} QOS_FILTER_TLV_IPV6_FLOW_LABEL, *PQOS_FILTER_TLV_IPV6_FLOW_LABEL; + +#endif // QCQOS_IPV6 +#endif + +// ======================= WMS ============================== +#define QMIWMS_SET_EVENT_REPORT_REQ 0x0001 +#define QMIWMS_SET_EVENT_REPORT_RESP 0x0001 +#define QMIWMS_EVENT_REPORT_IND 0x0001 +#define QMIWMS_RAW_SEND_REQ 0x0020 +#define QMIWMS_RAW_SEND_RESP 0x0020 +#define QMIWMS_RAW_WRITE_REQ 0x0021 +#define QMIWMS_RAW_WRITE_RESP 0x0021 +#define QMIWMS_RAW_READ_REQ 0x0022 +#define QMIWMS_RAW_READ_RESP 0x0022 +#define QMIWMS_MODIFY_TAG_REQ 0x0023 +#define QMIWMS_MODIFY_TAG_RESP 0x0023 +#define QMIWMS_DELETE_REQ 0x0024 +#define QMIWMS_DELETE_RESP 0x0024 +#define QMIWMS_GET_MESSAGE_PROTOCOL_REQ 0x0030 +#define QMIWMS_GET_MESSAGE_PROTOCOL_RESP 0x0030 +#define QMIWMS_LIST_MESSAGES_REQ 0x0031 +#define QMIWMS_LIST_MESSAGES_RESP 0x0031 +#define QMIWMS_GET_SMSC_ADDRESS_REQ 0x0034 +#define QMIWMS_GET_SMSC_ADDRESS_RESP 0x0034 +#define QMIWMS_SET_SMSC_ADDRESS_REQ 0x0035 +#define QMIWMS_SET_SMSC_ADDRESS_RESP 0x0035 +#define QMIWMS_GET_STORE_MAX_SIZE_REQ 0x0036 +#define QMIWMS_GET_STORE_MAX_SIZE_RESP 0x0036 + +#define WMS_MESSAGE_PROTOCOL_CDMA 0x00 +#define WMS_MESSAGE_PROTOCOL_WCDMA 0x01 + +#if 0 +typedef struct _QMIWMS_GET_MESSAGE_PROTOCOL_REQ_MSG +{ + USHORT Type; // QMUX type 0x0003 + USHORT Length; +} QMIWMS_GET_MESSAGE_PROTOCOL_REQ_MSG, *PQMIWMS_GET_MESSAGE_PROTOCOL_REQ_MSG; + +typedef struct _QMIWMS_GET_MESSAGE_PROTOCOL_RESP_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; + UCHAR TLV2Type; + USHORT TLV2Length; + UCHAR MessageProtocol; +} QMIWMS_GET_MESSAGE_PROTOCOL_RESP_MSG, *PQMIWMS_GET_MESSAGE_PROTOCOL_RESP_MSG; + +typedef struct _QMIWMS_GET_STORE_MAX_SIZE_REQ_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + UCHAR StorageType; +} QMIWMS_GET_STORE_MAX_SIZE_REQ_MSG, *PQMIWMS_GET_STORE_MAX_SIZE_REQ_MSG; + +typedef struct _QMIWMS_GET_STORE_MAX_SIZE_RESP_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; + UCHAR TLV2Type; + USHORT TLV2Length; + ULONG MemStoreMaxSize; +} QMIWMS_GET_STORE_MAX_SIZE_RESP_MSG, *PQMIWMS_GET_STORE_MAX_SIZE_RESP_MSG; + +typedef struct _REQUEST_TAG +{ + UCHAR TLVType; + USHORT TLVLength; + UCHAR TagType; +} REQUEST_TAG, *PREQUEST_TAG; + +typedef struct _QMIWMS_LIST_MESSAGES_REQ_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + UCHAR StorageType; +} QMIWMS_LIST_MESSAGES_REQ_MSG, *PQMIWMS_LIST_MESSAGES_REQ_MSG; + +typedef struct _QMIWMS_MESSAGE +{ + ULONG MessageIndex; + UCHAR TagType; +} QMIWMS_MESSAGE, *PQMIWMS_MESSAGE; + +typedef struct _QMIWMS_LIST_MESSAGES_RESP_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; + UCHAR TLV2Type; + USHORT TLV2Length; + ULONG NumMessages; +} QMIWMS_LIST_MESSAGES_RESP_MSG, *PQMIWMS_LIST_MESSAGES_RESP_MSG; + +typedef struct _QMIWMS_RAW_READ_REQ_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + UCHAR StorageType; + ULONG MemoryIndex; +} QMIWMS_RAW_READ_REQ_MSG, *PQMIWMS_RAW_READ_REQ_MSG; + +typedef struct _QMIWMS_RAW_READ_RESP_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; + UCHAR TLV2Type; + USHORT TLV2Length; + UCHAR TagType; + UCHAR Format; + USHORT MessageLength; + UCHAR Message; +} QMIWMS_RAW_READ_RESP_MSG, *PQMIWMS_RAW_READ_RESP_MSG; + +typedef struct _QMIWMS_MODIFY_TAG_REQ_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + UCHAR StorageType; + ULONG MemoryIndex; + UCHAR TagType; +} QMIWMS_MODIFY_TAG_REQ_MSG, *PQMIWMS_MODIFY_TAG_REQ_MSG; + +typedef struct _QMIWMS_MODIFY_TAG_RESP_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; +} QMIWMS_MODIFY_TAG_RESP_MSG, *PQMIWMS_MODIFY_TAG_RESP_MSG; + +typedef struct _QMIWMS_RAW_SEND_REQ_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + UCHAR SmsFormat; + USHORT SmsLength; + UCHAR SmsMessage; +} QMIWMS_RAW_SEND_REQ_MSG, *PQMIWMS_RAW_SEND_REQ_MSG; + +typedef struct _RAW_SEND_CAUSE_CODE +{ + UCHAR TLVType; + USHORT TLVLength; + USHORT CauseCode; +} RAW_SEND_CAUSE_CODE, *PRAW_SEND_CAUSE_CODE; + + +typedef struct _QMIWMS_RAW_SEND_RESP_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; +} QMIWMS_RAW_SEND_RESP_MSG, *PQMIWMS_RAW_SEND_RESP_MSG; + + +typedef struct _WMS_DELETE_MESSAGE_INDEX +{ + UCHAR TLVType; + USHORT TLVLength; + ULONG MemoryIndex; +} WMS_DELETE_MESSAGE_INDEX, *PWMS_DELETE_MESSAGE_INDEX; + +typedef struct _WMS_DELETE_MESSAGE_TAG +{ + UCHAR TLVType; + USHORT TLVLength; + UCHAR MessageTag; +} WMS_DELETE_MESSAGE_TAG, *PWMS_DELETE_MESSAGE_TAG; + +typedef struct _QMIWMS_DELETE_REQ_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + UCHAR StorageType; +} QMIWMS_DELETE_REQ_MSG, *PQMIWMS_DELETE_REQ_MSG; + +typedef struct _QMIWMS_DELETE_RESP_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; +} QMIWMS_DELETE_RESP_MSG, *PQMIWMS_DELETE_RESP_MSG; + + +typedef struct _QMIWMS_GET_SMSC_ADDRESS_REQ_MSG +{ + USHORT Type; + USHORT Length; +} QMIWMS_GET_SMSC_ADDRESS_REQ_MSG, *PQMIWMS_GET_SMSC_ADDRESS_REQ_MSG; + +typedef struct _QMIWMS_SMSC_ADDRESS +{ + UCHAR TLVType; + USHORT TLVLength; + UCHAR SMSCAddressType[3]; + UCHAR SMSCAddressLength; + UCHAR SMSCAddressDigits; +} QMIWMS_SMSC_ADDRESS, *PQMIWMS_SMSC_ADDRESS; + + +typedef struct _QMIWMS_GET_SMSC_ADDRESS_RESP_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; + UCHAR SMSCAddress; +} QMIWMS_GET_SMSC_ADDRESS_RESP_MSG, *PQMIWMS_GET_SMSC_ADDRESS_RESP_MSG; + +typedef struct _QMIWMS_SET_SMSC_ADDRESS_REQ_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + UCHAR SMSCAddress; +} QMIWMS_SET_SMSC_ADDRESS_REQ_MSG, *PQMIWMS_SET_SMSC_ADDRESS_REQ_MSG; + +typedef struct _QMIWMS_SET_SMSC_ADDRESS_RESP_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; +} QMIWMS_SET_SMSC_ADDRESS_RESP_MSG, *PQMIWMS_SET_SMSC_ADDRESS_RESP_MSG; + +typedef struct _QMIWMS_SET_EVENT_REPORT_REQ_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + UCHAR ReportNewMessage; +} QMIWMS_SET_EVENT_REPORT_REQ_MSG, *PQMIWMS_SET_EVENT_REPORT_REQ_MSG; + +typedef struct _QMIWMS_SET_EVENT_REPORT_RESP_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; +} QMIWMS_SET_EVENT_REPORT_RESP_MSG, *PQMIWMS_SET_EVENT_REPORT_RESP_MSG; + +typedef struct _QMIWMS_EVENT_REPORT_IND_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + UCHAR StorageType; + ULONG StorageIndex; +} QMIWMS_EVENT_REPORT_IND_MSG, *PQMIWMS_EVENT_REPORT_IND_MSG; +#endif + +// ======================= End of WMS ============================== + +// ======================= NAS ============================== +#define QMINAS_SET_EVENT_REPORT_REQ 0x0002 +#define QMINAS_SET_EVENT_REPORT_RESP 0x0002 +#define QMINAS_EVENT_REPORT_IND 0x0002 +#define QMINAS_GET_SIGNAL_STRENGTH_REQ 0x0020 +#define QMINAS_GET_SIGNAL_STRENGTH_RESP 0x0020 +#define QMINAS_PERFORM_NETWORK_SCAN_REQ 0x0021 +#define QMINAS_PERFORM_NETWORK_SCAN_RESP 0x0021 +#define QMINAS_INITIATE_NW_REGISTER_REQ 0x0022 +#define QMINAS_INITIATE_NW_REGISTER_RESP 0x0022 +#define QMINAS_INITIATE_ATTACH_REQ 0x0023 +#define QMINAS_INITIATE_ATTACH_RESP 0x0023 +#define QMINAS_GET_SERVING_SYSTEM_REQ 0x0024 +#define QMINAS_GET_SERVING_SYSTEM_RESP 0x0024 +#define QMINAS_SERVING_SYSTEM_IND 0x0024 +#define QMINAS_GET_HOME_NETWORK_REQ 0x0025 +#define QMINAS_GET_HOME_NETWORK_RESP 0x0025 +#define QMINAS_GET_PREFERRED_NETWORK_REQ 0x0026 +#define QMINAS_GET_PREFERRED_NETWORK_RESP 0x0026 +#define QMINAS_SET_PREFERRED_NETWORK_REQ 0x0027 +#define QMINAS_SET_PREFERRED_NETWORK_RESP 0x0027 +#define QMINAS_GET_FORBIDDEN_NETWORK_REQ 0x0028 +#define QMINAS_GET_FORBIDDEN_NETWORK_RESP 0x0028 +#define QMINAS_SET_FORBIDDEN_NETWORK_REQ 0x0029 +#define QMINAS_SET_FORBIDDEN_NETWORK_RESP 0x0029 +#define QMINAS_SET_TECHNOLOGY_PREF_REQ 0x002A +#define QMINAS_SET_TECHNOLOGY_PREF_RESP 0x002A +#define QMINAS_GET_RF_BAND_INFO_REQ 0x0031 +#define QMINAS_GET_RF_BAND_INFO_RESP 0x0031 +#define QMINAS_GET_PLMN_NAME_REQ 0x0044 +#define QMINAS_GET_PLMN_NAME_RESP 0x0044 +#define FIBO_PACKET_TRANSFER_START_IND 0X100 +#define FIBO_PACKET_TRANSFER_END_IND 0X101 +#define QMINAS_GET_SYS_INFO_REQ 0x004D +#define QMINAS_GET_SYS_INFO_RESP 0x004D +#define QMINAS_SYS_INFO_IND 0x004D + +typedef struct _QMINAS_GET_HOME_NETWORK_REQ_MSG { + USHORT Type; // QMUX type 0x0003 + USHORT Length; +} __attribute__((packed)) QMINAS_GET_HOME_NETWORK_REQ_MSG, + *PQMINAS_GET_HOME_NETWORK_REQ_MSG; + +typedef struct _HOME_NETWORK_SYSTEMID { + UCHAR TLVType; + USHORT TLVLength; + USHORT SystemID; + USHORT NetworkID; +} __attribute__((packed)) HOME_NETWORK_SYSTEMID, *PHOME_NETWORK_SYSTEMID; + +typedef struct _HOME_NETWORK { + UCHAR TLVType; + USHORT TLVLength; + USHORT MobileCountryCode; + USHORT MobileNetworkCode; + UCHAR NetworkDesclen; + UCHAR NetworkDesc; +} __attribute__((packed)) HOME_NETWORK, *PHOME_NETWORK; + +#if 0 +typedef struct _HOME_NETWORK_EXT +{ + UCHAR TLVType; + USHORT TLVLength; + USHORT MobileCountryCode; + USHORT MobileNetworkCode; + UCHAR NetworkDescDisp; + UCHAR NetworkDescEncoding; + UCHAR NetworkDesclen; + UCHAR NetworkDesc; +} HOME_NETWORK_EXT, *PHOME_NETWORK_EXT; + +typedef struct _QMINAS_GET_HOME_NETWORK_RESP_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; +} QMINAS_GET_HOME_NETWORK_RESP_MSG, *PQMINAS_GET_HOME_NETWORK_RESP_MSG; + +typedef struct _QMINAS_GET_PREFERRED_NETWORK_REQ_MSG +{ + USHORT Type; // QMUX type 0x0003 + USHORT Length; +} QMINAS_GET_PREFERRED_NETWORK_REQ_MSG, *PQMINAS_GET_PREFERRED_NETWORK_REQ_MSG; + + +typedef struct _PREFERRED_NETWORK +{ + USHORT MobileCountryCode; + USHORT MobileNetworkCode; + USHORT RadioAccess; +} PREFERRED_NETWORK, *PPREFERRED_NETWORK; + +typedef struct _QMINAS_GET_PREFERRED_NETWORK_RESP_MSG +{ + USHORT Type; // QMUX type 0x0003 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT + UCHAR TLV2Type; // 0x01 - required parameter + USHORT TLV2Length; // length of the mfr string + USHORT NumPreferredNetwork; +} QMINAS_GET_PREFERRED_NETWORK_RESP_MSG, *PQMINAS_GET_PREFERRED_NETWORK_RESP_MSG; + +typedef struct _QMINAS_GET_FORBIDDEN_NETWORK_REQ_MSG +{ + USHORT Type; // QMUX type 0x0003 + USHORT Length; +} QMINAS_GET_FORBIDDEN_NETWORK_REQ_MSG, *PQMINAS_GET_FORBIDDEN_NETWORK_REQ_MSG; + +typedef struct _FORBIDDEN_NETWORK +{ + USHORT MobileCountryCode; + USHORT MobileNetworkCode; +} FORBIDDEN_NETWORK, *PFORBIDDEN_NETWORK; + +typedef struct _QMINAS_GET_FORBIDDEN_NETWORK_RESP_MSG +{ + USHORT Type; // QMUX type 0x0003 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT + UCHAR TLV2Type; // 0x01 - required parameter + USHORT TLV2Length; // length of the mfr string + USHORT NumForbiddenNetwork; +} QMINAS_GET_FORBIDDEN_NETWORK_RESP_MSG, *PQMINAS_GET_FORBIDDEN_NETWORK_RESP_MSG; + +typedef struct _QMINAS_GET_SERVING_SYSTEM_REQ_MSG +{ + USHORT Type; // QMUX type 0x0003 + USHORT Length; +} QMINAS_GET_SERVING_SYSTEM_REQ_MSG, *PQMINAS_GET_SERVING_SYSTEM_REQ_MSG; + +typedef struct _QMINAS_ROAMING_INDICATOR_MSG +{ + UCHAR TLVType; // 0x01 - required parameter + USHORT TLVLength; // length of the mfr string + UCHAR RoamingIndicator; +} QMINAS_ROAMING_INDICATOR_MSG, *PQMINAS_ROAMING_INDICATOR_MSG; +#endif + +typedef struct _QMINAS_DATA_CAP { + UCHAR TLVType; // 0x01 - required parameter + USHORT TLVLength; // length of the mfr string + UCHAR DataCapListLen; + UCHAR DataCap; +} __attribute__((packed)) QMINAS_DATA_CAP, *PQMINAS_DATA_CAP; + +typedef struct _QMINAS_CURRENT_PLMN_MSG { + UCHAR TLVType; // 0x01 - required parameter + USHORT TLVLength; // length of the mfr string + USHORT MobileCountryCode; + USHORT MobileNetworkCode; + UCHAR NetworkDesclen; + UCHAR NetworkDesc; +} __attribute__((packed)) QMINAS_CURRENT_PLMN_MSG, *PQMINAS_CURRENT_PLMN_MSG; + +typedef struct _QMINAS_GET_SERVING_SYSTEM_RESP_MSG { + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; +} __attribute__((packed)) QMINAS_GET_SERVING_SYSTEM_RESP_MSG, + *PQMINAS_GET_SERVING_SYSTEM_RESP_MSG; + +typedef struct _SERVING_SYSTEM { + UCHAR TLVType; + USHORT TLVLength; + UCHAR RegistrationState; + UCHAR CSAttachedState; + UCHAR PSAttachedState; + UCHAR RegistredNetwork; + UCHAR InUseRadioIF; + UCHAR RadioIF; +} __attribute__((packed)) SERVING_SYSTEM, *PSERVING_SYSTEM; + +typedef struct _QMINAS_GET_SYS_INFO_RESP_MSG { + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; +} __attribute__((packed)) QMINAS_GET_SYS_INFO_RESP_MSG, + *PQMINAS_GET_SYS_INFO_RESP_MSG; + +typedef struct _QMINAS_SYS_INFO_IND_MSG { + USHORT Type; + USHORT Length; +} __attribute__((packed)) QMINAS_SYS_INFO_IND_MSG, *PQMINAS_SYS_INFO_IND_MSG; + +typedef struct _SERVICE_STATUS_INFO { + UCHAR TLVType; + USHORT TLVLength; + UCHAR SrvStatus; + UCHAR true_srv_status; + UCHAR IsPrefDataPath; +} __attribute__((packed)) SERVICE_STATUS_INFO, *PSERVICE_STATUS_INFO; + +typedef struct _CDMA_SYSTEM_INFO { + UCHAR TLVType; + USHORT TLVLength; + UCHAR SrvDomainValid; + UCHAR SrvDomain; + UCHAR SrvCapabilityValid; + UCHAR SrvCapability; + UCHAR RoamStatusValid; + UCHAR RoamStatus; + UCHAR IsSysForbiddenValid; + UCHAR IsSysForbidden; + UCHAR IsSysPrlMatchValid; + UCHAR IsSysPrlMatch; + UCHAR PRevInUseValid; + UCHAR PRevInUse; + UCHAR BSPRevValid; + UCHAR BSPRev; + UCHAR CCSSupportedValid; + UCHAR CCSSupported; + UCHAR CDMASysIdValid; + USHORT SID; + USHORT NID; + UCHAR BSInfoValid; + USHORT BaseID; + ULONG BaseLAT; + ULONG BaseLONG; + UCHAR PacketZoneValid; + USHORT PacketZone; + UCHAR NetworkIdValid; + UCHAR MCC[3]; + UCHAR MNC[3]; +} __attribute__((packed)) CDMA_SYSTEM_INFO, *PCDMA_SYSTEM_INFO; + +typedef struct _HDR_SYSTEM_INFO { + UCHAR TLVType; + USHORT TLVLength; + UCHAR SrvDomainValid; + UCHAR SrvDomain; + UCHAR SrvCapabilityValid; + UCHAR SrvCapability; + UCHAR RoamStatusValid; + UCHAR RoamStatus; + UCHAR IsSysForbiddenValid; + UCHAR IsSysForbidden; + UCHAR IsSysPrlMatchValid; + UCHAR IsSysPrlMatch; + UCHAR HdrPersonalityValid; + UCHAR HdrPersonality; + UCHAR HdrActiveProtValid; + UCHAR HdrActiveProt; + UCHAR is856SysIdValid; + UCHAR is856SysId[16]; +} __attribute__((packed)) HDR_SYSTEM_INFO, *PHDR_SYSTEM_INFO; + +typedef struct _GSM_SYSTEM_INFO { + UCHAR TLVType; + USHORT TLVLength; + UCHAR SrvDomainValid; + UCHAR SrvDomain; + UCHAR SrvCapabilityValid; + UCHAR SrvCapability; + UCHAR RoamStatusValid; + UCHAR RoamStatus; + UCHAR IsSysForbiddenValid; + UCHAR IsSysForbidden; + UCHAR LacValid; + USHORT Lac; + UCHAR CellIdValid; + ULONG CellId; + UCHAR RegRejectInfoValid; + UCHAR RejectSrvDomain; + UCHAR RejCause; + UCHAR NetworkIdValid; + UCHAR MCC[3]; + UCHAR MNC[3]; + UCHAR EgprsSuppValid; + UCHAR EgprsSupp; + UCHAR DtmSuppValid; + UCHAR DtmSupp; +} __attribute__((packed)) GSM_SYSTEM_INFO, *PGSM_SYSTEM_INFO; + +typedef struct _WCDMA_SYSTEM_INFO { + UCHAR TLVType; + USHORT TLVLength; + UCHAR SrvDomainValid; + UCHAR SrvDomain; + UCHAR SrvCapabilityValid; + UCHAR SrvCapability; + UCHAR RoamStatusValid; + UCHAR RoamStatus; + UCHAR IsSysForbiddenValid; + UCHAR IsSysForbidden; + UCHAR LacValid; + USHORT Lac; + UCHAR CellIdValid; + ULONG CellId; + UCHAR RegRejectInfoValid; + UCHAR RejectSrvDomain; + UCHAR RejCause; + UCHAR NetworkIdValid; + UCHAR MCC[3]; + UCHAR MNC[3]; + UCHAR HsCallStatusValid; + UCHAR HsCallStatus; + UCHAR HsIndValid; + UCHAR HsInd; + UCHAR PscValid; + UCHAR Psc; +} __attribute__((packed)) WCDMA_SYSTEM_INFO, *PWCDMA_SYSTEM_INFO; + +typedef struct _LTE_SYSTEM_INFO { + UCHAR TLVType; + USHORT TLVLength; + UCHAR SrvDomainValid; + UCHAR SrvDomain; + UCHAR SrvCapabilityValid; + UCHAR SrvCapability; + UCHAR RoamStatusValid; + UCHAR RoamStatus; + UCHAR IsSysForbiddenValid; + UCHAR IsSysForbidden; + UCHAR LacValid; + USHORT Lac; + UCHAR CellIdValid; + ULONG CellId; + UCHAR RegRejectInfoValid; + UCHAR RejectSrvDomain; + UCHAR RejCause; + UCHAR NetworkIdValid; + UCHAR MCC[3]; + UCHAR MNC[3]; + UCHAR TacValid; + USHORT Tac; +} __attribute__((packed)) LTE_SYSTEM_INFO, *PLTE_SYSTEM_INFO; +//begin modified by zhangkaibo add 5G network detect feature on x55 platform. 20200605 +typedef struct _NR5G_SYSTEM_INFO { + UCHAR TLVType; + USHORT TLVLength; + UCHAR SrvDomainValid; + UCHAR SrvDomain; + UCHAR SrvCapabilityValid; + UCHAR SrvCapability; + UCHAR RoamStatusValid; + UCHAR RoamStatus; + UCHAR IsSysForbiddenValid; + UCHAR IsSysForbidden; + UCHAR LacValid; + USHORT Lac; + UCHAR CellIdValid; + ULONG CellId; + UCHAR RegRejectInfoValid; + UCHAR RejectSrvDomain; + UCHAR RejCause; + UCHAR NetworkIdValid; + UCHAR MCC[3]; + UCHAR MNC[3]; + UCHAR TacValid; + USHORT Tac; +} __attribute__((packed)) NR5G_SYSTEM_INFO, *PNR5G_SYSTEM_INFO; + +//end modified by zhangkaibo add 5G network detect feature on x55 platform. 20200605 +typedef struct _TDSCDMA_SYSTEM_INFO { + UCHAR TLVType; + USHORT TLVLength; + UCHAR SrvDomainValid; + UCHAR SrvDomain; + UCHAR SrvCapabilityValid; + UCHAR SrvCapability; + UCHAR RoamStatusValid; + UCHAR RoamStatus; + UCHAR IsSysForbiddenValid; + UCHAR IsSysForbidden; + UCHAR LacValid; + USHORT Lac; + UCHAR CellIdValid; + ULONG CellId; + UCHAR RegRejectInfoValid; + UCHAR RejectSrvDomain; + UCHAR RejCause; + UCHAR NetworkIdValid; + UCHAR MCC[3]; + UCHAR MNC[3]; + UCHAR HsCallStatusValid; + UCHAR HsCallStatus; + UCHAR HsIndValid; + UCHAR HsInd; + UCHAR CellParameterIdValid; + USHORT CellParameterId; + UCHAR CellBroadcastCapValid; + ULONG CellBroadcastCap; + UCHAR CsBarStatusValid; + ULONG CsBarStatus; + UCHAR PsBarStatusValid; + ULONG PsBarStatus; + UCHAR CipherDomainValid; + UCHAR CipherDomain; +} __attribute__((packed)) TDSCDMA_SYSTEM_INFO, *PTDSCDMA_SYSTEM_INFO; + +#if 0 +typedef struct _QMINAS_SERVING_SYSTEM_IND_MSG +{ + USHORT Type; + USHORT Length; +} QMINAS_SERVING_SYSTEM_IND_MSG, *PQMINAS_SERVING_SYSTEM_IND_MSG; + +typedef struct _QMINAS_SET_PREFERRED_NETWORK_REQ_MSG +{ + USHORT Type; // QMUX type 0x0003 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT NumPreferredNetwork; + USHORT MobileCountryCode; + USHORT MobileNetworkCode; + USHORT RadioAccess; +} QMINAS_SET_PREFERRED_NETWORK_REQ_MSG, *PQMINAS_SET_PREFERRED_NETWORK_REQ_MSG; + +typedef struct _QMINAS_SET_PREFERRED_NETWORK_RESP_MSG +{ + USHORT Type; // QMUX type 0x0003 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT +} QMINAS_SET_PREFERRED_NETWORK_RESP_MSG, *PQMINAS_SET_PREFERRED_NETWORK_RESP_MSG; + +typedef struct _QMINAS_SET_FORBIDDEN_NETWORK_REQ_MSG +{ + USHORT Type; // QMUX type 0x0003 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT NumForbiddenNetwork; + USHORT MobileCountryCode; + USHORT MobileNetworkCode; +} QMINAS_SET_FORBIDDEN_NETWORK_REQ_MSG, *PQMINAS_SET_FORBIDDEN_NETWORK_REQ_MSG; + +typedef struct _QMINAS_SET_FORBIDDEN_NETWORK_RESP_MSG +{ + USHORT Type; // QMUX type 0x0003 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT +} QMINAS_SET_FORBIDDEN_NETWORK_RESP_MSG, *PQMINAS_SET_FORBIDDEN_NETWORK_RESP_MSG; + +typedef struct _QMINAS_PERFORM_NETWORK_SCAN_REQ_MSG +{ + USHORT Type; // QMUX type 0x0003 + USHORT Length; +} QMINAS_PERFORM_NETWORK_SCAN_REQ_MSG, *PQMINAS_PERFORM_NETWORK_SCAN_REQ_MSG; + +typedef struct _VISIBLE_NETWORK +{ + USHORT MobileCountryCode; + USHORT MobileNetworkCode; + UCHAR NetworkStatus; + UCHAR NetworkDesclen; +} VISIBLE_NETWORK, *PVISIBLE_NETWORK; + +typedef struct _QMINAS_PERFORM_NETWORK_SCAN_RESP_MSG +{ + USHORT Type; // QMUX type 0x0003 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT +} QMINAS_PERFORM_NETWORK_SCAN_RESP_MSG, *PQMINAS_PERFORM_NETWORK_SCAN_RESP_MSG; + +typedef struct _QMINAS_PERFORM_NETWORK_SCAN_NETWORK_INFO +{ + UCHAR TLVType; // 0x010 - required parameter + USHORT TLVLength; // length + USHORT NumNetworkInstances; +} QMINAS_PERFORM_NETWORK_SCAN_NETWORK_INFO, *PQMINAS_PERFORM_NETWORK_SCAN_NETWORK_INFO; + +typedef struct _QMINAS_PERFORM_NETWORK_SCAN_RAT_INFO +{ + UCHAR TLVType; // 0x011 - required parameter + USHORT TLVLength; // length + USHORT NumInst; +} QMINAS_PERFORM_NETWORK_SCAN_RAT_INFO, *PQMINAS_PERFORM_NETWORK_SCAN_RAT_INFO; + +typedef struct _QMINAS_PERFORM_NETWORK_SCAN_RAT +{ + USHORT MCC; + USHORT MNC; + UCHAR RAT; +} QMINAS_PERFORM_NETWORK_SCAN_RAT, *PQMINAS_PERFORM_NETWORK_SCAN_RAT; + + +typedef struct _QMINAS_MANUAL_NW_REGISTER +{ + UCHAR TLV2Type; // 0x02 - result code + USHORT TLV2Length; // 4 + USHORT MobileCountryCode; + USHORT MobileNetworkCode; + UCHAR RadioAccess; +} QMINAS_MANUAL_NW_REGISTER, *PQMINAS_MANUAL_NW_REGISTER; + +typedef struct _QMINAS_INITIATE_NW_REGISTER_REQ_MSG +{ + USHORT Type; // QMUX type 0x0003 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + UCHAR RegisterAction; +} QMINAS_INITIATE_NW_REGISTER_REQ_MSG, *PQMINAS_INITIATE_NW_REGISTER_REQ_MSG; + +typedef struct _QMINAS_INITIATE_NW_REGISTER_RESP_MSG +{ + USHORT Type; // QMUX type 0x0003 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT +} QMINAS_INITIATE_NW_REGISTER_RESP_MSG, *PQMINAS_INITIATE_NW_REGISTER_RESP_MSG; + +typedef struct _QMINAS_SET_TECHNOLOGY_PREF_REQ_MSG +{ + USHORT Type; // QMUX type 0x0003 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT TechPref; + UCHAR Duration; +} QMINAS_SET_TECHNOLOGY_PREF_REQ_MSG, *PQMINAS_SET_TECHNOLOGY_PREF_REQ_MSG; + +typedef struct _QMINAS_SET_TECHNOLOGY_PREF_RESP_MSG +{ + USHORT Type; // QMUX type 0x0003 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT +} QMINAS_SET_TECHNOLOGY_PREF_RESP_MSG, *PQMINAS_SET_TECHNOLOGY_PREF_RESP_MSG; + +typedef struct _QMINAS_GET_SIGNAL_STRENGTH_REQ_MSG +{ + USHORT Type; // QMUX type 0x0003 + USHORT Length; +} QMINAS_GET_SIGNAL_STRENGTH_REQ_MSG, *PQMINAS_GET_SIGNAL_STRENGTH_REQ_MSG; + +typedef struct _QMINAS_SIGNAL_STRENGTH +{ + CHAR SigStrength; + UCHAR RadioIf; +} QMINAS_SIGNAL_STRENGTH, *PQMINAS_SIGNAL_STRENGTH; + +typedef struct _QMINAS_SIGNAL_STRENGTH_LIST +{ + UCHAR TLV3Type; + USHORT TLV3Length; + USHORT NumInstance; +} QMINAS_SIGNAL_STRENGTH_LIST, *PQMINAS_SIGNAL_STRENGTH_LIST; + + +typedef struct _QMINAS_GET_SIGNAL_STRENGTH_RESP_MSG +{ + USHORT Type; // QMUX type 0x0003 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT + UCHAR TLV2Type; + USHORT TLV2Length; + CHAR SignalStrength; + UCHAR RadioIf; +} QMINAS_GET_SIGNAL_STRENGTH_RESP_MSG, *PQMINAS_GET_SIGNAL_STRENGTH_RESP_MSG; + + +typedef struct _QMINAS_SET_EVENT_REPORT_REQ_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + UCHAR ReportSigStrength; + UCHAR NumTresholds; + CHAR TresholdList[2]; +} QMINAS_SET_EVENT_REPORT_REQ_MSG, *PQMINAS_SET_EVENT_REPORT_REQ_MSG; + +typedef struct _QMINAS_SET_EVENT_REPORT_RESP_MSG +{ + USHORT Type; // QMUX type 0x0003 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT +} QMINAS_SET_EVENT_REPORT_RESP_MSG, *PQMINAS_SET_EVENT_REPORT_RESP_MSG; + +typedef struct _QMINAS_SIGNAL_STRENGTH_TLV +{ + UCHAR TLVType; + USHORT TLVLength; + CHAR SigStrength; + UCHAR RadioIf; +} QMINAS_SIGNAL_STRENGTH_TLV, *PQMINAS_SIGNAL_STRENGTH_TLV; + +typedef struct _QMINAS_REJECT_CAUSE_TLV +{ + UCHAR TLVType; + USHORT TLVLength; + UCHAR ServiceDomain; + USHORT RejectCause; +} QMINAS_REJECT_CAUSE_TLV, *PQMINAS_REJECT_CAUSE_TLV; + +typedef struct _QMINAS_EVENT_REPORT_IND_MSG +{ + USHORT Type; + USHORT Length; +} QMINAS_EVENT_REPORT_IND_MSG, *PQMINAS_EVENT_REPORT_IND_MSG; + +typedef struct _QMINAS_GET_RF_BAND_INFO_REQ_MSG +{ + USHORT Type; + USHORT Length; +} QMINAS_GET_RF_BAND_INFO_REQ_MSG, *PQMINAS_GET_RF_BAND_INFO_REQ_MSG; + +typedef struct _QMINASRF_BAND_INFO +{ + UCHAR RadioIf; + USHORT ActiveBand; + USHORT ActiveChannel; +} QMINASRF_BAND_INFO, *PQMINASRF_BAND_INFO; + +typedef struct _QMINAS_GET_RF_BAND_INFO_RESP_MSG +{ + USHORT Type; // QMUX type 0x0003 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT + UCHAR TLV2Type; + USHORT TLV2Length; + UCHAR NumInstances; +} QMINAS_GET_RF_BAND_INFO_RESP_MSG, *PQMINAS_GET_RF_BAND_INFO_RESP_MSG; + + +typedef struct _QMINAS_GET_PLMN_NAME_REQ_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT MCC; + USHORT MNC; +} QMINAS_GET_PLMN_NAME_REQ_MSG, *PQMINAS_GET_PLMN_NAME_REQ_MSG; + +typedef struct _QMINAS_GET_PLMN_NAME_RESP_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT +} QMINAS_GET_PLMN_NAME_RESP_MSG, *PQMINAS_GET_PLMN_NAME_RESP_MSG; + +typedef struct _QMINAS_GET_PLMN_NAME_SPN +{ + UCHAR TLVType; + USHORT TLVLength; + UCHAR SPN_Enc; + UCHAR SPN_Len; +} QMINAS_GET_PLMN_NAME_SPN, *PQMINAS_GET_PLMN_NAME_SPN; + +typedef struct _QMINAS_GET_PLMN_NAME_PLMN +{ + UCHAR PLMN_Enc; + UCHAR PLMN_Ci; + UCHAR PLMN_SpareBits; + UCHAR PLMN_Len; +} QMINAS_GET_PLMN_NAME_PLMN, *PQMINAS_GET_PLMN_NAME_PLMN; + +typedef struct _QMINAS_INITIATE_ATTACH_REQ_MSG +{ + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + UCHAR PsAttachAction; +} QMINAS_INITIATE_ATTACH_REQ_MSG, *PQMINAS_INITIATE_ATTACH_REQ_MSG; + +typedef struct _QMINAS_INITIATE_ATTACH_RESP_MSG +{ + USHORT Type; // QMUX type 0x0003 + USHORT Length; + UCHAR TLVType; // 0x02 - result code + USHORT TLVLength; // 4 + USHORT QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + USHORT QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT +} QMINAS_INITIATE_ATTACH_RESP_MSG, *PQMINAS_INITIATE_ATTACH_RESP_MSG; +#endif +// ======================= End of NAS ============================== + +// ======================= UIM ============================== +#define QMIUIM_READ_TRANSPARENT_REQ 0x0020 +#define QMIUIM_READ_TRANSPARENT_RESP 0x0020 +#define QMIUIM_READ_TRANSPARENT_IND 0x0020 +#define QMIUIM_READ_RECORD_REQ 0x0021 +#define QMIUIM_READ_RECORD_RESP 0x0021 +#define QMIUIM_READ_RECORD_IND 0x0021 +#define QMIUIM_WRITE_TRANSPARENT_REQ 0x0022 +#define QMIUIM_WRITE_TRANSPARENT_RESP 0x0022 +#define QMIUIM_WRITE_TRANSPARENT_IND 0x0022 +#define QMIUIM_WRITE_RECORD_REQ 0x0023 +#define QMIUIM_WRITE_RECORD_RESP 0x0023 +#define QMIUIM_WRITE_RECORD_IND 0x0023 +#define QMIUIM_SET_PIN_PROTECTION_REQ 0x0025 +#define QMIUIM_SET_PIN_PROTECTION_RESP 0x0025 +#define QMIUIM_SET_PIN_PROTECTION_IND 0x0025 +#define QMIUIM_VERIFY_PIN_REQ 0x0026 +#define QMIUIM_VERIFY_PIN_RESP 0x0026 +#define QMIUIM_VERIFY_PIN_IND 0x0026 +#define QMIUIM_UNBLOCK_PIN_REQ 0x0027 +#define QMIUIM_UNBLOCK_PIN_RESP 0x0027 +#define QMIUIM_UNBLOCK_PIN_IND 0x0027 +#define QMIUIM_CHANGE_PIN_REQ 0x0028 +#define QMIUIM_CHANGE_PIN_RESP 0x0028 +#define QMIUIM_CHANGE_PIN_IND 0x0028 +#define QMIUIM_DEPERSONALIZATION_REQ 0x0029 +#define QMIUIM_DEPERSONALIZATION_RESP 0x0029 +#define QMIUIM_EVENT_REG_REQ 0x002E +#define QMIUIM_EVENT_REG_RESP 0x002E +#define QMIUIM_GET_CARD_STATUS_REQ 0x002F +#define QMIUIM_GET_CARD_STATUS_RESP 0x002F +#define QMIUIM_STATUS_CHANGE_IND 0x0032 + +typedef struct _QMIUIM_GET_CARD_STATUS_RESP_MSG { + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; +} __attribute__((packed)) QMIUIM_GET_CARD_STATUS_RESP_MSG, + *PQMIUIM_GET_CARD_STATUS_RESP_MSG; + +typedef struct _QMIUIM_PIN_STATE { + UCHAR UnivPIN; + UCHAR PIN1State; + UCHAR PIN1Retries; + UCHAR PUK1Retries; + UCHAR PIN2State; + UCHAR PIN2Retries; + UCHAR PUK2Retries; +} __attribute__((packed)) QMIUIM_PIN_STATE, *PQMIUIM_PIN_STATE; + +typedef struct _QMIUIM_APP_STATUS { + UCHAR AppType; + UCHAR AppState; + UCHAR PersoState; + UCHAR PersoFeature; + UCHAR PersoRetries; + UCHAR PersoUnblockRetries; + UCHAR AIDLength; + UCHAR AIDValue[16]; + QMIUIM_PIN_STATE PinState; +} __attribute__((packed)) QMIUIM_APP_STATUS, *PQMIUIM_APP_STATUS; + +//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817 +typedef struct _instance{ + UCHAR CardState; + UCHAR UPINState; + UCHAR UPINRetries; + UCHAR UPUKRetries; + UCHAR ErrorCode; + UCHAR NumApp; +}Instance; + +typedef struct _QMIUIM_CARD_STATUS { + UCHAR TLVType; + USHORT TLVLength; + USHORT IndexGWPri; + USHORT Index1XPri; + USHORT IndexGWSec; + USHORT Index1XSec; + UCHAR NumSlot; +/* + UCHAR CardState; + UCHAR UPINState; + UCHAR UPINRetries; + UCHAR UPUKRetries; + UCHAR ErrorCode; + UCHAR NumApp; + QMIUIM_APP_STATUS AppStatus[8]; +*/ +}__attribute__((packed)) QMIUIM_CARD_STATUS, *PQMIUIM_CARD_STATUS; +//2021-03-24 willa.liu@fibocom.com changed end for support mantis 0071817 + +typedef struct _QMIUIM_VERIFY_PIN_REQ_MSG { + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + UCHAR Session_Type; + UCHAR Aid_Len; + UCHAR TLV2Type; + USHORT TLV2Length; + UCHAR PINID; + UCHAR PINLen; + UCHAR PINValue; +} __attribute__((packed)) QMIUIM_VERIFY_PIN_REQ_MSG, + *PQMIUIM_VERIFY_PIN_REQ_MSG; + +typedef struct _QMIUIM_VERIFY_PIN_RESP_MSG { + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; + UCHAR TLV2Type; + USHORT TLV2Length; + UCHAR PINVerifyRetriesLeft; + UCHAR PINUnblockRetriesLeft; +} __attribute__((packed)) QMIUIM_VERIFY_PIN_RESP_MSG, + *PQMIUIM_VERIFY_PIN_RESP_MSG; + +//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817 +typedef struct _QMIUIM_BIND_PIN_REQ_MSG { + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + uint8_t Value; +} __attribute__((packed)) QMIUIM_BIND_PIN_REQ_MSG, *PQMIUIM_BIND_PIN_REQ_MSG; + +typedef struct _QMIUIM_BIND_PIN_REQ_MSG_4 { + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + UINT Value; +} __attribute__((packed)) QMIUIM_BIND_PIN_REQ_MSG_4; +//2021-03-24 willa.liu@fibocom.com changed end for support mantis 0071817 + +typedef struct _QMIUIM_READ_TRANSPARENT_REQ_MSG { + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + UCHAR Session_Type; + UCHAR Aid_Len; + UCHAR TLV2Type; + USHORT TLV2Length; + USHORT file_id; + UCHAR path_len; + UCHAR path[]; +} __attribute__((packed)) QMIUIM_READ_TRANSPARENT_REQ_MSG, + *PQMIUIM_READ_TRANSPARENT_REQ_MSG; + +typedef struct _READ_TRANSPARENT_TLV { + UCHAR TLVType; + USHORT TLVLength; + USHORT Offset; + USHORT Length; +} __attribute__((packed)) READ_TRANSPARENT_TLV, *PREAD_TRANSPARENT_TLV; + +typedef struct _QMIUIM_CONTENT { + UCHAR TLVType; + USHORT TLVLength; + USHORT content_len; + UCHAR content[]; +} __attribute__((packed)) QMIUIM_CONTENT, *PQMIUIM_CONTENT; + +typedef struct _QMIUIM_READ_TRANSPARENT_RESP_MSG { + USHORT Type; + USHORT Length; + UCHAR TLVType; + USHORT TLVLength; + USHORT QMUXResult; + USHORT QMUXError; +} __attribute__((packed)) QMIUIM_READ_TRANSPARENT_RESP_MSG, + *PQMIUIM_READ_TRANSPARENT_RESP_MSG; + +typedef struct _QMUX_MSG { + QCQMUX_HDR QMUXHdr; + union { + // Message Header + QCQMUX_MSG_HDR QMUXMsgHdr; + QCQMUX_MSG_HDR_RESP QMUXMsgHdrResp; + + // QMIWDS Message +#if 0 + QMIWDS_GET_PKT_SRVC_STATUS_REQ_MSG PacketServiceStatusReq; + QMIWDS_GET_PKT_SRVC_STATUS_RESP_MSG PacketServiceStatusRsp; + QMIWDS_GET_PKT_SRVC_STATUS_IND_MSG PacketServiceStatusInd; + QMIWDS_EVENT_REPORT_IND_MSG EventReportInd; + QMIWDS_GET_CURRENT_CHANNEL_RATE_REQ_MSG GetCurrChannelRateReq; + QMIWDS_GET_CURRENT_CHANNEL_RATE_RESP_MSG GetCurrChannelRateRsp; + QMIWDS_GET_PKT_STATISTICS_REQ_MSG GetPktStatsReq; + QMIWDS_GET_PKT_STATISTICS_RESP_MSG GetPktStatsRsp; + QMIWDS_SET_EVENT_REPORT_REQ_MSG EventReportReq; + QMIWDS_SET_EVENT_REPORT_RESP_MSG EventReportRsp; +#endif + //#ifdef QC_IP_MODE + QMIWDS_GET_RUNTIME_SETTINGS_REQ_MSG GetRuntimeSettingsReq; + QMIWDS_GET_RUNTIME_SETTINGS_RESP_MSG GetRuntimeSettingsRsp; + //#endif // QC_IP_MODE + QMIWDS_SET_CLIENT_IP_FAMILY_PREF_REQ_MSG SetClientIpFamilyPrefReq; + QMIWDS_SET_CLIENT_IP_FAMILY_PREF_RESP_MSG SetClientIpFamilyPrefResp; + QMIWDS_SET_AUTO_CONNECT_REQ_MSG SetAutoConnectReq; +#if 0 + QMIWDS_GET_MIP_MODE_REQ_MSG GetMipModeReq; + QMIWDS_GET_MIP_MODE_RESP_MSG GetMipModeResp; +#endif + QMIWDS_START_NETWORK_INTERFACE_REQ_MSG StartNwInterfaceReq; + QMIWDS_START_NETWORK_INTERFACE_RESP_MSG StartNwInterfaceResp; + QMIWDS_STOP_NETWORK_INTERFACE_REQ_MSG StopNwInterfaceReq; + QMIWDS_STOP_NETWORK_INTERFACE_RESP_MSG StopNwInterfaceResp; + QMIWDS_GET_DEFAULT_SETTINGS_REQ_MSG GetDefaultSettingsReq; + QMIWDS_GET_DEFAULT_SETTINGS_RESP_MSG GetDefaultSettingsResp; +//begin modified by zhangkaibo add create profile qmi. mantis 0049137,0048741 20200610 + QMIWDS_CREATE_PROFILE_SETTINGS_REQ_MSG CreateProfileSettingsReq; + QMIWDS_CREATE_PROFILE_SETTINGS_RESP_MSG CreateProfileSettingsResp; +//end modified by zhangkaibo add create profile qmi. mantis 0049137,0048741 20200610 + QMIWDS_MODIFY_PROFILE_SETTINGS_REQ_MSG ModifyProfileSettingsReq; + QMIWDS_MODIFY_PROFILE_SETTINGS_RESP_MSG ModifyProfileSettingsResp; + QMIWDS_GET_PROFILE_SETTINGS_REQ_MSG GetProfileSettingsReq; +#if 0 + QMIWDS_GET_DATA_BEARER_REQ_MSG GetDataBearerReq; + QMIWDS_GET_DATA_BEARER_RESP_MSG GetDataBearerResp; + QMIWDS_DUN_CALL_INFO_REQ_MSG DunCallInfoReq; + QMIWDS_DUN_CALL_INFO_RESP_MSG DunCallInfoResp; +#endif + QMIWDS_BIND_MUX_DATA_PORT_REQ_MSG BindMuxDataPortReq; + + // QMIDMS Messages +#if 0 + QMIDMS_GET_DEVICE_MFR_REQ_MSG GetDeviceMfrReq; + QMIDMS_GET_DEVICE_MFR_RESP_MSG GetDeviceMfrRsp; + QMIDMS_GET_DEVICE_MODEL_ID_REQ_MSG GetDeviceModeIdReq; + QMIDMS_GET_DEVICE_MODEL_ID_RESP_MSG GetDeviceModeIdRsp; + QMIDMS_GET_DEVICE_REV_ID_REQ_MSG GetDeviceRevIdReq; + QMIDMS_GET_DEVICE_REV_ID_RESP_MSG GetDeviceRevIdRsp; + QMIDMS_GET_MSISDN_REQ_MSG GetMsisdnReq; + QMIDMS_GET_MSISDN_RESP_MSG GetMsisdnRsp; + QMIDMS_GET_DEVICE_SERIAL_NUMBERS_REQ_MSG GetDeviceSerialNumReq; + QMIDMS_GET_DEVICE_SERIAL_NUMBERS_RESP_MSG GetDeviceSerialNumRsp; + QMIDMS_GET_DEVICE_CAP_REQ_MSG GetDeviceCapReq; + QMIDMS_GET_DEVICE_CAP_RESP_MSG GetDeviceCapResp; + QMIDMS_GET_BAND_CAP_REQ_MSG GetBandCapReq; + QMIDMS_GET_BAND_CAP_RESP_MSG GetBandCapRsp; + QMIDMS_GET_ACTIVATED_STATUS_REQ_MSG GetActivatedStatusReq; + QMIDMS_GET_ACTIVATED_STATUS_RESP_MSG GetActivatedStatusResp; + QMIDMS_GET_OPERATING_MODE_REQ_MSG GetOperatingModeReq; + QMIDMS_GET_OPERATING_MODE_RESP_MSG GetOperatingModeResp; +#endif + QMIDMS_SET_OPERATING_MODE_REQ_MSG SetOperatingModeReq; + QMIDMS_SET_OPERATING_MODE_RESP_MSG SetOperatingModeResp; +#if 0 + QMIDMS_UIM_GET_ICCID_REQ_MSG GetICCIDReq; + QMIDMS_UIM_GET_ICCID_RESP_MSG GetICCIDResp; + QMIDMS_ACTIVATE_AUTOMATIC_REQ_MSG ActivateAutomaticReq; + QMIDMS_ACTIVATE_AUTOMATIC_RESP_MSG ActivateAutomaticResp; + QMIDMS_ACTIVATE_MANUAL_REQ_MSG ActivateManualReq; + QMIDMS_ACTIVATE_MANUAL_RESP_MSG ActivateManualResp; +#endif + QMIDMS_UIM_GET_PIN_STATUS_REQ_MSG UIMGetPinStatusReq; + QMIDMS_UIM_GET_PIN_STATUS_RESP_MSG UIMGetPinStatusResp; + QMIDMS_UIM_VERIFY_PIN_REQ_MSG UIMVerifyPinReq; + QMIDMS_UIM_VERIFY_PIN_RESP_MSG UIMVerifyPinResp; +#if 0 + QMIDMS_UIM_SET_PIN_PROTECTION_REQ_MSG UIMSetPinProtectionReq; + QMIDMS_UIM_SET_PIN_PROTECTION_RESP_MSG UIMSetPinProtectionResp; + QMIDMS_UIM_CHANGE_PIN_REQ_MSG UIMChangePinReq; + QMIDMS_UIM_CHANGE_PIN_RESP_MSG UIMChangePinResp; + QMIDMS_UIM_UNBLOCK_PIN_REQ_MSG UIMUnblockPinReq; + QMIDMS_UIM_UNBLOCK_PIN_RESP_MSG UIMUnblockPinResp; + QMIDMS_SET_EVENT_REPORT_REQ_MSG DmsSetEventReportReq; + QMIDMS_SET_EVENT_REPORT_RESP_MSG DmsSetEventReportResp; + QMIDMS_EVENT_REPORT_IND_MSG DmsEventReportInd; +#endif + QMIDMS_UIM_GET_STATE_REQ_MSG UIMGetStateReq; + QMIDMS_UIM_GET_STATE_RESP_MSG UIMGetStateResp; + QMIDMS_UIM_GET_IMSI_REQ_MSG UIMGetIMSIReq; + QMIDMS_UIM_GET_IMSI_RESP_MSG UIMGetIMSIResp; +#if 0 + QMIDMS_UIM_GET_CK_STATUS_REQ_MSG UIMGetCkStatusReq; + QMIDMS_UIM_GET_CK_STATUS_RESP_MSG UIMGetCkStatusResp; + QMIDMS_UIM_SET_CK_PROTECTION_REQ_MSG UIMSetCkProtectionReq; + QMIDMS_UIM_SET_CK_PROTECTION_RESP_MSG UIMSetCkProtectionResp; + QMIDMS_UIM_UNBLOCK_CK_REQ_MSG UIMUnblockCkReq; + QMIDMS_UIM_UNBLOCK_CK_RESP_MSG UIMUnblockCkResp; +#endif + + // QMIQOS Messages +#if 0 + QMI_QOS_SET_EVENT_REPORT_REQ_MSG QosSetEventReportReq; + QMI_QOS_SET_EVENT_REPORT_RESP_MSG QosSetEventReportRsp; + QMI_QOS_EVENT_REPORT_IND_MSG QosEventReportInd; +#endif + + // QMIWMS Messages +#if 0 + QMIWMS_GET_MESSAGE_PROTOCOL_REQ_MSG GetMessageProtocolReq; + QMIWMS_GET_MESSAGE_PROTOCOL_RESP_MSG GetMessageProtocolResp; + QMIWMS_GET_SMSC_ADDRESS_REQ_MSG GetSMSCAddressReq; + QMIWMS_GET_SMSC_ADDRESS_RESP_MSG GetSMSCAddressResp; + QMIWMS_SET_SMSC_ADDRESS_REQ_MSG SetSMSCAddressReq; + QMIWMS_SET_SMSC_ADDRESS_RESP_MSG SetSMSCAddressResp; + QMIWMS_GET_STORE_MAX_SIZE_REQ_MSG GetStoreMaxSizeReq; + QMIWMS_GET_STORE_MAX_SIZE_RESP_MSG GetStoreMaxSizeResp; + QMIWMS_LIST_MESSAGES_REQ_MSG ListMessagesReq; + QMIWMS_LIST_MESSAGES_RESP_MSG ListMessagesResp; + QMIWMS_RAW_READ_REQ_MSG RawReadMessagesReq; + QMIWMS_RAW_READ_RESP_MSG RawReadMessagesResp; + QMIWMS_SET_EVENT_REPORT_REQ_MSG WmsSetEventReportReq; + QMIWMS_SET_EVENT_REPORT_RESP_MSG WmsSetEventReportResp; + QMIWMS_EVENT_REPORT_IND_MSG WmsEventReportInd; + QMIWMS_DELETE_REQ_MSG WmsDeleteReq; + QMIWMS_DELETE_RESP_MSG WmsDeleteResp; + QMIWMS_RAW_SEND_REQ_MSG RawSendMessagesReq; + QMIWMS_RAW_SEND_RESP_MSG RawSendMessagesResp; + QMIWMS_MODIFY_TAG_REQ_MSG WmsModifyTagReq; + QMIWMS_MODIFY_TAG_RESP_MSG WmsModifyTagResp; +#endif + + // QMINAS Messages +#if 0 + QMINAS_GET_HOME_NETWORK_REQ_MSG GetHomeNetworkReq; + QMINAS_GET_HOME_NETWORK_RESP_MSG GetHomeNetworkResp; + QMINAS_GET_PREFERRED_NETWORK_REQ_MSG GetPreferredNetworkReq; + QMINAS_GET_PREFERRED_NETWORK_RESP_MSG GetPreferredNetworkResp; + QMINAS_GET_FORBIDDEN_NETWORK_REQ_MSG GetForbiddenNetworkReq; + QMINAS_GET_FORBIDDEN_NETWORK_RESP_MSG GetForbiddenNetworkResp; + QMINAS_GET_SERVING_SYSTEM_REQ_MSG GetServingSystemReq; +#endif + QMINAS_GET_SERVING_SYSTEM_RESP_MSG GetServingSystemResp; + QMINAS_GET_SYS_INFO_RESP_MSG GetSysInfoResp; + QMINAS_SYS_INFO_IND_MSG NasSysInfoInd; +#if 0 + QMINAS_SERVING_SYSTEM_IND_MSG NasServingSystemInd; + QMINAS_SET_PREFERRED_NETWORK_REQ_MSG SetPreferredNetworkReq; + QMINAS_SET_PREFERRED_NETWORK_RESP_MSG SetPreferredNetworkResp; + QMINAS_SET_FORBIDDEN_NETWORK_REQ_MSG SetForbiddenNetworkReq; + QMINAS_SET_FORBIDDEN_NETWORK_RESP_MSG SetForbiddenNetworkResp; + QMINAS_PERFORM_NETWORK_SCAN_REQ_MSG PerformNetworkScanReq; + QMINAS_PERFORM_NETWORK_SCAN_RESP_MSG PerformNetworkScanResp; + QMINAS_INITIATE_NW_REGISTER_REQ_MSG InitiateNwRegisterReq; + QMINAS_INITIATE_NW_REGISTER_RESP_MSG InitiateNwRegisterResp; + QMINAS_SET_TECHNOLOGY_PREF_REQ_MSG SetTechnologyPrefReq; + QMINAS_SET_TECHNOLOGY_PREF_RESP_MSG SetTechnologyPrefResp; + QMINAS_GET_SIGNAL_STRENGTH_REQ_MSG GetSignalStrengthReq; + QMINAS_GET_SIGNAL_STRENGTH_RESP_MSG GetSignalStrengthResp; + QMINAS_SET_EVENT_REPORT_REQ_MSG SetEventReportReq; + QMINAS_SET_EVENT_REPORT_RESP_MSG SetEventReportResp; + QMINAS_EVENT_REPORT_IND_MSG NasEventReportInd; + QMINAS_GET_RF_BAND_INFO_REQ_MSG GetRFBandInfoReq; + QMINAS_GET_RF_BAND_INFO_RESP_MSG GetRFBandInfoResp; + QMINAS_INITIATE_ATTACH_REQ_MSG InitiateAttachReq; + QMINAS_INITIATE_ATTACH_RESP_MSG InitiateAttachResp; + QMINAS_GET_PLMN_NAME_REQ_MSG GetPLMNNameReq; + QMINAS_GET_PLMN_NAME_RESP_MSG GetPLMNNameResp; +#endif + + // QMIUIM Messages + QMIUIM_GET_CARD_STATUS_RESP_MSG UIMGetCardStatus; + QMIUIM_VERIFY_PIN_REQ_MSG UIMUIMVerifyPinReq; + QMIUIM_VERIFY_PIN_RESP_MSG UIMUIMVerifyPinResp; +//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817 + QMIUIM_BIND_PIN_REQ_MSG UIMUIMBindPinReq; + QMIUIM_BIND_PIN_REQ_MSG_4 UIMUIMBindPinReq_4; +//2021-03-24 willa.liu@fibocom.com changed end for support mantis 0071817 +#if 0 + QMIUIM_SET_PIN_PROTECTION_REQ_MSG UIMUIMSetPinProtectionReq; + QMIUIM_SET_PIN_PROTECTION_RESP_MSG UIMUIMSetPinProtectionResp; + QMIUIM_CHANGE_PIN_REQ_MSG UIMUIMChangePinReq; + QMIUIM_CHANGE_PIN_RESP_MSG UIMUIMChangePinResp; + QMIUIM_UNBLOCK_PIN_REQ_MSG UIMUIMUnblockPinReq; + QMIUIM_UNBLOCK_PIN_RESP_MSG UIMUIMUnblockPinResp; +#endif + QMIUIM_READ_TRANSPARENT_REQ_MSG UIMUIMReadTransparentReq; + QMIUIM_READ_TRANSPARENT_RESP_MSG UIMUIMReadTransparentResp; + + QMIWDS_ADMIN_SET_DATA_FORMAT_REQ_MSG SetDataFormatReq; + }; +} __attribute__((packed)) QMUX_MSG, *PQMUX_MSG; + +//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817 +#define QMI_WDS_BIND_SUBSCRIPTION_REQ_V01 0x00AF +#define QMI_WDS_BIND_SUBSCRIPTION_RESP_V01 0x00AF +#define QMI_DMS_BIND_SUBSCRIPTION_REQ_V01 0x0054 +#define QMI_DMS_BIND_SUBSCRIPTION_RESP_V01 0x0054 +#define QMI_NAS_BIND_SUBSCRIPTION_REQ_V01 0x0045 +#define QMI_NAS_BIND_SUBSCRIPTION_RESP_V01 0x0045 +#define QMI_QOS_BIND_SUBSCRIPTION_REQ_V01 0x002D +#define QMI_QOS_BIND_SUBSCRIPTION_RESP_V01 0x002D +#define QMI_WMS_BIND_SUBSCRIPTION_REQ_V01 0x004C +#define QMI_WMS_BIND_SUBSCRIPTION_RESP_V01 0x004C + +typedef enum { + QMI_RESULT_TYPE_MIN_ENUM_VAL_V01 = -2147483647, /**< To force a 32 bit signed enum. Do not change or use*/ + QMI_RESULT_SUCCESS_V01 = 0, + QMI_RESULT_FAILURE_V01 = 1, + QMI_RESULT_TYPE_MAX_ENUM_VAL_V01 = 2147483647 /**< To force a 32 bit signed enum. Do not change or use*/ +}qmi_result_type_v01; + +typedef enum { + QMI_ERROR_TYPE_MIN_ENUM_VAL_V01 = -2147483647, /**< To force a 32 bit signed enum. Do not change or use*/ + QMI_ERR_NONE_V01 = 0x0000, + QMI_ERR_MALFORMED_MSG_V01 = 0x0001, + QMI_ERR_NO_MEMORY_V01 = 0x0002, + QMI_ERR_INTERNAL_V01 = 0x0003, + QMI_ERR_ABORTED_V01 = 0x0004, + QMI_ERR_CLIENT_IDS_EXHAUSTED_V01 = 0x0005, + QMI_ERR_UNABORTABLE_TRANSACTION_V01 = 0x0006, + QMI_ERR_INVALID_CLIENT_ID_V01 = 0x0007, + QMI_ERR_NO_THRESHOLDS_V01 = 0x0008, + QMI_ERR_INVALID_HANDLE_V01 = 0x0009, + QMI_ERR_INVALID_PROFILE_V01 = 0x000A, + QMI_ERR_INVALID_PINID_V01 = 0x000B, + QMI_ERR_INCORRECT_PIN_V01 = 0x000C, + QMI_ERR_NO_NETWORK_FOUND_V01 = 0x000D, + QMI_ERR_CALL_FAILED_V01 = 0x000E, + QMI_ERR_OUT_OF_CALL_V01 = 0x000F, + QMI_ERR_NOT_PROVISIONED_V01 = 0x0010, + QMI_ERR_MISSING_ARG_V01 = 0x0011, + QMI_ERR_ARG_TOO_LONG_V01 = 0x0013, + QMI_ERR_INVALID_TX_ID_V01 = 0x0016, + QMI_ERR_DEVICE_IN_USE_V01 = 0x0017, + QMI_ERR_OP_NETWORK_UNSUPPORTED_V01 = 0x0018, + QMI_ERR_OP_DEVICE_UNSUPPORTED_V01 = 0x0019, + QMI_ERR_NO_EFFECT_V01 = 0x001A, + QMI_ERR_NO_FREE_PROFILE_V01 = 0x001B, + QMI_ERR_INVALID_PDP_TYPE_V01 = 0x001C, + QMI_ERR_INVALID_TECH_PREF_V01 = 0x001D, + QMI_ERR_INVALID_PROFILE_TYPE_V01 = 0x001E, + QMI_ERR_INVALID_SERVICE_TYPE_V01 = 0x001F, + QMI_ERR_INVALID_REGISTER_ACTION_V01 = 0x0020, + QMI_ERR_INVALID_PS_ATTACH_ACTION_V01 = 0x0021, + QMI_ERR_AUTHENTICATION_FAILED_V01 = 0x0022, + QMI_ERR_PIN_BLOCKED_V01 = 0x0023, + QMI_ERR_PIN_PERM_BLOCKED_V01 = 0x0024, + QMI_ERR_SIM_NOT_INITIALIZED_V01 = 0x0025, + QMI_ERR_MAX_QOS_REQUESTS_IN_USE_V01 = 0x0026, + QMI_ERR_INCORRECT_FLOW_FILTER_V01 = 0x0027, + QMI_ERR_NETWORK_QOS_UNAWARE_V01 = 0x0028, + QMI_ERR_INVALID_ID_V01 = 0x0029, + QMI_ERR_INVALID_QOS_ID_V01 = 0x0029, + QMI_ERR_REQUESTED_NUM_UNSUPPORTED_V01 = 0x002A, + QMI_ERR_INTERFACE_NOT_FOUND_V01 = 0x002B, + QMI_ERR_FLOW_SUSPENDED_V01 = 0x002C, + QMI_ERR_INVALID_DATA_FORMAT_V01 = 0x002D, + QMI_ERR_GENERAL_V01 = 0x002E, + QMI_ERR_UNKNOWN_V01 = 0x002F, + QMI_ERR_INVALID_ARG_V01 = 0x0030, + QMI_ERR_INVALID_INDEX_V01 = 0x0031, + QMI_ERR_NO_ENTRY_V01 = 0x0032, + QMI_ERR_DEVICE_STORAGE_FULL_V01 = 0x0033, + QMI_ERR_DEVICE_NOT_READY_V01 = 0x0034, + QMI_ERR_NETWORK_NOT_READY_V01 = 0x0035, + QMI_ERR_CAUSE_CODE_V01 = 0x0036, + QMI_ERR_MESSAGE_NOT_SENT_V01 = 0x0037, + QMI_ERR_MESSAGE_DELIVERY_FAILURE_V01 = 0x0038, + QMI_ERR_INVALID_MESSAGE_ID_V01 = 0x0039, + QMI_ERR_ENCODING_V01 = 0x003A, + QMI_ERR_AUTHENTICATION_LOCK_V01 = 0x003B, + QMI_ERR_INVALID_TRANSITION_V01 = 0x003C, + QMI_ERR_NOT_A_MCAST_IFACE_V01 = 0x003D, + QMI_ERR_MAX_MCAST_REQUESTS_IN_USE_V01 = 0x003E, + QMI_ERR_INVALID_MCAST_HANDLE_V01 = 0x003F, + QMI_ERR_INVALID_IP_FAMILY_PREF_V01 = 0x0040, + QMI_ERR_SESSION_INACTIVE_V01 = 0x0041, + QMI_ERR_SESSION_INVALID_V01 = 0x0042, + QMI_ERR_SESSION_OWNERSHIP_V01 = 0x0043, + QMI_ERR_INSUFFICIENT_RESOURCES_V01 = 0x0044, + QMI_ERR_DISABLED_V01 = 0x0045, + QMI_ERR_INVALID_OPERATION_V01 = 0x0046, + QMI_ERR_INVALID_QMI_CMD_V01 = 0x0047, + QMI_ERR_TPDU_TYPE_V01 = 0x0048, + QMI_ERR_SMSC_ADDR_V01 = 0x0049, + QMI_ERR_INFO_UNAVAILABLE_V01 = 0x004A, + QMI_ERR_SEGMENT_TOO_LONG_V01 = 0x004B, + QMI_ERR_SEGMENT_ORDER_V01 = 0x004C, + QMI_ERR_BUNDLING_NOT_SUPPORTED_V01 = 0x004D, + QMI_ERR_OP_PARTIAL_FAILURE_V01 = 0x004E, + QMI_ERR_POLICY_MISMATCH_V01 = 0x004F, + QMI_ERR_SIM_FILE_NOT_FOUND_V01 = 0x0050, + QMI_ERR_EXTENDED_INTERNAL_V01 = 0x0051, + QMI_ERR_ACCESS_DENIED_V01 = 0x0052, + QMI_ERR_HARDWARE_RESTRICTED_V01 = 0x0053, + QMI_ERR_ACK_NOT_SENT_V01 = 0x0054, + QMI_ERR_INJECT_TIMEOUT_V01 = 0x0055, + QMI_ERR_INCOMPATIBLE_STATE_V01 = 0x005A, + QMI_ERR_FDN_RESTRICT_V01 = 0x005B, + QMI_ERR_SUPS_FAILURE_CAUSE_V01 = 0x005C, + QMI_ERR_NO_RADIO_V01 = 0x005D, + QMI_ERR_NOT_SUPPORTED_V01 = 0x005E, + QMI_ERR_NO_SUBSCRIPTION_V01 = 0x005F, + QMI_ERR_CARD_CALL_CONTROL_FAILED_V01 = 0x0060, + QMI_ERR_NETWORK_ABORTED_V01 = 0x0061, + QMI_ERR_MSG_BLOCKED_V01 = 0x0062, + QMI_ERR_INVALID_SESSION_TYPE_V01 = 0x0064, + QMI_ERR_INVALID_PB_TYPE_V01 = 0x0065, + QMI_ERR_NO_SIM_V01 = 0x0066, + QMI_ERR_PB_NOT_READY_V01 = 0x0067, + QMI_ERR_PIN_RESTRICTION_V01 = 0x0068, + QMI_ERR_PIN2_RESTRICTION_V01 = 0x0069, + QMI_ERR_PUK_RESTRICTION_V01 = 0x006A, + QMI_ERR_PUK2_RESTRICTION_V01 = 0x006B, + QMI_ERR_PB_ACCESS_RESTRICTED_V01 = 0x006C, + QMI_ERR_PB_DELETE_IN_PROG_V01 = 0x006D, + QMI_ERR_PB_TEXT_TOO_LONG_V01 = 0x006E, + QMI_ERR_PB_NUMBER_TOO_LONG_V01 = 0x006F, + QMI_ERR_PB_HIDDEN_KEY_RESTRICTION_V01 = 0x0070, + QMI_ERR_PB_NOT_AVAILABLE_V01 = 0x0071, + QMI_ERR_DEVICE_MEMORY_ERROR_V01 = 0x0072, + QMI_ERR_NO_PERMISSION_V01 = 0x0073, + QMI_ERR_TOO_SOON_V01 = 0x0074, + QMI_ERR_TIME_NOT_ACQUIRED_V01 = 0x0075, + QMI_ERR_OP_IN_PROGRESS_V01 = 0x0076, + QMI_ERR_EPERM_V01 = 0x101, /**< Operation not permitted */ + QMI_ERR_ENOENT_V01 = 0x102, /**< No such file or directory */ + QMI_ERR_ESRCH_V01 = 0x103, /**< No such process */ + QMI_ERR_EINTR_V01 = 0x104, /**< Interrupted system call */ + QMI_ERR_EIO_V01 = 0x105, /**< I/O error */ + QMI_ERR_ENXIO_V01 = 0x106, /**< No such device or address */ + QMI_ERR_E2BIG_V01 = 0x107, /**< Argument list too long */ + QMI_ERR_ENOEXEC_V01 = 0x108, /**< Exec format error */ + QMI_ERR_EBADF_V01 = 0x109, /**< Bad file number */ + QMI_ERR_ECHILD_V01 = 0x10A, /**< No child processes */ + QMI_ERR_EAGAIN_V01 = 0x10B, /**< Try again */ + QMI_ERR_ENOMEM_V01 = 0x10C, /**< Out of memory */ + QMI_ERR_EACCES_V01 = 0x10D, /**< Permission denied */ + QMI_ERR_EFAULT_V01 = 0x10E, /**< Bad address */ + QMI_ERR_ENOTBLK_V01 = 0x10F, /**< Block device required */ + QMI_ERR_EBUSY_V01 = 0x110, /**< Device or resource busy */ + QMI_ERR_EEXIST_V01 = 0x111, /**< File exists */ + QMI_ERR_EXDEV_V01 = 0x112, /**< Cross-device link */ + QMI_ERR_ENODEV_V01 = 0x113, /**< No such device */ + QMI_ERR_ENOTDIR_V01 = 0x114, /**< Not a directory */ + QMI_ERR_EISDIR_V01 = 0x115, /**< Is a directory */ + QMI_ERR_EINVAL_V01 = 0x116, /**< Invalid argument */ + QMI_ERR_ENFILE_V01 = 0x117, /**< File table overflow */ + QMI_ERR_EMFILE_V01 = 0x118, /**< Too many open files */ + QMI_ERR_ENOTTY_V01 = 0x119, /**< Not a typewriter */ + QMI_ERR_ETXTBSY_V01 = 0x11A, /**< Text file busy */ + QMI_ERR_EFBIG_V01 = 0x11B, /**< File too large */ + QMI_ERR_ENOSPC_V01 = 0x11C, /**< No space left on device */ + QMI_ERR_ESPIPE_V01 = 0x11D, /**< Illegal seek */ + QMI_ERR_EROFS_V01 = 0x11E, /**< Read-only file system */ + QMI_ERR_EMLINK_V01 = 0x11F, /**< Too many links */ + QMI_ERR_EPIPE_V01 = 0x120, /**< Broken pipe */ + QMI_ERR_EDOM_V01 = 0x121, /**< Math argument out of domain of func */ + QMI_ERR_ERANGE_V01 = 0x122, /**< Math result not representable */ + QMI_ERR_EDEADLK_V01 = 0x123, /**< Resource deadlock would occur */ + QMI_ERR_ENAMETOOLONG_V01 = 0x124, /**< File name too long */ + QMI_ERR_ENOLCK_V01 = 0x125, /**< No record locks available */ + QMI_ERR_ENOSYS_V01 = 0x126, /**< Function not implemented */ + QMI_ERR_ENOTEMPTY_V01 = 0x127, /**< Directory not empty */ + QMI_ERR_ELOOP_V01 = 0x128, /**< Too many symbolic links encountered */ + QMI_ERR_EWOULDBLOCK_V01 = 0x10B, /**< Operation would block */ + QMI_ERR_ENOMSG_V01 = 0x12A, /**< No message of desired type */ + QMI_ERR_EIDRM_V01 = 0x12B, /**< Identifier removed */ + QMI_ERR_ECHRNG_V01 = 0x12C, /**< Channel number out of range */ + QMI_ERR_EL2NSYNC_V01 = 0x12D, /**< Level 2 not synchronized */ + QMI_ERR_EL3HLT_V01 = 0x12E, /**< Level 3 halted */ + QMI_ERR_EL3RST_V01 = 0x12F, /**< Level 3 reset */ + QMI_ERR_ELNRNG_V01 = 0x130, /**< Link number out of range */ + QMI_ERR_EUNATCH_V01 = 0x131, /**< Protocol driver not attached */ + QMI_ERR_ENOCSI_V01 = 0x132, /**< No CSI structure available */ + QMI_ERR_EL2HLT_V01 = 0x133, /**< Level 2 halted */ + QMI_ERR_EBADE_V01 = 0x134, /**< Invalid exchange */ + QMI_ERR_EBADR_V01 = 0x135, /**< Invalid request descriptor */ + QMI_ERR_EXFULL_V01 = 0x136, /**< Exchange full */ + QMI_ERR_ENOANO_V01 = 0x137, /**< No anode */ + QMI_ERR_EBADRQC_V01 = 0x138, /**< Invalid request code */ + QMI_ERR_EBADSLT_V01 = 0x139, /**< Invalid slot */ + QMI_ERR_EDEADLOCK_V01 = 0x123, /**< Resource deadlock would occur */ + QMI_ERR_EBFONT_V01 = 0x13B, /**< Bad font file format */ + QMI_ERR_ENOSTR_V01 = 0x13C, /**< Device not a stream */ + QMI_ERR_ENODATA_V01 = 0x13D, /**< No data available */ + QMI_ERR_ETIME_V01 = 0x13E, /**< Timer expired */ + QMI_ERR_ENOSR_V01 = 0x13F, /**< Out of streams resources */ + QMI_ERR_ENONET_V01 = 0x140, /**< Machine is not on the network */ + QMI_ERR_ENOPKG_V01 = 0x141, /**< Package not installed */ + QMI_ERR_EREMOTE_V01 = 0x142, /**< Object is remote */ + QMI_ERR_ENOLINK_V01 = 0x143, /**< Link has been severed */ + QMI_ERR_EADV_V01 = 0x144, /**< Advertise error */ + QMI_ERR_ESRMNT_V01 = 0x145, /**< Srmount error */ + QMI_ERR_ECOMM_V01 = 0x146, /**< Communication error on send */ + QMI_ERR_EPROTO_V01 = 0x147, /**< Protocol error */ + QMI_ERR_EMULTIHOP_V01 = 0x148, /**< Multihop attempted */ + QMI_ERR_EDOTDOT_V01 = 0x149, /**< RFS specific error */ + QMI_ERR_EBADMSG_V01 = 0x14A, /**< Not a data message */ + QMI_ERR_EOVERFLOW_V01 = 0x14B, /**< Value too large for defined data type */ + QMI_ERR_ENOTUNIQ_V01 = 0x14C, /**< Name not unique on network */ + QMI_ERR_EBADFD_V01 = 0x14D, /**< File descriptor in bad state */ + QMI_ERR_EREMCHG_V01 = 0x14E, /**< Remote address changed */ + QMI_ERR_ELIBACC_V01 = 0x14F, /**< Can not access a needed shared library */ + QMI_ERR_ELIBBAD_V01 = 0x150, /**< Accessing a corrupted shared library */ + QMI_ERR_ELIBSCN_V01 = 0x151, /**< .lib section in a.out corrupted */ + QMI_ERR_ELIBMAX_V01 = 0x152, /**< Attempting to link in too many shared libraries */ + QMI_ERR_ELIBEXEC_V01 = 0x153, /**< Cannot exec a shared library directly */ + QMI_ERR_EILSEQ_V01 = 0x154, /**< Illegal byte sequence */ + QMI_ERR_ERESTART_V01 = 0x155, /**< Interrupted system call should be restarted */ + QMI_ERR_ESTRPIPE_V01 = 0x156, /**< Streams pipe error */ + QMI_ERR_EUSERS_V01 = 0x157, /**< Too many users */ + QMI_ERR_ENOTSOCK_V01 = 0x158, /**< Socket operation on non-socket */ + QMI_ERR_EDESTADDRREQ_V01 = 0x159, /**< Destination address required */ + QMI_ERR_EMSGSIZE_V01 = 0x15A, /**< Message too long */ + QMI_ERR_EPROTOTYPE_V01 = 0x15B, /**< Protocol wrong type for socket */ + QMI_ERR_ENOPROTOOPT_V01 = 0x15C, /**< Protocol not available */ + QMI_ERR_EPROTONOSUPPORT_V01 = 0x15D, /**< Protocol not supported */ + QMI_ERR_ESOCKTNOSUPPORT_V01 = 0x15E, /**< Socket type not supported */ + QMI_ERR_EOPNOTSUPP_V01 = 0x15F, /**< Operation not supported on transport endpoint */ + QMI_ERR_EPFNOSUPPORT_V01 = 0x160, /**< Protocol family not supported */ + QMI_ERR_EAFNOSUPPORT_V01 = 0x161, /**< Address family not supported by protocol */ + QMI_ERR_EADDRINUSE_V01 = 0x162, /**< Address already in use */ + QMI_ERR_EADDRNOTAVAIL_V01 = 0x163, /**< Cannot assign requested address */ + QMI_ERR_ENETDOWN_V01 = 0x164, /**< Network is down */ + QMI_ERR_ENETUNREACH_V01 = 0x165, /**< Network is unreachable */ + QMI_ERR_ENETRESET_V01 = 0x166, /**< Network dropped connection because of reset */ + QMI_ERR_ECONNABORTED_V01 = 0x167, /**< Software caused connection abort */ + QMI_ERR_ECONNRESET_V01 = 0x168, /**< Connection reset by peer */ + QMI_ERR_ENOBUFS_V01 = 0x169, /**< No buffer space available */ + QMI_ERR_EISCONN_V01 = 0x16A, /**< Transport endpoint is already connected */ + QMI_ERR_ENOTCONN_V01 = 0x16B, /**< Transport endpoint is not connected */ + QMI_ERR_ESHUTDOWN_V01 = 0x16C, /**< Cannot send after transport endpoint shutdown */ + QMI_ERR_ETOOMANYREFS_V01 = 0x16D, /**< Too many references: cannot splice */ + QMI_ERR_ETIMEDOUT_V01 = 0x16E, /**< Connection timed out */ + QMI_ERR_ECONNREFUSED_V01 = 0x16F, /**< Connection refused */ + QMI_ERR_EHOSTDOWN_V01 = 0x170, /**< Host is down */ + QMI_ERR_EHOSTUNREACH_V01 = 0x171, /**< No route to host */ + QMI_ERR_EALREADY_V01 = 0x172, /**< Operation already in progress */ + QMI_ERR_EINPROGRESS_V01 = 0x173, /**< Operation now in progress */ + QMI_ERR_ESTALE_V01 = 0x174, /**< Stale NFS file handle */ + QMI_ERR_EUCLEAN_V01 = 0x175, /**< Structure needs cleaning */ + QMI_ERR_ENOTNAM_V01 = 0x176, /**< Not a XENIX named type file */ + QMI_ERR_ENAVAIL_V01 = 0x177, /**< No XENIX semaphores available */ + QMI_ERR_EISNAM_V01 = 0x178, /**< Is a named type file */ + QMI_ERR_EREMOTEIO_V01 = 0x179, /**< Remote I/O error */ + QMI_ERR_EDQUOT_V01 = 0x17A, /**< Quota exceeded */ + QMI_ERR_ENOMEDIUM_V01 = 0x17B, /**< No medium found */ + QMI_ERR_EMEDIUMTYPE_V01 = 0x17C, /**< Wrong medium type */ + QMI_ERR_ECANCELED_V01 = 0x17D, /**< Operation Canceled */ + QMI_ERR_ENOKEY_V01 = 0x17E, /**< Required key not available */ + QMI_ERR_EKEYEXPIRED_V01 = 0x17F, /**< Key has expired */ + QMI_ERR_EKEYREVOKED_V01 = 0x180, /**< Key has been revoked */ + QMI_ERR_EKEYREJECTED_V01 = 0x181, /**< Key was rejected by service */ + QMI_ERR_EOWNERDEAD_V01 = 0x182, /**< Owner died */ + QMI_ERR_ENOTRECOVERABLE_V01 = 0x183, /**< State not recoverable */ + QMI_ERROR_TYPE_MAX_ENUM_VAL_V01 = 2147483647 /**< To force a 32 bit signed enum. Do not change or use*/ +}qmi_error_type_v01; + +typedef struct { + qmi_result_type_v01 result; + qmi_error_type_v01 error; +}qmi_response_type_v01; /* Type */ + +typedef enum { + NAS_SUBS_TYPE_ENUM_MIN_ENUM_VAL_V01 = -2147483647, /**< To force a 32 bit signed enum. Do not change or use*/ + NAS_PRIMARY_SUBSCRIPTION_V01 = 0x00, /**< Primary subscription \n */ + NAS_SECONDARY_SUBSCRIPTION_V01 = 0x01, /**< Secondary subscription \n */ + NAS_TERTIARY_SUBSCRIPTION_V01 = 0x02, /**< Tertiary subscription */ + NAS_SUBS_TYPE_ENUM_MAX_ENUM_VAL_V01 = 2147483647 /**< To force a 32 bit signed enum. Do not change or use*/ +}nas_subs_type_enum_v01; + +typedef struct { + nas_subs_type_enum_v01 subs_type; +}nas_bind_subscription_req_msg_v01; /* Message */ +//2021-03-24 willa.liu@fibocom.com changed end for support mantis 0071817 +#pragma pack(pop) + +#endif// MPQMUX_H diff --git a/package/wwan/app/fibocom-dial/src/Makefile b/package/wwan/app/fibocom-dial/src/Makefile new file mode 100755 index 000000000..e70d4f95a --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/Makefile @@ -0,0 +1,42 @@ +ifneq ($(CROSS_COMPILE),) +CROSS-COMPILE:=$(CROSS_COMPILE) +endif + +CFLAGS += -DGHT_FEATURE_PCIE_AUTO + +ifeq ($(CC),cc) +CC:=$(CROSS-COMPILE)gcc +endif +LD:=$(CROSS-COMPILE)ld + +SRC=QmiWwanCM.c GobiNetCM.c main.c MPQMUX.c QMIThread.c util.c qmap_bridge_mode.c query_pcie_mode.c + +FB_DHCP=udhcpc.c + +FIBO_PROXY_SRC=fibo_qmimsg_server.c + +LIBMNL=libmnl/ifutils.c libmnl/attr.c libmnl/callback.c libmnl/nlmsg.c libmnl/socket.c +FB_NDHCP=udhcpc_netlink.c +FB_NDHCP+=${LIBMNL} + +release: clean + $(CC) $(CFLAGS) -Wall -s ${SRC} ${FB_NDHCP} -o fibocom-dial -lpthread -ldl + $(CC) -Wall -s multi-pdn-manager.c query_pcie_mode.c util.c -o multi-pdn-manager -lpthread -ldl + $(CC) -Wall -s ${FIBO_PROXY_SRC} -o fibo_qmimsg_server -lpthread -ldl + +dhcp: clean + $(CC) $(CFLAGS) -Wall -s ${SRC} ${FB_DHCP} -o fibocom-dial -lpthread -ldl + $(CC) -Wall -s multi-pdn-manager.c query_pcie_mode.c util.c -o multi-pdn-manager -lpthread -ldl + $(CC) -Wall -s ${FIBO_PROXY_SRC} -o fibo_qmimsg_server -lpthread -ldl + +ndhcp: clean + $(CC) $(CFLAGS) -Wall -s ${SRC} ${FB_NDHCP} -o fibocom-dial -lpthread -ldl + $(CC) -Wall -s multi-pdn-manager.c query_pcie_mode.cutil.c -o multi-pdn-manager -lpthread -ldl + $(CC) -Wall -s ${FIBO_PROXY_SRC} -o fibo_qmimsg_server -lpthread -ldl + +qmi-proxy: + $(CC) -Wall -s fibo-qmi-proxy.c -o fibo-qmi-proxy -lpthread -ldl + +clean: + rm -rf fibocom-dial *~ multi-pdn-manager fibo_qmimsg_server + diff --git a/package/wwan/app/fibocom-dial/src/QMIThread.c b/package/wwan/app/fibocom-dial/src/QMIThread.c new file mode 100755 index 000000000..34f50c30a --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/QMIThread.c @@ -0,0 +1,2551 @@ +#include "QMIThread.h" +#include "query_pcie_mode.h" +extern char *strndup(const char *__string, size_t __n); + +//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817 +//extern int *speed_arr; +//extern int *name_arr; + +PQCQMIMSG pResponse; +PQMUX_MSG pMUXMsg; +//2021-03-24 willa.liu@fibocom.com changed end for support mantis 0071817 + +#define qmi_rsp_check_and_return()\ + do { \ + if (err < 0 || pResponse == NULL) { \ + dbg_time("%s err = %d", __func__, err); \ + return err; \ + } \ + pMUXMsg = &pResponse->MUXMsg; \ + if (le16_to_cpu(pMUXMsg->QMUXMsgHdrResp.QMUXResult) || \ + le16_to_cpu(pMUXMsg->QMUXMsgHdrResp.QMUXError)) { \ + USHORT QMUXError = le16_to_cpu(pMUXMsg->QMUXMsgHdrResp.QMUXError); \ + dbg_time("%s QMUXResult = 0x%x, QMUXError = 0x%x", __func__, \ + le16_to_cpu(pMUXMsg->QMUXMsgHdrResp.QMUXResult), \ + QMUXError); \ + free(pResponse); \ + return QMUXError; \ + } \ + } while (0) + +#define qmi_rsp_check() \ + do { \ + if (err < 0 || pResponse == NULL) { \ + dbg_time("%s err = %d", __func__, err); \ + return err; \ + } \ + pMUXMsg = &pResponse->MUXMsg; \ + if (le16_to_cpu(pMUXMsg->QMUXMsgHdrResp.QMUXResult) || \ + le16_to_cpu(pMUXMsg->QMUXMsgHdrResp.QMUXError)) { \ + USHORT QMUXError = le16_to_cpu(pMUXMsg->QMUXMsgHdrResp.QMUXError); \ + dbg_time("%s QMUXResult = 0x%x, QMUXError = 0x%x", __func__, \ + le16_to_cpu(pMUXMsg->QMUXMsgHdrResp.QMUXResult), \ + QMUXError); \ + } \ + } while (0) + +int qmiclientId[QMUX_TYPE_WDS_ADMIN + + 1]; // GobiNet use fd to indicate client ID, so type of + // qmiclientId must be int +static uint32_t WdsConnectionIPv4Handle = 0; +static uint32_t WdsConnectionIPv6Handle = 0; +static int s_is_cdma = 0; +static int s_hdr_personality = 0; // 0x01-HRPD, 0x02-eHRPD +static char *qstrcpy(char *to, const char *from) +{ // no __strcpy_chk + char *save = to; + for (; (*to = *from) != '\0'; ++from, ++to) + ; + return (save); +} + + + +typedef USHORT (*CUSTOMQMUX)(PQMUX_MSG pMUXMsg, void *arg); + +// To retrieve the ith (Index) TLV +PQMI_TLV_HDR GetTLV(PQCQMUX_MSG_HDR pQMUXMsgHdr, int TLVType) +{ + int TLVFind = 0; + USHORT Length = le16_to_cpu(pQMUXMsgHdr->Length); + PQMI_TLV_HDR pTLVHdr = (PQMI_TLV_HDR)(pQMUXMsgHdr + 1); + + while (Length >= sizeof(QMI_TLV_HDR)) { + TLVFind++; + if (TLVType > 0x1000) { + if ((TLVFind + 0x1000) == TLVType) + return pTLVHdr; + } else if (pTLVHdr->TLVType == TLVType) { + return pTLVHdr; + } + + Length -= (le16_to_cpu((pTLVHdr->TLVLength)) + sizeof(QMI_TLV_HDR)); + pTLVHdr = (PQMI_TLV_HDR)(((UCHAR *)pTLVHdr) + + le16_to_cpu(pTLVHdr->TLVLength) + + sizeof(QMI_TLV_HDR)); + } + + return NULL; +} + +static USHORT GetQMUXTransactionId(void) +{ + static int TransactionId = 0; + if (++TransactionId > 0xFFFF) + TransactionId = 1; + return TransactionId; +} + +static PQCQMIMSG ComposeQMUXMsg(UCHAR QMIType, USHORT Type, + CUSTOMQMUX customQmuxMsgFunction, void *arg) +{ + UCHAR QMIBuf[WDM_DEFAULT_BUFSIZE]; + PQCQMIMSG pRequest = (PQCQMIMSG)QMIBuf; + int Length; + + memset(QMIBuf, 0x00, sizeof(QMIBuf)); + pRequest->QMIHdr.IFType = USB_CTL_MSG_TYPE_QMI; + pRequest->QMIHdr.CtlFlags = 0x00; + pRequest->QMIHdr.QMIType = QMIType; + pRequest->QMIHdr.ClientId = qmiclientId[QMIType] & 0xFF; + + if (qmiclientId[QMIType] == 0) { + dbg_time("QMIType %d has no clientID", QMIType); + return NULL; + } + + pRequest->MUXMsg.QMUXHdr.CtlFlags = + QMUX_CTL_FLAG_SINGLE_MSG | QMUX_CTL_FLAG_TYPE_CMD; + pRequest->MUXMsg.QMUXHdr.TransactionId = + cpu_to_le16(GetQMUXTransactionId()); + pRequest->MUXMsg.QMUXMsgHdr.Type = cpu_to_le16(Type); + if (customQmuxMsgFunction) + pRequest->MUXMsg.QMUXMsgHdr.Length = + cpu_to_le16(customQmuxMsgFunction(&pRequest->MUXMsg, arg) - + sizeof(QCQMUX_MSG_HDR)); + else + pRequest->MUXMsg.QMUXMsgHdr.Length = cpu_to_le16(0x0000); + + pRequest->QMIHdr.Length = cpu_to_le16( + le16_to_cpu(pRequest->MUXMsg.QMUXMsgHdr.Length) + + sizeof(QCQMUX_MSG_HDR) + sizeof(QCQMUX_HDR) + sizeof(QCQMI_HDR) - 1); + Length = le16_to_cpu(pRequest->QMIHdr.Length) + 1; + + pRequest = (PQCQMIMSG)malloc(Length); + if (pRequest == NULL) { + dbg_time("%s fail to malloc", __func__); + } else { + memcpy(pRequest, QMIBuf, Length); + } + + return pRequest; +} + +static USHORT WdsStartNwInterfaceReq(PQMUX_MSG pMUXMsg, void *arg) +{ + PQMIWDS_TECHNOLOGY_PREFERECE pTechPref; + PQMIWDS_AUTH_PREFERENCE pAuthPref; + PQMIWDS_USERNAME pUserName; + PQMIWDS_PASSWD pPasswd; + PQMIWDS_APNNAME pApnName; + PQMIWDS_IP_FAMILY_TLV pIpFamily; + USHORT TLVLength = 0; + UCHAR *pTLV; + PROFILE_T *profile = (PROFILE_T *)arg; + const char *profile_user = profile->user; + const char *profile_password = profile->password; + int profile_auth = profile->auth; + + if (s_is_cdma && (profile_user == NULL || profile_user[0] == '\0') && + (profile_password == NULL || profile_password[0] == '\0')) { + profile_user = "ctnet@mycdma.cn"; + profile_password = "vnet.mobi"; + profile_auth = 2; // chap + } + + pTLV = (UCHAR *)(&pMUXMsg->StartNwInterfaceReq + 1); + pMUXMsg->StartNwInterfaceReq.Length = 0; + + // Set technology Preferece + pTechPref = (PQMIWDS_TECHNOLOGY_PREFERECE)(pTLV + TLVLength); + pTechPref->TLVType = 0x30; + pTechPref->TLVLength = cpu_to_le16(0x01); + if (s_is_cdma == 0) + pTechPref->TechPreference = 0x01; + else + pTechPref->TechPreference = 0x02; + TLVLength += (le16_to_cpu(pTechPref->TLVLength) + sizeof(QCQMICTL_TLV_HDR)); + + // Set APN Name + if (profile->apn && !s_is_cdma) { // cdma no apn + pApnName = (PQMIWDS_APNNAME)(pTLV + TLVLength); + pApnName->TLVType = 0x14; + pApnName->TLVLength = cpu_to_le16(strlen(profile->apn)); + qstrcpy((char *)&pApnName->ApnName, profile->apn); + TLVLength += + (le16_to_cpu(pApnName->TLVLength) + sizeof(QCQMICTL_TLV_HDR)); + } + + // Set User Name + if (profile_user) { + pUserName = (PQMIWDS_USERNAME)(pTLV + TLVLength); + pUserName->TLVType = 0x17; + pUserName->TLVLength = cpu_to_le16(strlen(profile_user)); + qstrcpy((char *)&pUserName->UserName, profile_user); + TLVLength += + (le16_to_cpu(pUserName->TLVLength) + sizeof(QCQMICTL_TLV_HDR)); + } + + // Set Password + if (profile_password) { + pPasswd = (PQMIWDS_PASSWD)(pTLV + TLVLength); + pPasswd->TLVType = 0x18; + pPasswd->TLVLength = cpu_to_le16(strlen(profile_password)); + qstrcpy((char *)&pPasswd->Passwd, profile_password); + TLVLength += + (le16_to_cpu(pPasswd->TLVLength) + sizeof(QCQMICTL_TLV_HDR)); + } + + // Set Auth Protocol + if (profile_user && profile_password) { + pAuthPref = (PQMIWDS_AUTH_PREFERENCE)(pTLV + TLVLength); + pAuthPref->TLVType = 0x16; + pAuthPref->TLVLength = cpu_to_le16(0x01); + pAuthPref->AuthPreference = + profile_auth; // 0 ~ None, 1 ~ Pap, 2 ~ Chap, 3 ~ MsChapV2 + TLVLength += + (le16_to_cpu(pAuthPref->TLVLength) + sizeof(QCQMICTL_TLV_HDR)); + } + + // Add IP Family Preference + pIpFamily = (PQMIWDS_IP_FAMILY_TLV)(pTLV + TLVLength); + pIpFamily->TLVType = 0x19; + pIpFamily->TLVLength = cpu_to_le16(0x01); + pIpFamily->IpFamily = profile->curIpFamily; + TLVLength += (le16_to_cpu(pIpFamily->TLVLength) + sizeof(QCQMICTL_TLV_HDR)); + + // Set Profile Index + if (profile->pdp && !s_is_cdma) { // cdma only support one pdp, so no need + // to set profile index + PQMIWDS_PROFILE_IDENTIFIER pProfileIndex = + (PQMIWDS_PROFILE_IDENTIFIER)(pTLV + TLVLength); + pProfileIndex->TLVLength = cpu_to_le16(0x01); + pProfileIndex->TLVType = 0x31; + pProfileIndex->ProfileIndex = profile->pdpindex; + if (s_is_cdma && s_hdr_personality == 0x02) { + pProfileIndex->TLVType = 0x32; // profile_index_3gpp2 + pProfileIndex->ProfileIndex = 101; + } + TLVLength += + (le16_to_cpu(pProfileIndex->TLVLength) + sizeof(QCQMICTL_TLV_HDR)); + } + + return sizeof(QMIWDS_START_NETWORK_INTERFACE_REQ_MSG) + TLVLength; +} + +static USHORT WdsStopNwInterfaceReq(PQMUX_MSG pMUXMsg, void *arg) +{ + pMUXMsg->StopNwInterfaceReq.TLVType = 0x01; + pMUXMsg->StopNwInterfaceReq.TLVLength = cpu_to_le16(0x04); + if (*((int *)arg) == IpFamilyV4) + pMUXMsg->StopNwInterfaceReq.Handle = + cpu_to_le32(WdsConnectionIPv4Handle); + else + pMUXMsg->StopNwInterfaceReq.Handle = + cpu_to_le32(WdsConnectionIPv6Handle); + return sizeof(QMIWDS_STOP_NETWORK_INTERFACE_REQ_MSG); +} + +static USHORT WdsSetClientIPFamilyPref(PQMUX_MSG pMUXMsg, void *arg) +{ + pMUXMsg->SetClientIpFamilyPrefReq.TLVType = 0x01; + pMUXMsg->SetClientIpFamilyPrefReq.TLVLength = cpu_to_le16(0x01); + pMUXMsg->SetClientIpFamilyPrefReq.IpPreference = *((UCHAR *)arg); + return sizeof(QMIWDS_SET_CLIENT_IP_FAMILY_PREF_REQ_MSG); +} + +static USHORT WdsSetAutoConnect(PQMUX_MSG pMUXMsg, void *arg) +{ + pMUXMsg->SetAutoConnectReq.TLVType = 0x01; + pMUXMsg->SetAutoConnectReq.TLVLength = cpu_to_le16(0x01); + pMUXMsg->SetAutoConnectReq.autoconnect_setting = *((UCHAR *)arg); + return sizeof(QMIWDS_SET_AUTO_CONNECT_REQ_MSG); +} + +enum peripheral_ep_type { + DATA_EP_TYPE_RESERVED = 0x0, + DATA_EP_TYPE_HSIC = 0x1, + DATA_EP_TYPE_HSUSB = 0x2, + DATA_EP_TYPE_PCIE = 0x3, + DATA_EP_TYPE_EMBEDDED = 0x4, + DATA_EP_TYPE_BAM_DMUX = 0x5, +}; + +typedef struct { + UINT rx_urb_size; + enum peripheral_ep_type ep_type; + UINT iface_id; + UCHAR MuxId; +} QMAP_SETTING; +static USHORT WdsSetQMUXBindMuxDataPort(PQMUX_MSG pMUXMsg, void *arg) +{ + QMAP_SETTING *qmap_settings = (QMAP_SETTING *)arg; + + pMUXMsg->BindMuxDataPortReq.TLVType = 0x10; + pMUXMsg->BindMuxDataPortReq.TLVLength = cpu_to_le16(0x08); + pMUXMsg->BindMuxDataPortReq.ep_type = cpu_to_le32(qmap_settings->ep_type); + pMUXMsg->BindMuxDataPortReq.iface_id = cpu_to_le32(qmap_settings->iface_id); + pMUXMsg->BindMuxDataPortReq.TLV2Type = 0x11; + pMUXMsg->BindMuxDataPortReq.TLV2Length = cpu_to_le16(0x01); + pMUXMsg->BindMuxDataPortReq.MuxId = qmap_settings->MuxId; + pMUXMsg->BindMuxDataPortReq.TLV3Type = 0x13; + pMUXMsg->BindMuxDataPortReq.TLV3Length = cpu_to_le16(0x04); + pMUXMsg->BindMuxDataPortReq.client_type = + cpu_to_le32(1); // WDS_CLIENT_TYPE_TETHERED + + return sizeof(QMIWDS_BIND_MUX_DATA_PORT_REQ_MSG); +} + +static USHORT WdaSetDataFormat(PQMUX_MSG pMUXMsg, void *arg) +{ + QMAP_SETTING *qmap_settings = (QMAP_SETTING *)arg; + + if (qmap_settings->rx_urb_size == 0) { + PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV_QOS pWdsAdminQosTlv; + PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV linkProto; + PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV dlTlp; + + pWdsAdminQosTlv = + (PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV_QOS)(&pMUXMsg->QMUXMsgHdr + 1); + pWdsAdminQosTlv->TLVType = 0x10; + pWdsAdminQosTlv->TLVLength = cpu_to_le16(0x0001); + pWdsAdminQosTlv->QOSSetting = 0; /* no-QOS header */ + + linkProto = (PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV)(pWdsAdminQosTlv + 1); + linkProto->TLVType = 0x11; + linkProto->TLVLength = cpu_to_le16(4); + linkProto->Value = cpu_to_le32(0x01); /* Set Ethernet mode */ + + dlTlp = (PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV)(linkProto + 1); + ; + dlTlp->TLVType = 0x13; + dlTlp->TLVLength = cpu_to_le16(4); + dlTlp->Value = cpu_to_le32(0x00); + + if (sizeof(*linkProto) != 7) + dbg_time("%s sizeof(*linkProto) = %d, is not 7!", __func__, + sizeof(*linkProto)); + + return sizeof(QCQMUX_MSG_HDR) + sizeof(*pWdsAdminQosTlv) + + sizeof(*linkProto) + sizeof(*dlTlp); + } else { + // Indicates whether the Quality of Service(QOS) data format is used by + // the client. + pMUXMsg->SetDataFormatReq.QosDataFormatTlv.TLVType = 0x10; + pMUXMsg->SetDataFormatReq.QosDataFormatTlv.TLVLength = + cpu_to_le16(0x0001); + pMUXMsg->SetDataFormatReq.QosDataFormatTlv.QOSSetting = + 0; /* no-QOS header */ + // Underlying Link Layer Protocol + pMUXMsg->SetDataFormatReq.UnderlyingLinkLayerProtocolTlv.TLVType = 0x11; + pMUXMsg->SetDataFormatReq.UnderlyingLinkLayerProtocolTlv.TLVLength = + cpu_to_le16(4); + pMUXMsg->SetDataFormatReq.UnderlyingLinkLayerProtocolTlv.Value = + cpu_to_le32(0x02); /* Set IP mode */ + // Uplink (UL) data aggregation protocol to be used for uplink data + // transfer. + pMUXMsg->SetDataFormatReq.UplinkDataAggregationProtocolTlv.TLVType = + 0x12; + pMUXMsg->SetDataFormatReq.UplinkDataAggregationProtocolTlv.TLVLength = + cpu_to_le16(4); + pMUXMsg->SetDataFormatReq.UplinkDataAggregationProtocolTlv.Value = + cpu_to_le32(0x05); // UL QMAP is enabled + // Downlink (DL) data aggregation protocol to be used for downlink data + // transfer + pMUXMsg->SetDataFormatReq.DownlinkDataAggregationProtocolTlv.TLVType = + 0x13; + pMUXMsg->SetDataFormatReq.DownlinkDataAggregationProtocolTlv.TLVLength = + cpu_to_le16(4); + pMUXMsg->SetDataFormatReq.DownlinkDataAggregationProtocolTlv.Value = + cpu_to_le32(0x05); // UL QMAP is enabled + // Maximum number of datagrams in a single aggregated packet on downlink + pMUXMsg->SetDataFormatReq.DownlinkDataAggregationMaxDatagramsTlv + .TLVType = 0x15; + pMUXMsg->SetDataFormatReq.DownlinkDataAggregationMaxDatagramsTlv + .TLVLength = cpu_to_le16(4); + pMUXMsg->SetDataFormatReq.DownlinkDataAggregationMaxDatagramsTlv.Value = + cpu_to_le32(qmap_settings->rx_urb_size / 512); + // Maximum size in bytes of a single aggregated packet allowed on + // downlink + pMUXMsg->SetDataFormatReq.DownlinkDataAggregationMaxSizeTlv.TLVType = + 0x16; + pMUXMsg->SetDataFormatReq.DownlinkDataAggregationMaxSizeTlv.TLVLength = + cpu_to_le16(4); + pMUXMsg->SetDataFormatReq.DownlinkDataAggregationMaxSizeTlv.Value = + cpu_to_le32(qmap_settings->rx_urb_size); + // Peripheral End Point ID + pMUXMsg->SetDataFormatReq.epTlv.TLVType = 0x17; + pMUXMsg->SetDataFormatReq.epTlv.TLVLength = cpu_to_le16(8); + pMUXMsg->SetDataFormatReq.epTlv.ep_type = + cpu_to_le32(qmap_settings->ep_type); + pMUXMsg->SetDataFormatReq.epTlv.iface_id = + cpu_to_le32(qmap_settings->iface_id); + + return sizeof(QMIWDS_ADMIN_SET_DATA_FORMAT_REQ_MSG); + } +} + +#ifdef CONFIG_SIM + +static USHORT UimVerifyPinReqSend(PQMUX_MSG pMUXMsg, void *arg) +{ + pMUXMsg->UIMUIMVerifyPinReq.TLVType = 0x01; + pMUXMsg->UIMUIMVerifyPinReq.TLVLength = cpu_to_le16(0x02); + pMUXMsg->UIMUIMVerifyPinReq.Session_Type = 0x00; + pMUXMsg->UIMUIMVerifyPinReq.Aid_Len = 0x00; + pMUXMsg->UIMUIMVerifyPinReq.TLV2Type = 0x02; + pMUXMsg->UIMUIMVerifyPinReq.TLV2Length = + cpu_to_le16(2 + strlen((const char *)arg)); + pMUXMsg->UIMUIMVerifyPinReq.PINID = 0x01; // Pin1, not Puk + pMUXMsg->UIMUIMVerifyPinReq.PINLen = strlen((const char *)arg); + qstrcpy((PCHAR)&pMUXMsg->UIMUIMVerifyPinReq.PINValue, ((const char *)arg)); + return sizeof(QMIUIM_VERIFY_PIN_REQ_MSG) + (strlen((const char *)arg) - 1); +} +//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817 +static USHORT UimBindPinReqSend_NAS_WMS(PQMUX_MSG pMUXMsg, void *arg) +{ + pMUXMsg->UIMUIMBindPinReq.TLVType = 0x01; + pMUXMsg->UIMUIMBindPinReq.TLVLength = cpu_to_le16(0x01); + pMUXMsg->UIMUIMBindPinReq.Value = 0x01; + return sizeof(QMIUIM_BIND_PIN_REQ_MSG); +} + +static USHORT UimBindPinReqSend_WDS_DMS_QOS(PQMUX_MSG pMUXMsg, void *arg) +{ + pMUXMsg->UIMUIMBindPinReq_4.TLVType = 0x01; + pMUXMsg->UIMUIMBindPinReq_4.TLVLength = cpu_to_le16(0x04); + pMUXMsg->UIMUIMBindPinReq_4.Value = 0x0002; + return sizeof(QMIUIM_BIND_PIN_REQ_MSG_4); +} +//2021-03-24 willa.liu@fibocom.com changed end for support mantis 0071817 +#ifdef CONFIG_IMSI_ICCID +static USHORT UimReadTransparentIMSIReqSend(PQMUX_MSG pMUXMsg, void *arg) +{ + PREAD_TRANSPARENT_TLV pReadTransparent; + + pMUXMsg->UIMUIMReadTransparentReq.TLVType = 0x01; + pMUXMsg->UIMUIMReadTransparentReq.TLVLength = cpu_to_le16(0x02); + if (!strcmp((char *)arg, "EF_ICCID")) { + pMUXMsg->UIMUIMReadTransparentReq.Session_Type = 0x06; + pMUXMsg->UIMUIMReadTransparentReq.Aid_Len = 0x00; + + pMUXMsg->UIMUIMReadTransparentReq.TLV2Type = 0x02; + pMUXMsg->UIMUIMReadTransparentReq.file_id = cpu_to_le16(0x2FE2); + pMUXMsg->UIMUIMReadTransparentReq.path_len = 0x02; + pMUXMsg->UIMUIMReadTransparentReq.path[0] = 0x00; + pMUXMsg->UIMUIMReadTransparentReq.path[1] = 0x3F; + } else if (!strcmp((char *)arg, "EF_IMSI")) { + pMUXMsg->UIMUIMReadTransparentReq.Session_Type = 0x00; + pMUXMsg->UIMUIMReadTransparentReq.Aid_Len = 0x00; + + pMUXMsg->UIMUIMReadTransparentReq.TLV2Type = 0x02; + pMUXMsg->UIMUIMReadTransparentReq.file_id = cpu_to_le16(0x6F07); + pMUXMsg->UIMUIMReadTransparentReq.path_len = 0x04; + pMUXMsg->UIMUIMReadTransparentReq.path[0] = 0x00; + pMUXMsg->UIMUIMReadTransparentReq.path[1] = 0x3F; + pMUXMsg->UIMUIMReadTransparentReq.path[2] = 0xFF; + pMUXMsg->UIMUIMReadTransparentReq.path[3] = 0x7F; + } + + pMUXMsg->UIMUIMReadTransparentReq.TLV2Length = + cpu_to_le16(3 + pMUXMsg->UIMUIMReadTransparentReq.path_len); + + pReadTransparent = (PREAD_TRANSPARENT_TLV)( + &pMUXMsg->UIMUIMReadTransparentReq + .path[pMUXMsg->UIMUIMReadTransparentReq.path_len]); + pReadTransparent->TLVType = 0x03; + pReadTransparent->TLVLength = cpu_to_le16(0x04); + pReadTransparent->Offset = cpu_to_le16(0x00); + pReadTransparent->Length = cpu_to_le16(0x00); + + return (sizeof(QMIUIM_READ_TRANSPARENT_REQ_MSG) + + pMUXMsg->UIMUIMReadTransparentReq.path_len + + sizeof(READ_TRANSPARENT_TLV)); +} +#endif +#endif + +#ifdef CONFIG_APN +static USHORT WdsGetProfileSettingsReqSend(PQMUX_MSG pMUXMsg, void *arg) +{ + PROFILE_T *profile = (PROFILE_T *)arg; + pMUXMsg->GetProfileSettingsReq.Length = + cpu_to_le16(sizeof(QMIWDS_GET_PROFILE_SETTINGS_REQ_MSG) - 4); + pMUXMsg->GetProfileSettingsReq.TLVType = 0x01; + pMUXMsg->GetProfileSettingsReq.TLVLength = cpu_to_le16(0x02); + pMUXMsg->GetProfileSettingsReq.ProfileType = 0x00; // 0 ~ 3GPP, 1 ~ 3GPP2 + pMUXMsg->GetProfileSettingsReq.ProfileIndex = profile->pdpindex; + return sizeof(QMIWDS_GET_PROFILE_SETTINGS_REQ_MSG); +} +//begin modified by zhangkaibo add create profile qmi. mantis 0049137,0048741 20200610 +static USHORT WdsCreateProfileSettingsReq(PQMUX_MSG pMUXMsg, void *arg) +{ + USHORT TLVLength = 0; + UCHAR *pTLV; + PROFILE_T *profile = (PROFILE_T *)arg; + PQMIWDS_PDPTYPE pPdpType; + + pMUXMsg->CreateProfileSettingsReq.Length = + cpu_to_le16(sizeof(QMIWDS_CREATE_PROFILE_SETTINGS_REQ_MSG) - 4); + pMUXMsg->CreateProfileSettingsReq.TLVType = 0x01; + pMUXMsg->CreateProfileSettingsReq.TLVLength = cpu_to_le16(0x01); + pMUXMsg->CreateProfileSettingsReq.ProfileType = + 0x00; // 0 ~ 3GPP, 1 ~ 3GPP2 + + pTLV = (UCHAR *)(&pMUXMsg->CreateProfileSettingsReq + 1); + + pPdpType = (PQMIWDS_PDPTYPE)(pTLV + TLVLength); + pPdpType->TLVType = 0x11; + pPdpType->TLVLength = cpu_to_le16(0x01); + // 0 ?C PDP-IP (IPv4) + // 1 ?C PDP-PPP + // 2 ?C PDP-IPv6 + // 3 ?C PDP-IPv4v6 + if (profile->ipv4_flag && profile->ipv6_flag) + pPdpType->PdpType = 3; + else if (profile->ipv6_flag) + pPdpType->PdpType = 2; + else + pPdpType->PdpType = 0; + TLVLength += (le16_to_cpu(pPdpType->TLVLength) + sizeof(QCQMICTL_TLV_HDR)); + + // Set APN Name + if (profile->apn) { + PQMIWDS_APNNAME pApnName = (PQMIWDS_APNNAME)(pTLV + TLVLength); + pApnName->TLVType = 0x14; + pApnName->TLVLength = cpu_to_le16(strlen(profile->apn)); + qstrcpy((char *)&pApnName->ApnName, profile->apn); + TLVLength += + (le16_to_cpu(pApnName->TLVLength) + sizeof(QCQMICTL_TLV_HDR)); + } + + // Set User Name + if (profile->user) { + PQMIWDS_USERNAME pUserName = (PQMIWDS_USERNAME)(pTLV + TLVLength); + pUserName->TLVType = 0x1B; + + pUserName->TLVLength = cpu_to_le16(strlen(profile->user)); + qstrcpy((char *)&pUserName->UserName, profile->user); + TLVLength += + (le16_to_cpu(pUserName->TLVLength) + sizeof(QCQMICTL_TLV_HDR)); + } + + // Set Password + if (profile->password) { + PQMIWDS_PASSWD pPasswd = (PQMIWDS_PASSWD)(pTLV + TLVLength); + pPasswd->TLVType = 0x1C; + pPasswd->TLVLength = cpu_to_le16(strlen(profile->password)); + qstrcpy((char *)&pPasswd->Passwd, profile->password); + TLVLength += + (le16_to_cpu(pPasswd->TLVLength) + sizeof(QCQMICTL_TLV_HDR)); + } + + // Set Auth Protocol + if (profile->user && profile->password) { + PQMIWDS_AUTH_PREFERENCE pAuthPref = + (PQMIWDS_AUTH_PREFERENCE)(pTLV + TLVLength); + pAuthPref->TLVType = 0x1D; + pAuthPref->TLVLength = cpu_to_le16(0x01); + pAuthPref->AuthPreference = + profile->auth; // 0 ~ None, 1 ~ Pap, 2 ~ Chap, 3 ~ MsChapV2 + TLVLength += + (le16_to_cpu(pAuthPref->TLVLength) + sizeof(QCQMICTL_TLV_HDR)); + } + + return sizeof(QMIWDS_CREATE_PROFILE_SETTINGS_REQ_MSG) + TLVLength; +} +//end modified by zhangkaibo add create profile qmi. mantis 0049137,0048741 20200610 +static USHORT WdsModifyProfileSettingsReq(PQMUX_MSG pMUXMsg, void *arg) +{ + USHORT TLVLength = 0; + UCHAR *pTLV; + PROFILE_T *profile = (PROFILE_T *)arg; + PQMIWDS_PDPTYPE pPdpType; + + pMUXMsg->ModifyProfileSettingsReq.Length = + cpu_to_le16(sizeof(QMIWDS_MODIFY_PROFILE_SETTINGS_REQ_MSG) - 4); + pMUXMsg->ModifyProfileSettingsReq.TLVType = 0x01; + pMUXMsg->ModifyProfileSettingsReq.TLVLength = cpu_to_le16(0x02); + pMUXMsg->ModifyProfileSettingsReq.ProfileType = + 0x00; // 0 ~ 3GPP, 1 ~ 3GPP2 + pMUXMsg->ModifyProfileSettingsReq.ProfileIndex = profile->pdpindex; + + pTLV = (UCHAR *)(&pMUXMsg->ModifyProfileSettingsReq + 1); + + pPdpType = (PQMIWDS_PDPTYPE)(pTLV + TLVLength); + pPdpType->TLVType = 0x11; + pPdpType->TLVLength = cpu_to_le16(0x01); + // 0 ?C PDP-IP (IPv4) + // 1 ?C PDP-PPP + // 2 ?C PDP-IPv6 + // 3 ?C PDP-IPv4v6 + if (profile->ipv6_flag && profile->ipv4_flag) + pPdpType->PdpType = 3; + else if (profile->ipv6_flag) + pPdpType->PdpType = 2; + else + pPdpType->PdpType = 0; + TLVLength += (le16_to_cpu(pPdpType->TLVLength) + sizeof(QCQMICTL_TLV_HDR)); + + // Set APN Name + if (profile->apn) { + PQMIWDS_APNNAME pApnName = (PQMIWDS_APNNAME)(pTLV + TLVLength); + pApnName->TLVType = 0x14; + pApnName->TLVLength = cpu_to_le16(strlen(profile->apn)); + qstrcpy((char *)&pApnName->ApnName, profile->apn); + TLVLength += + (le16_to_cpu(pApnName->TLVLength) + sizeof(QCQMICTL_TLV_HDR)); + } + + // Set User Name + if (profile->user) { + PQMIWDS_USERNAME pUserName = (PQMIWDS_USERNAME)(pTLV + TLVLength); + pUserName->TLVType = 0x1B; + pUserName->TLVLength = cpu_to_le16(strlen(profile->user)); + qstrcpy((char *)&pUserName->UserName, profile->user); + TLVLength += + (le16_to_cpu(pUserName->TLVLength) + sizeof(QCQMICTL_TLV_HDR)); + } + + // Set Password + if (profile->password) { + PQMIWDS_PASSWD pPasswd = (PQMIWDS_PASSWD)(pTLV + TLVLength); + pPasswd->TLVType = 0x1C; + pPasswd->TLVLength = cpu_to_le16(strlen(profile->password)); + qstrcpy((char *)&pPasswd->Passwd, profile->password); + TLVLength += + (le16_to_cpu(pPasswd->TLVLength) + sizeof(QCQMICTL_TLV_HDR)); + } + + // Set Auth Protocol + if (profile->user && profile->password) { + PQMIWDS_AUTH_PREFERENCE pAuthPref = + (PQMIWDS_AUTH_PREFERENCE)(pTLV + TLVLength); + pAuthPref->TLVType = 0x1D; + pAuthPref->TLVLength = cpu_to_le16(0x01); + pAuthPref->AuthPreference = + profile->auth; // 0 ~ None, 1 ~ Pap, 2 ~ Chap, 3 ~ MsChapV2 + TLVLength += + (le16_to_cpu(pAuthPref->TLVLength) + sizeof(QCQMICTL_TLV_HDR)); + } + + return sizeof(QMIWDS_MODIFY_PROFILE_SETTINGS_REQ_MSG) + TLVLength; +} +#endif + +static USHORT WdsGetRuntimeSettingReq(PQMUX_MSG pMUXMsg, void *arg) +{ + pMUXMsg->GetRuntimeSettingsReq.TLVType = 0x10; + pMUXMsg->GetRuntimeSettingsReq.TLVLength = cpu_to_le16(0x04); + // the following mask also applies to IPV6 + pMUXMsg->GetRuntimeSettingsReq.Mask = + cpu_to_le32(QMIWDS_GET_RUNTIME_SETTINGS_MASK_IPV4DNS_ADDR | + QMIWDS_GET_RUNTIME_SETTINGS_MASK_IPV4_ADDR | + QMIWDS_GET_RUNTIME_SETTINGS_MASK_MTU | + QMIWDS_GET_RUNTIME_SETTINGS_MASK_IPV4GATEWAY_ADDR); // | + // QMIWDS_GET_RUNTIME_SETTINGS_MASK_PCSCF_SV_ADDR | + // QMIWDS_GET_RUNTIME_SETTINGS_MASK_PCSCF_DOM_NAME; + + return sizeof(QMIWDS_GET_RUNTIME_SETTINGS_REQ_MSG); +} + +static PQCQMIMSG s_pRequest; +static PQCQMIMSG s_pResponse; +static pthread_mutex_t s_commandmutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t s_commandcond = PTHREAD_COND_INITIALIZER; + +static int is_response(const PQCQMIMSG pRequest, const PQCQMIMSG pResponse) +{ + if ((pRequest->QMIHdr.QMIType == pResponse->QMIHdr.QMIType) && + (pRequest->QMIHdr.ClientId == pResponse->QMIHdr.ClientId)) { + USHORT requestTID, responseTID; + if (pRequest->QMIHdr.QMIType == QMUX_TYPE_CTL) { + requestTID = pRequest->CTLMsg.QMICTLMsgHdr.TransactionId; + responseTID = pResponse->CTLMsg.QMICTLMsgHdr.TransactionId; + } else { + requestTID = le16_to_cpu(pRequest->MUXMsg.QMUXHdr.TransactionId); + responseTID = le16_to_cpu(pResponse->MUXMsg.QMUXHdr.TransactionId); + } + return (requestTID == responseTID); + } + return 0; +} + +int (*qmidev_send)(PQCQMIMSG pRequest); + +int QmiThreadSendQMITimeout(PQCQMIMSG pRequest, PQCQMIMSG *ppResponse, + unsigned msecs) +{ + int ret; + + if (!pRequest) { + return -EINVAL; + } + + pthread_mutex_lock(&s_commandmutex); + + if (ppResponse) + *ppResponse = NULL; + + dump_qmi(pRequest, le16_to_cpu(pRequest->QMIHdr.Length) + 1); + + s_pRequest = pRequest; + s_pResponse = NULL; + + ret = qmidev_send(pRequest); + + if (ret == 0) { + ret = pthread_cond_timeout_np(&s_commandcond, &s_commandmutex, msecs); + if (!ret) { + if (s_pResponse && ppResponse) { + *ppResponse = s_pResponse; + } else { + if (s_pResponse) { + free(s_pResponse); + s_pResponse = NULL; + } + } + } else { + dbg_time("%s pthread_cond_timeout_np=%d, errno: %d (%s)", __func__, + ret, errno, strerror(errno)); + } + } + + pthread_mutex_unlock(&s_commandmutex); + + return ret; +} + +int QmiThreadSendQMI(PQCQMIMSG pRequest, PQCQMIMSG *ppResponse) +{ + return QmiThreadSendQMITimeout(pRequest, ppResponse, 30 * 1000); +} + +void QmiThreadRecvQMI(PQCQMIMSG pResponse) +{ + pthread_mutex_lock(&s_commandmutex); + if (pResponse == NULL) { + if (s_pRequest) { + free(s_pRequest); + s_pRequest = NULL; + s_pResponse = NULL; + pthread_cond_signal(&s_commandcond); + } + pthread_mutex_unlock(&s_commandmutex); + return; + } + dump_qmi(pResponse, le16_to_cpu(pResponse->QMIHdr.Length) + 1); + if (s_pRequest && is_response(s_pRequest, pResponse)) { + free(s_pRequest); + s_pRequest = NULL; + s_pResponse = malloc(le16_to_cpu(pResponse->QMIHdr.Length) + 1); + if (s_pResponse != NULL) { + memcpy(s_pResponse, pResponse, + le16_to_cpu(pResponse->QMIHdr.Length) + 1); + } + pthread_cond_signal(&s_commandcond); + } else if ((pResponse->QMIHdr.QMIType == QMUX_TYPE_NAS) && + (le16_to_cpu(pResponse->MUXMsg.QMUXMsgHdrResp.Type) == + QMINAS_SERVING_SYSTEM_IND)) { + qmidevice_send_event_to_main( + RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED); + } else if ((pResponse->QMIHdr.QMIType == QMUX_TYPE_WDS) && + (le16_to_cpu(pResponse->MUXMsg.QMUXMsgHdrResp.Type) == + QMIWDS_GET_PKT_SRVC_STATUS_IND)) { + qmidevice_send_event_to_main(RIL_UNSOL_DATA_CALL_LIST_CHANGED); + } else if ((pResponse->QMIHdr.QMIType == QMUX_TYPE_WDS_IPV6) && + (le16_to_cpu(pResponse->MUXMsg.QMUXMsgHdrResp.Type) == + QMIWDS_GET_PKT_SRVC_STATUS_IND)) { + qmidevice_send_event_to_main(RIL_UNSOL_DATA_CALL_LIST_CHANGED); + } else if ((pResponse->QMIHdr.QMIType == QMUX_TYPE_NAS) && + (le16_to_cpu(pResponse->MUXMsg.QMUXMsgHdrResp.Type) == + QMINAS_SYS_INFO_IND)) { + qmidevice_send_event_to_main( + RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED); + } else { + if (debug_qmi) + dbg_time("nobody care this qmi msg!!"); + } + pthread_mutex_unlock(&s_commandmutex); +} + +int requestSetEthMode(PROFILE_T *profile) +{ + PQCQMIMSG pRequest; + PQCQMIMSG pResponse = NULL; + PQMUX_MSG pMUXMsg; + int err; + PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV linkProto; + UCHAR IpPreference; + UCHAR autoconnect_setting = 0; + QMAP_SETTING qmap_settings = {0, 0, 0, 0}; + + if (profile->qmap_mode) { + profile->rawIP = 1; + + + qmap_settings.MuxId = profile->muxid; + + if (qmidev_is_pciemhi(profile->qmichannel)) { // SDX20_PCIE + qmap_settings.rx_urb_size = 32*1024; //SDX24&SDX55 support 32KB + qmap_settings.ep_type = DATA_EP_TYPE_PCIE; + qmap_settings.iface_id = 0x04; + } else { // for MDM9x07&MDM9x40&SDX20 USB + qmap_settings.rx_urb_size = profile->qmap_size; + //profile->qmap_size; // SDX24&SDX55 support 32KB + qmap_settings.ep_type = DATA_EP_TYPE_HSUSB; +//2021-02-08 zhangkaibo@fibocom.com changed begin for mantis 0070613 + qmap_settings.iface_id = profile->interfacenum; +//2021-02-08 zhangkaibo@fibocom.com changed end for mantis 0070613 + } + + if (qmidev_is_gobinet( + profile->qmichannel)) { // GobiNet set data format + // in GobiNet driver + goto skip_WdaSetDataFormat; + } else if (profile->qmap_mode > + 1) { // QMAP MUX enabled, set data format in fibo-qmi-proxy + +//2021-06-03 willa.liu@fibocom.com changed begin for support mantis 0079541 +//2021-01-27 willa.liu@fibocom.com changed begin for support mantis 0068849 + //goto skip_WdaSetDataFormat; + goto skip_WdaSetDataFormat; +//2021-01-27 willa.liu@fibocom.com changed end for support mantis 0068849 +//2021-06-03 willa.liu@fibocom.com changed end for support mantis 0079541 + + } + } + + pRequest = + ComposeQMUXMsg(QMUX_TYPE_WDS_ADMIN, QMIWDS_ADMIN_SET_DATA_FORMAT_REQ, + WdaSetDataFormat, (void *)&qmap_settings); + err = QmiThreadSendQMI(pRequest, &pResponse); + qmi_rsp_check_and_return(); + + linkProto = (PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV)GetTLV( + &pResponse->MUXMsg.QMUXMsgHdr, 0x11); + if (linkProto != NULL) { + profile->rawIP = (le32_to_cpu(linkProto->Value) == 2); + } + + linkProto = (PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV)GetTLV( + &pResponse->MUXMsg.QMUXMsgHdr, 0x16); + if (linkProto != NULL && profile->qmap_mode) { + qmap_settings.rx_urb_size = le32_to_cpu(linkProto->Value); + dbg_time( + "qmap_settings.rx_urb_size = %d", + qmap_settings.rx_urb_size); // must same as rx_urb_size defined + // in GobiNet&qmi_wwan driver + } + + free(pResponse); + +skip_WdaSetDataFormat: +//bind v4 client + // set ipv4 + if(profile->ipv4_flag) + { +/* IpPreference = IpFamilyV4; + pRequest = + ComposeQMUXMsg(QMUX_TYPE_WDS, QMIWDS_SET_CLIENT_IP_FAMILY_PREF_REQ, + WdsSetClientIPFamilyPref, (void *)&IpPreference); + err = QmiThreadSendQMI(pRequest, &pResponse); + if (pResponse) + free(pResponse); +*/ + if (profile->qmapnet_adapter) { + // bind wds mux data port + pRequest = ComposeQMUXMsg( + QMUX_TYPE_WDS, QMIWDS_BIND_MUX_DATA_PORT_REQ, + WdsSetQMUXBindMuxDataPort, (void *)&qmap_settings); + err = QmiThreadSendQMI(pRequest, &pResponse); + qmi_rsp_check_and_return(); + if (pResponse) + free(pResponse); + } +// set auto connect + pRequest = ComposeQMUXMsg(QMUX_TYPE_WDS, QMIWDS_SET_AUTO_CONNECT_REQ, + WdsSetAutoConnect, (void *)&autoconnect_setting); + QmiThreadSendQMI(pRequest, &pResponse); + if (pResponse) + free(pResponse); + } + +//bind v6 client + if(profile->ipv6_flag) + { + IpPreference = IpFamilyV6; + pRequest = ComposeQMUXMsg( + QMUX_TYPE_WDS_IPV6, QMIWDS_SET_CLIENT_IP_FAMILY_PREF_REQ, + WdsSetClientIPFamilyPref, (void *)&IpPreference); + err = QmiThreadSendQMI(pRequest, &pResponse); + qmi_rsp_check_and_return(); + if (pResponse) + free(pResponse); + + if (profile->qmapnet_adapter) { + // bind wds mux data port + pRequest = ComposeQMUXMsg( + QMUX_TYPE_WDS_IPV6, QMIWDS_BIND_MUX_DATA_PORT_REQ, + WdsSetQMUXBindMuxDataPort, (void *)&qmap_settings); + err = QmiThreadSendQMI(pRequest, &pResponse); + qmi_rsp_check_and_return(); + if (pResponse) + free(pResponse); + } + IpPreference = IpFamilyV6; + pRequest = ComposeQMUXMsg( + QMUX_TYPE_WDS_IPV6, QMIWDS_SET_CLIENT_IP_FAMILY_PREF_REQ, + WdsSetClientIPFamilyPref, (void *)&IpPreference); + err = QmiThreadSendQMI(pRequest, &pResponse); + qmi_rsp_check_and_return(); + if (pResponse) + free(pResponse); + +// set auto connect + pRequest = ComposeQMUXMsg(QMUX_TYPE_WDS_IPV6, QMIWDS_SET_AUTO_CONNECT_REQ, + WdsSetAutoConnect, (void *)&autoconnect_setting); + QmiThreadSendQMI(pRequest, &pResponse); + if (pResponse) + free(pResponse); + } + return 0; +} + +#ifdef CONFIG_SIM +int requestGetPINStatus(SIM_Status *pSIMStatus) +{ + PQCQMIMSG pRequest; + PQCQMIMSG pResponse; + PQMUX_MSG pMUXMsg; + int err; + PQMIDMS_UIM_PIN_STATUS pPin1Status = NULL; + // PQMIDMS_UIM_PIN_STATUS pPin2Status = NULL; + + + pRequest = ComposeQMUXMsg(QMUX_TYPE_UIM, QMIUIM_GET_CARD_STATUS_REQ, + NULL, NULL); + + err = QmiThreadSendQMI(pRequest, &pResponse); + qmi_rsp_check_and_return(); + + pPin1Status = + (PQMIDMS_UIM_PIN_STATUS)GetTLV(&pResponse->MUXMsg.QMUXMsgHdr, 0x11); + // pPin2Status = + // (PQMIDMS_UIM_PIN_STATUS)GetTLV(&pResponse->MUXMsg.QMUXMsgHdr, 0x12); + + if (pPin1Status != NULL) { + if (pPin1Status->PINStatus == QMI_PIN_STATUS_NOT_VERIF) { + *pSIMStatus = SIM_PIN; + } else if (pPin1Status->PINStatus == QMI_PIN_STATUS_BLOCKED) { + *pSIMStatus = SIM_PUK; + } else if (pPin1Status->PINStatus == QMI_PIN_STATUS_PERM_BLOCKED) { + *pSIMStatus = SIM_BAD; + } + } + + free(pResponse); + return 0; +} + +static int requestGetSIMMode(PROFILE_T *profile) +{ + int i; + int fd; + int ret; + int len; + char buffer[1024] = {0}; + char *sendbuffer = "AT+GTDUALSIMEN?"; + int totallen = 0; + fd_set readfds; + struct timeval timeout; + struct termios tiosfd, tio; + int timeoutVal = 5; + char *dev = NULL; + if(qmidev_is_gobinet(profile->qmichannel)) + { + dev = "/dev/ttyUSB1"; //The port under Linux is operated by opening the device file + } + else + { + dev = "/dev/mhi_DUN"; //The port under Linux is operated by opening the device file + } + + fd = open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK); + if(fd < 0) + goto ERR; + fcntl(fd, F_SETFL, O_RDWR); + xget1(fd, &tio, &tiosfd); + + if(xset1(fd, &tio, dev)) + goto ERR; + + tcflush(fd, TCIOFLUSH); + + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + + sprintf(buffer, "%s\r", sendbuffer); + ret = write (fd, buffer, strlen(buffer)); + if(ret < 0) + { + dbg_time("write failed\n"); + goto ERR; + } + dbg_time("dev: %s\nsendbuffer:%s\n", dev, sendbuffer); + sleep(3); + + while(1) + { + timeout.tv_sec = timeoutVal; + timeout.tv_usec = 0; + + ret = select(fd+1, &readfds, (fd_set *)0, (fd_set *)0, &timeout); + if(ret > 0) + { + ret = read(fd, buffer+totallen, sizeof(buffer)-totallen-1); + if(ret < 0) + { + dbg_time("read failed\n"); + goto ERR; + } + + if(ret == 0) + { + goto ERR; + } + + totallen += ret; + buffer[totallen] = '\0'; + dbg_time("read %d %s", ret, &buffer[totallen-ret]); + +//current buffer is return value + if(strstr(buffer, "+GTDUALSIMEN: 1")) + { + close(fd); + dbg_time("read 1\n"); + return 1; + } + else + { + close(fd); + dbg_time("read 0/2/3\n"); + return 0; + } + } + else + { + dbg_time("select timeout\n"); + goto ERR; + } + + } + + close(fd); + +ERR: + if(fd > 0) + close(fd); + return -1; +} + + +//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817 +int requestGetSIMCardNumber(PROFILE_T *profile) +{ + int i; + int fd; + int ret; + int len; + char buffer[1024] = {0}; + int rate; + char *sendbuffer; + int totallen = 0; + fd_set readfds; + struct timeval timeout; + struct termios tiosfd, tio; + int timeoutVal = 5; + char *dev = NULL; + if(qmidev_is_gobinet(profile->qmichannel)) + { + dev = "/dev/ttyUSB1"; //The port under Linux is operated by opening the device file + } + else + { + dev = "/dev/mhi_DUN"; //The port under Linux is operated by opening the device file + } + rate = 115200; + sendbuffer = "AT+GTDUALSIM?"; + if(requestGetSIMMode(profile) != 1) + { + return 0; + } + fd = open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK); + if(fd < 0) + goto ERR; + fcntl(fd, F_SETFL, O_RDWR); + xget1(fd, &tio, &tiosfd); + + if(xset1(fd, &tio, dev)) + goto ERR; + + tcflush(fd, TCIOFLUSH); + + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + + sprintf(buffer, "%s\r", sendbuffer); + ret = write (fd, buffer, strlen(buffer)); + if(ret < 0) + { + dbg_time("write failed\n"); + goto ERR; + } + dbg_time("dev: %s\nrate:%d\nsendbuffer:%s\n", dev, rate, sendbuffer); + sleep(3); + goto read_result; + while(1) + { + timeout.tv_sec = timeoutVal; + timeout.tv_usec = 0; + + //ret = select(fd+1, &readfds, (fd_set *)0, (fd_set *)0, &timeout); + //if(ret > 0) + { + read_result: + ret = read(fd, buffer+totallen, sizeof(buffer)-totallen-1); + if(ret < 0) + { + dbg_time("read failed\n"); + goto ERR; + } + + if(ret == 0) + { + goto ERR; + } + + totallen += ret; + buffer[totallen] = '\0'; + dbg_time("read %d %s", ret, &buffer[totallen-ret]); + +//current buffer is return value + if(strstr(buffer, "+GTDUALSIM: 0")) + { + close(fd); + dbg_time("read 0\n"); + return 0; + } + else if(strstr(buffer, "+GTDUALSIM: 1")) + { + close(fd); + dbg_time("read 1\n"); + return 1; + } + else + continue; + } + //else + { + //dbg_time("select timeout\n"); + //goto ERR; + } + + } + + close(fd); + +ERR: + if(fd > 0) + close(fd); + return -1; +} + +int requestSimBindSubscription_NAS_WMS() +{ + PQCQMIMSG pRequest_nas; + PQCQMIMSG pResponse_nas; + int err; + + pRequest_nas = ComposeQMUXMsg(QMUX_TYPE_NAS, QMI_NAS_BIND_SUBSCRIPTION_REQ_V01, + UimBindPinReqSend_NAS_WMS, NULL); + err = QmiThreadSendQMI(pRequest_nas, &pResponse_nas); + free(pResponse_nas); + + return 0; +} + +int requestSimBindSubscription_WDS_DMS_QOS() +{ + PQCQMIMSG pRequest_wds; + PQCQMIMSG pRequest_dms; + + PQCQMIMSG pResponse_wds; + PQCQMIMSG pResponse_dms; + int err; + + pRequest_wds = ComposeQMUXMsg(QMUX_TYPE_WDS, QMI_WDS_BIND_SUBSCRIPTION_REQ_V01, + UimBindPinReqSend_WDS_DMS_QOS, NULL); + err = QmiThreadSendQMI(pRequest_wds, &pResponse_wds); + + pRequest_dms = ComposeQMUXMsg(QMUX_TYPE_DMS, QMI_DMS_BIND_SUBSCRIPTION_REQ_V01, + UimBindPinReqSend_WDS_DMS_QOS, NULL); + err = QmiThreadSendQMI(pRequest_dms, &pResponse_dms); + + free(pResponse_wds); + free(pResponse_dms); + + return 0; +} + +//int requestGetSIMStatus(SIM_Status *pSIMStatus) +int requestGetSIMStatus(SIM_Status *pSIMStatus, const int sim_select) +{ // RIL_REQUEST_GET_SIM_STATUS + int i; + dbg_time("sim_select = %d\n", sim_select); + PQCQMIMSG pRequest; + PQCQMIMSG pResponse; + PQMUX_MSG pMUXMsg; + int err; + const char *SIM_Status_String[] = { + "SIM_ABSENT", + "SIM_NOT_READY", + "SIM_READY", /* SIM_READY means the radio state is RADIO_STATE_SIM_READY + */ + "SIM_PIN", + "SIM_PUK", + "SIM_NETWORK_PERSONALIZATION"}; + + pRequest = ComposeQMUXMsg(QMUX_TYPE_UIM, QMIUIM_GET_CARD_STATUS_REQ, + NULL, NULL); + + err = QmiThreadSendQMI(pRequest, &pResponse); + qmi_rsp_check_and_return(); + + *pSIMStatus = SIM_ABSENT; + PQMIUIM_CARD_STATUS pCardStatus = NULL; + PQMIUIM_PIN_STATE pPINState = NULL; + UCHAR CardState = 0x01; + UCHAR PIN1State = QMI_PIN_STATUS_NOT_VERIF; + // UCHAR PIN1Retries; + // UCHAR PUK1Retries; + // UCHAR PIN2State; + // UCHAR PIN2Retries; + // UCHAR PUK2Retries; + + void *temp = NULL; + QMIUIM_APP_STATUS * curr_app = NULL; + Instance * curr_ints = NULL; + + pCardStatus = + (PQMIUIM_CARD_STATUS)GetTLV(&pResponse->MUXMsg.QMUXMsgHdr, 0x10); + if(sim_select == 0) + { + temp =(void*)pCardStatus + sizeof(QMIUIM_CARD_STATUS); + curr_ints = temp; + dbg_time("curr_ints_sim1 %s", curr_ints); + temp = temp + sizeof(Instance); + curr_app = temp; + } + else + { + temp = (void*)pCardStatus + sizeof(QMIUIM_CARD_STATUS); + temp = temp + sizeof(Instance) + (sizeof(QMIUIM_APP_STATUS)*(((Instance *)temp)->NumApp)); + curr_ints = temp; + dbg_time("curr_ints_sim2 %s", curr_ints); + curr_app = temp + sizeof(Instance); + } +/* + if (pCardStatus != NULL) { + + for (i = 0; i < pCardStatus->NumApp; i++) { + if (pCardStatus->AppStatus[i].AppType == 2) { + pPINState = &(pCardStatus->AppStatus[i].PinState); + break; + } + } + if (i == pCardStatus->NumApp) { + dbg_time("no USIM Card info"); + return -1; + } + + CardState = pCardStatus->CardState; + if (pPINState->UnivPIN == 1) { + PIN1State = pCardStatus->UPINState; +*/ + if (curr_ints != NULL) { + dbg_time("curr_ints->CardState is %d", curr_ints->CardState); + dbg_time("curr_ints->NumApp is %d", curr_ints->NumApp); + for (i = 0; i < curr_ints->NumApp; i++) { + dbg_time("AppType = %d\n", curr_app[i].AppType); + if (curr_app[i].AppType == 2) { + pPINState = &(curr_app[i].PinState); + break; + } + } + if (i == curr_ints->NumApp) { + dbg_time("no USIM Card info"); + return -1; + } + + //CardState = pCardStatus->CardState; + CardState = curr_ints->CardState; + if (pPINState->UnivPIN == 1) { + PIN1State = curr_ints->UPINState; + // PIN1Retries = pCardStatus->UPINRetries; + // PUK1Retries = pCardStatus->UPUKRetries; + } else { + PIN1State = pPINState->PIN1State; + // PIN1Retries = pPINState->PIN1Retries; + // PUK1Retries = pPINState->PUK1Retries; + } + // PIN2State = pPINState->PIN2State; + // PIN2Retries = pPINState->PIN2Retries; + // PUK2Retries = pPINState->PUK2Retries; + } +//2021-03-24 willa.liu@fibocom.com changed end for support mantis 0071817 + *pSIMStatus = SIM_ABSENT; + if ((CardState == 0x01) && ((PIN1State == QMI_PIN_STATUS_VERIFIED) || + (PIN1State == QMI_PIN_STATUS_DISABLED))) { + *pSIMStatus = SIM_READY; + } else if (CardState == 0x01) { + if (PIN1State == QMI_PIN_STATUS_NOT_VERIF) { + *pSIMStatus = SIM_PIN; + } + if (PIN1State == QMI_PIN_STATUS_BLOCKED) { + *pSIMStatus = SIM_PUK; + } else if (PIN1State == QMI_PIN_STATUS_PERM_BLOCKED) { + *pSIMStatus = SIM_BAD; + } else if (PIN1State == QMI_PIN_STATUS_NOT_INIT || + PIN1State == QMI_PIN_STATUS_VERIFIED || + PIN1State == QMI_PIN_STATUS_DISABLED) { + *pSIMStatus = SIM_READY; + } + } else if (CardState == 0x00 || CardState == 0x02) { + } else { + } + + dbg_time("%s SIMStatus: %s", __func__, SIM_Status_String[*pSIMStatus]); + + free(pResponse); + + return 0; +} + +int requestEnterSimPin(const CHAR *pPinCode) +{ + PQCQMIMSG pRequest; + PQCQMIMSG pResponse; + PQMUX_MSG pMUXMsg; + int err; + + pRequest = ComposeQMUXMsg(QMUX_TYPE_UIM, QMIUIM_VERIFY_PIN_REQ, + UimVerifyPinReqSend, (void *)pPinCode); + + err = QmiThreadSendQMI(pRequest, &pResponse); + qmi_rsp_check_and_return(); + + free(pResponse); + return 0; +} + +#ifdef CONFIG_IMSI_ICCID +int requestGetICCID(void) +{ // RIL_REQUEST_GET_IMSI + PQCQMIMSG pRequest; + PQCQMIMSG pResponse; + PQMUX_MSG pMUXMsg; + PQMIUIM_CONTENT pUimContent; + int err; + + pRequest = + ComposeQMUXMsg(QMUX_TYPE_UIM, QMIUIM_READ_TRANSPARENT_REQ, + UimReadTransparentIMSIReqSend, (void *)"EF_ICCID"); + err = QmiThreadSendQMI(pRequest, &pResponse); + + + qmi_rsp_check_and_return(); + + pUimContent = (PQMIUIM_CONTENT)GetTLV(&pResponse->MUXMsg.QMUXMsgHdr, 0x11); + if (pUimContent != NULL) { + static char DeviceICCID[32] = {'\0'}; + int i = 0, j = 0; + + for (i = 0, j = 0; i < le16_to_cpu(pUimContent->content_len); ++i) { + char charmaps[] = "0123456789ABCDEF"; + + DeviceICCID[j++] = charmaps[(pUimContent->content[i] & 0x0F)]; + DeviceICCID[j++] = + charmaps[((pUimContent->content[i] & 0xF0) >> 0x04)]; + } + DeviceICCID[j] = '\0'; + + dbg_time("%s DeviceICCID: %s", __func__, DeviceICCID); + } + + free(pResponse); + return 0; +} + +int requestGetIMSI(void) +{ // RIL_REQUEST_GET_IMSI + PQCQMIMSG pRequest; + PQCQMIMSG pResponse; + PQMUX_MSG pMUXMsg; + PQMIUIM_CONTENT pUimContent; + int err; + + pRequest = + ComposeQMUXMsg(QMUX_TYPE_UIM, QMIUIM_READ_TRANSPARENT_REQ, + UimReadTransparentIMSIReqSend, (void *)"EF_IMSI"); + err = QmiThreadSendQMI(pRequest, &pResponse); + + + qmi_rsp_check_and_return(); + + pUimContent = (PQMIUIM_CONTENT)GetTLV(&pResponse->MUXMsg.QMUXMsgHdr, 0x11); + if (pUimContent != NULL) { + static char DeviceIMSI[32] = {'\0'}; + int i = 0, j = 0; + + for (i = 0, j = 0; i < le16_to_cpu(pUimContent->content[0]); ++i) { + if (i != 0) + DeviceIMSI[j++] = (pUimContent->content[i + 1] & 0x0F) + '0'; + DeviceIMSI[j++] = + ((pUimContent->content[i + 1] & 0xF0) >> 0x04) + '0'; + } + DeviceIMSI[j] = '\0'; + + dbg_time("%s DeviceIMSI: %s", __func__, DeviceIMSI); + } + + free(pResponse); + return 0; +} +#endif +#endif + +static void fibo_convert_cdma_mcc_2_ascii_mcc(USHORT *p_mcc, USHORT mcc) +{ + unsigned int d1, d2, d3, buf = mcc + 111; + + if (mcc == 0x3FF) // wildcard + { + *p_mcc = 3; + } else { + d3 = buf % 10; + buf = (d3 == 0) ? (buf - 10) / 10 : buf / 10; + + d2 = buf % 10; + buf = (d2 == 0) ? (buf - 10) / 10 : buf / 10; + + d1 = (buf == 10) ? 0 : buf; + + // dbg_time("d1:%d, d2:%d,d3:%d",d1,d2,d3); + if (d1 < 10 && d2 < 10 && d3 < 10) { + *p_mcc = d1 * 100 + d2 * 10 + d3; + } else { + // dbg_time( "invalid digits %d %d %d", d1, d2, d3 ); + *p_mcc = 0; + } + } +} + +static void fibo_convert_cdma_mnc_2_ascii_mnc(USHORT *p_mnc, USHORT imsi_11_12) +{ + unsigned int d1, d2, buf = imsi_11_12 + 11; + + if (imsi_11_12 == 0x7F) // wildcard + { + *p_mnc = 7; + } else { + d2 = buf % 10; + buf = (d2 == 0) ? (buf - 10) / 10 : buf / 10; + + d1 = (buf == 10) ? 0 : buf; + + if (d1 < 10 && d2 < 10) { + *p_mnc = d1 * 10 + d2; + } else { + // dbg_time( "invalid digits %d %d", d1, d2, 0 ); + *p_mnc = 0; + } + } +} + +int requestGetHomeNetwork(USHORT *p_mcc, USHORT *p_mnc, USHORT *p_sid, + USHORT *p_nid) +{ + PQCQMIMSG pRequest; + PQCQMIMSG pResponse; + PQMUX_MSG pMUXMsg; + int err; + PHOME_NETWORK pHomeNetwork; + PHOME_NETWORK_SYSTEMID pHomeNetworkSystemID; + + pRequest = + ComposeQMUXMsg(QMUX_TYPE_NAS, QMINAS_GET_HOME_NETWORK_REQ, NULL, NULL); + err = QmiThreadSendQMI(pRequest, &pResponse); + qmi_rsp_check_and_return(); + + pHomeNetwork = (PHOME_NETWORK)GetTLV(&pResponse->MUXMsg.QMUXMsgHdr, 0x01); + if (pHomeNetwork && p_mcc && p_mnc) { + *p_mcc = le16_to_cpu(pHomeNetwork->MobileCountryCode); + *p_mnc = le16_to_cpu(pHomeNetwork->MobileNetworkCode); + // dbg_time("%s MobileCountryCode: %d, MobileNetworkCode: %d", __func__, + // *pMobileCountryCode, *pMobileNetworkCode); + } + + pHomeNetworkSystemID = + (PHOME_NETWORK_SYSTEMID)GetTLV(&pResponse->MUXMsg.QMUXMsgHdr, 0x10); + if (pHomeNetworkSystemID && p_sid && p_nid) { + *p_sid = le16_to_cpu( + pHomeNetworkSystemID->SystemID); // china-hefei: sid 14451 + *p_nid = le16_to_cpu(pHomeNetworkSystemID->NetworkID); + // dbg_time("%s SystemID: %d, NetworkID: %d", __func__, *pSystemID, + // *pNetworkID); + } + + free(pResponse); + + return 0; +} + +struct wwan_data_class_str class2str[] = { + {WWAN_DATA_CLASS_NONE, "UNKNOWN"}, + {WWAN_DATA_CLASS_GPRS, "GPRS"}, + {WWAN_DATA_CLASS_EDGE, "EDGE"}, + {WWAN_DATA_CLASS_UMTS, "UMTS"}, + {WWAN_DATA_CLASS_HSDPA, "HSDPA"}, + {WWAN_DATA_CLASS_HSUPA, "HSUPA"}, + {WWAN_DATA_CLASS_LTE, "LTE"}, + {WWAN_DATA_CLASS_1XRTT, "1XRTT"}, + {WWAN_DATA_CLASS_1XEVDO, "1XEVDO"}, + {WWAN_DATA_CLASS_1XEVDO_REVA, "1XEVDO_REVA"}, + {WWAN_DATA_CLASS_1XEVDV, "1XEVDV"}, + {WWAN_DATA_CLASS_3XRTT, "3XRTT"}, + {WWAN_DATA_CLASS_1XEVDO_REVB, "1XEVDO_REVB"}, + {WWAN_DATA_CLASS_UMB, "UMB"}, + {WWAN_DATA_CLASS_CUSTOM, "CUSTOM"}, +//begin modified by zhangkaibo add 5G network detect feature on x55 platform. 20200605 + {WWAN_DATA_CLASS_5G, "NR5G"}, +//end modified by zhangkaibo add 5G network detect feature on x55 platform. 20200605 +}; + +CHAR *wwan_data_class2str(ULONG class) +{ + unsigned int i = 0; + for (i = 0; i < sizeof(class2str) / sizeof(class2str[0]); i++) { + if (class2str[i].class == class) { + return class2str[i].str; + } + } + return "UNKNOWN"; +} + +int requestRegistrationState2(UCHAR *pPSAttachedState) +{ + PQCQMIMSG pRequest; + PQCQMIMSG pResponse; + PQMUX_MSG pMUXMsg; + int err; + USHORT MobileCountryCode = 0; + USHORT MobileNetworkCode = 0; + const char *pDataCapStr = "UNKNOW"; + LONG remainingLen; + PSERVICE_STATUS_INFO pServiceStatusInfo; + int is_lte = 0; + PCDMA_SYSTEM_INFO pCdmaSystemInfo; + PHDR_SYSTEM_INFO pHdrSystemInfo; + PGSM_SYSTEM_INFO pGsmSystemInfo; + PWCDMA_SYSTEM_INFO pWcdmaSystemInfo; + PLTE_SYSTEM_INFO pLteSystemInfo; +//begin modified by zhangkaibo add 5G network detect feature on x55 platform. 20200605 + PNR5G_SYSTEM_INFO pNr5gSystemInfo; +//end modified by zhangkaibo add 5G network detect feature on x55 platform. 20200605 + PTDSCDMA_SYSTEM_INFO pTdscdmaSystemInfo; + UCHAR DeviceClass = 0; + ULONG DataCapList = 0; + + *pPSAttachedState = 0; + pRequest = + ComposeQMUXMsg(QMUX_TYPE_NAS, QMINAS_GET_SYS_INFO_REQ, NULL, NULL); + err = QmiThreadSendQMI(pRequest, &pResponse); + qmi_rsp_check_and_return(); + + pServiceStatusInfo = (PSERVICE_STATUS_INFO)( + ((PCHAR)&pMUXMsg->GetSysInfoResp) + QCQMUX_MSG_HDR_SIZE); + remainingLen = le16_to_cpu(pMUXMsg->GetSysInfoResp.Length); + + s_is_cdma = 0; + s_hdr_personality = 0; + while (remainingLen > 0) { + switch (pServiceStatusInfo->TLVType) { + case 0x10: // CDMA + if (pServiceStatusInfo->SrvStatus == 0x02) { + DataCapList = WWAN_DATA_CLASS_1XRTT | WWAN_DATA_CLASS_1XEVDO | + WWAN_DATA_CLASS_1XEVDO_REVA | + WWAN_DATA_CLASS_1XEVDV | + WWAN_DATA_CLASS_1XEVDO_REVB; + DeviceClass = DEVICE_CLASS_CDMA; + s_is_cdma = (0 == is_lte); + } + break; + case 0x11: // HDR + if (pServiceStatusInfo->SrvStatus == 0x02) { + DataCapList = WWAN_DATA_CLASS_3XRTT | WWAN_DATA_CLASS_UMB; + DeviceClass = DEVICE_CLASS_CDMA; + s_is_cdma = (0 == is_lte); + } + break; + case 0x12: // GSM + if (pServiceStatusInfo->SrvStatus == 0x02) { + DataCapList = WWAN_DATA_CLASS_GPRS | WWAN_DATA_CLASS_EDGE; + DeviceClass = DEVICE_CLASS_GSM; + } + break; + case 0x13: // WCDMA + if (pServiceStatusInfo->SrvStatus == 0x02) { + DataCapList = WWAN_DATA_CLASS_UMTS; + DeviceClass = DEVICE_CLASS_GSM; + } + break; +//begin modified by zhangkaibo add 5G network detect feature on x55 platform. 20200605 + case 0x4A: // NR5G + if (pServiceStatusInfo->SrvStatus == 0x02) { + DataCapList = WWAN_DATA_CLASS_5G; + DeviceClass = DEVICE_CLASS_GSM; + is_lte = 1; + s_is_cdma = 0; + } + break; +//end modified by zhangkaibo add 5G network detect feature on x55 platform. 20200605 + case 0x14: // LTE + if (pServiceStatusInfo->SrvStatus == 0x02) { + DataCapList = WWAN_DATA_CLASS_LTE; + DeviceClass = DEVICE_CLASS_GSM; + is_lte = 1; + s_is_cdma = 0; + } + break; + case 0x24: // TDSCDMA + if (pServiceStatusInfo->SrvStatus == 0x02) { + pDataCapStr = "TD-SCDMA"; + } + break; + case 0x15: // CDMA + // CDMA_SYSTEM_INFO + pCdmaSystemInfo = (PCDMA_SYSTEM_INFO)pServiceStatusInfo; + if (pCdmaSystemInfo->SrvDomainValid == 0x01) { + *pPSAttachedState = 0; + if (pCdmaSystemInfo->SrvDomain & 0x02) { + *pPSAttachedState = 1; + s_is_cdma = (0 == is_lte); + } + } +#if 0 + if (pCdmaSystemInfo->SrvCapabilityValid == 0x01) { + *pPSAttachedState = 0; + if (pCdmaSystemInfo->SrvCapability & 0x02) { + *pPSAttachedState = 1; + s_is_cdma = (0 == is_lte); + } + } +#endif + if (pCdmaSystemInfo->NetworkIdValid == 0x01) { + int i; + CHAR temp[10]; + strncpy(temp, (CHAR *)pCdmaSystemInfo->MCC, 3); + temp[3] = '\0'; + for (i = 0; i < 4; i++) { + if ((UCHAR)temp[i] == 0xFF) { + temp[i] = '\0'; + } + } + MobileCountryCode = (USHORT)atoi(temp); + + strncpy(temp, (CHAR *)pCdmaSystemInfo->MNC, 3); + temp[3] = '\0'; + for (i = 0; i < 4; i++) { + if ((UCHAR)temp[i] == 0xFF) { + temp[i] = '\0'; + } + } + MobileNetworkCode = (USHORT)atoi(temp); + } + break; + case 0x16: // HDR + // HDR_SYSTEM_INFO + pHdrSystemInfo = (PHDR_SYSTEM_INFO)pServiceStatusInfo; + if (pHdrSystemInfo->SrvDomainValid == 0x01) { + *pPSAttachedState = 0; + if (pHdrSystemInfo->SrvDomain & 0x02) { + *pPSAttachedState = 1; + s_is_cdma = (0 == is_lte); + } + } +#if 0 + if (pHdrSystemInfo->SrvCapabilityValid == 0x01) { + *pPSAttachedState = 0; + if (pHdrSystemInfo->SrvCapability & 0x02) { + *pPSAttachedState = 1; + s_is_cdma = (0 == is_lte); + } + } +#endif + if (*pPSAttachedState && + pHdrSystemInfo->HdrPersonalityValid == 0x01) { + if (pHdrSystemInfo->HdrPersonality == 0x03) + s_hdr_personality = 0x02; + // else if (pHdrSystemInfo->HdrPersonality == 0x02) + // s_hdr_personality = 0x01; + } + USHORT cmda_mcc = 0, cdma_mnc = 0; + if (!requestGetHomeNetwork(&cmda_mcc, &cdma_mnc, NULL, NULL) && + cmda_mcc) { + fibo_convert_cdma_mcc_2_ascii_mcc(&MobileCountryCode, cmda_mcc); + fibo_convert_cdma_mnc_2_ascii_mnc(&MobileNetworkCode, cdma_mnc); + } + break; + case 0x17: // GSM + // GSM_SYSTEM_INFO + pGsmSystemInfo = (PGSM_SYSTEM_INFO)pServiceStatusInfo; + if (pGsmSystemInfo->SrvDomainValid == 0x01) { + *pPSAttachedState = 0; + if (pGsmSystemInfo->SrvDomain & 0x02) { + *pPSAttachedState = 1; + } + } +#if 0 + if (pGsmSystemInfo->SrvCapabilityValid == 0x01) { + *pPSAttachedState = 0; + if (pGsmSystemInfo->SrvCapability & 0x02) { + *pPSAttachedState = 1; + } + } +#endif + if (pGsmSystemInfo->NetworkIdValid == 0x01) { + int i; + CHAR temp[10]; + strncpy(temp, (CHAR *)pGsmSystemInfo->MCC, 3); + temp[3] = '\0'; + for (i = 0; i < 4; i++) { + if ((UCHAR)temp[i] == 0xFF) { + temp[i] = '\0'; + } + } + MobileCountryCode = (USHORT)atoi(temp); + + strncpy(temp, (CHAR *)pGsmSystemInfo->MNC, 3); + temp[3] = '\0'; + for (i = 0; i < 4; i++) { + if ((UCHAR)temp[i] == 0xFF) { + temp[i] = '\0'; + } + } + MobileNetworkCode = (USHORT)atoi(temp); + } + break; + case 0x18: // WCDMA + // WCDMA_SYSTEM_INFO + pWcdmaSystemInfo = (PWCDMA_SYSTEM_INFO)pServiceStatusInfo; + if (pWcdmaSystemInfo->SrvDomainValid == 0x01) { + *pPSAttachedState = 0; + if (pWcdmaSystemInfo->SrvDomain & 0x02) { + *pPSAttachedState = 1; + } + } +#if 0 + if (pWcdmaSystemInfo->SrvCapabilityValid == 0x01) { + *pPSAttachedState = 0; + if (pWcdmaSystemInfo->SrvCapability & 0x02) { + *pPSAttachedState = 1; + } + } +#endif + if (pWcdmaSystemInfo->NetworkIdValid == 0x01) { + int i; + CHAR temp[10]; + strncpy(temp, (CHAR *)pWcdmaSystemInfo->MCC, 3); + temp[3] = '\0'; + for (i = 0; i < 4; i++) { + if ((UCHAR)temp[i] == 0xFF) { + temp[i] = '\0'; + } + } + MobileCountryCode = (USHORT)atoi(temp); + + strncpy(temp, (CHAR *)pWcdmaSystemInfo->MNC, 3); + temp[3] = '\0'; + for (i = 0; i < 4; i++) { + if ((UCHAR)temp[i] == 0xFF) { + temp[i] = '\0'; + } + } + MobileNetworkCode = (USHORT)atoi(temp); + } + break; + case 0x19: // LTE_SYSTEM_INFO + // LTE_SYSTEM_INFO + pLteSystemInfo = (PLTE_SYSTEM_INFO)pServiceStatusInfo; + if (pLteSystemInfo->SrvDomainValid == 0x01) { + *pPSAttachedState = 0; + if (pLteSystemInfo->SrvDomain & 0x02) { + *pPSAttachedState = 1; + is_lte = 1; + s_is_cdma = 0; + } + } +#if 0 + if (pLteSystemInfo->SrvCapabilityValid == 0x01) { + *pPSAttachedState = 0; + if (pLteSystemInfo->SrvCapability & 0x02) { + *pPSAttachedState = 1; + is_lte = 1; + s_is_cdma = 0; + } + } +#endif + if (pLteSystemInfo->NetworkIdValid == 0x01) { + int i; + CHAR temp[10]; + strncpy(temp, (CHAR *)pLteSystemInfo->MCC, 3); + temp[3] = '\0'; + for (i = 0; i < 4; i++) { + if ((UCHAR)temp[i] == 0xFF) { + temp[i] = '\0'; + } + } + MobileCountryCode = (USHORT)atoi(temp); + + strncpy(temp, (CHAR *)pLteSystemInfo->MNC, 3); + temp[3] = '\0'; + for (i = 0; i < 4; i++) { + if ((UCHAR)temp[i] == 0xFF) { + temp[i] = '\0'; + } + } + MobileNetworkCode = (USHORT)atoi(temp); + } + break; +//begin modified by zhangkaibo add 5G network detect feature on x55 platform. 20200605 + case 0x4b: // NR5G_SYSTEM_INFO + // NR5G_SYSTEM_INFO + pNr5gSystemInfo = (PNR5G_SYSTEM_INFO)pServiceStatusInfo; + if (pNr5gSystemInfo->SrvDomainValid == 0x01) { + *pPSAttachedState = 0; + if (pNr5gSystemInfo->SrvDomain & 0x02) { + *pPSAttachedState = 1; + is_lte = 1; + s_is_cdma = 0; + } + } + + if (pNr5gSystemInfo->NetworkIdValid == 0x01) { + int i; + CHAR temp[10]; + strncpy(temp, (CHAR *)pNr5gSystemInfo->MCC, 3); + temp[3] = '\0'; + for (i = 0; i < 4; i++) { + if ((UCHAR)temp[i] == 0xFF) { + temp[i] = '\0'; + } + } + MobileCountryCode = (USHORT)atoi(temp); + + strncpy(temp, (CHAR *)pNr5gSystemInfo->MNC, 3); + temp[3] = '\0'; + for (i = 0; i < 4; i++) { + if ((UCHAR)temp[i] == 0xFF) { + temp[i] = '\0'; + } + } + MobileNetworkCode = (USHORT)atoi(temp); + } + break; +//end modified by zhangkaibo add 5G network detect feature on x55 platform. 20200605 + case 0x25: // TDSCDMA + // TDSCDMA_SYSTEM_INFO + pTdscdmaSystemInfo = (PTDSCDMA_SYSTEM_INFO)pServiceStatusInfo; + if (pTdscdmaSystemInfo->SrvDomainValid == 0x01) { + *pPSAttachedState = 0; + if (pTdscdmaSystemInfo->SrvDomain & 0x02) { + *pPSAttachedState = 1; + } + } +#if 0 + if (pTdscdmaSystemInfo->SrvCapabilityValid == 0x01) { + *pPSAttachedState = 0; + if (pTdscdmaSystemInfo->SrvCapability & 0x02) { + *pPSAttachedState = 1; + } + } +#endif + if (pTdscdmaSystemInfo->NetworkIdValid == 0x01) { + int i; + CHAR temp[10]; + strncpy(temp, (CHAR *)pTdscdmaSystemInfo->MCC, 3); + temp[3] = '\0'; + for (i = 0; i < 4; i++) { + if ((UCHAR)temp[i] == 0xFF) { + temp[i] = '\0'; + } + } + MobileCountryCode = (USHORT)atoi(temp); + + strncpy(temp, (CHAR *)pTdscdmaSystemInfo->MNC, 3); + temp[3] = '\0'; + for (i = 0; i < 4; i++) { + if ((UCHAR)temp[i] == 0xFF) { + temp[i] = '\0'; + } + } + MobileNetworkCode = (USHORT)atoi(temp); + } + break; + default: + break; + } /* switch (pServiceStatusInfo->TLYType) */ + remainingLen -= (le16_to_cpu(pServiceStatusInfo->TLVLength) + 3); + pServiceStatusInfo = (PSERVICE_STATUS_INFO)( + (PCHAR)&pServiceStatusInfo->TLVLength + + le16_to_cpu(pServiceStatusInfo->TLVLength) + sizeof(USHORT)); + } /* while (remainingLen > 0) */ + + if (DeviceClass == DEVICE_CLASS_CDMA) { + if (s_hdr_personality == 2) { + pDataCapStr = s_hdr_personality == 2 ? "eHRPD" : "HRPD"; + } else if (DataCapList & WWAN_DATA_CLASS_1XEVDO_REVB) { + pDataCapStr = wwan_data_class2str(WWAN_DATA_CLASS_1XEVDO_REVB); + } else if (DataCapList & WWAN_DATA_CLASS_1XEVDO_REVA) { + pDataCapStr = wwan_data_class2str(WWAN_DATA_CLASS_1XEVDO_REVA); + } else if (DataCapList & WWAN_DATA_CLASS_1XEVDO) { + pDataCapStr = wwan_data_class2str(WWAN_DATA_CLASS_1XEVDO); + } else if (DataCapList & WWAN_DATA_CLASS_1XRTT) { + pDataCapStr = wwan_data_class2str(WWAN_DATA_CLASS_1XRTT); + } else if (DataCapList & WWAN_DATA_CLASS_3XRTT) { + pDataCapStr = wwan_data_class2str(WWAN_DATA_CLASS_3XRTT); + } else if (DataCapList & WWAN_DATA_CLASS_UMB) { + pDataCapStr = wwan_data_class2str(WWAN_DATA_CLASS_UMB); + } + } else { + if (DataCapList & WWAN_DATA_CLASS_LTE) { + pDataCapStr = wwan_data_class2str(WWAN_DATA_CLASS_LTE); + } else if ((DataCapList & WWAN_DATA_CLASS_HSDPA) && + (DataCapList & WWAN_DATA_CLASS_HSUPA)) { + pDataCapStr = "HSDPA_HSUPA"; + } else if (DataCapList & WWAN_DATA_CLASS_HSDPA) { + pDataCapStr = wwan_data_class2str(WWAN_DATA_CLASS_HSDPA); + } else if (DataCapList & WWAN_DATA_CLASS_HSUPA) { + pDataCapStr = wwan_data_class2str(WWAN_DATA_CLASS_HSUPA); + } else if (DataCapList & WWAN_DATA_CLASS_UMTS) { + pDataCapStr = wwan_data_class2str(WWAN_DATA_CLASS_UMTS); + } else if (DataCapList & WWAN_DATA_CLASS_EDGE) { + pDataCapStr = wwan_data_class2str(WWAN_DATA_CLASS_EDGE); + } else if (DataCapList & WWAN_DATA_CLASS_GPRS) { + pDataCapStr = wwan_data_class2str(WWAN_DATA_CLASS_GPRS); +//begin modified by zhangkaibo add 5G network detect feature on x55 platform. 20200605 + } else if (DataCapList & WWAN_DATA_CLASS_5G) { + pDataCapStr = wwan_data_class2str(WWAN_DATA_CLASS_5G); +//end modified by zhangkaibo add 5G network detect feature on x55 platform. 20200605 + } + } + g_MobileCountryCode = MobileCountryCode; + g_MobileNetworkCode = MobileNetworkCode; + dbg_time("%s MCC: %d, MNC: %d, PS: %s, DataCap: %s", __func__, + MobileCountryCode, MobileNetworkCode, + (*pPSAttachedState == 1) ? "Attached" : "Detached", pDataCapStr); + + free(pResponse); + + return 0; +} + +int requestRegistrationState(UCHAR *pPSAttachedState) +{ + PQCQMIMSG pRequest; + PQCQMIMSG pResponse; + PQMUX_MSG pMUXMsg; + int err; + PQMINAS_CURRENT_PLMN_MSG pCurrentPlmn; + PSERVING_SYSTEM pServingSystem; + PQMINAS_DATA_CAP pDataCap; + USHORT MobileCountryCode = 0; + USHORT MobileNetworkCode = 0; + const char *pDataCapStr = "UNKNOW"; +//begin modified by zhangkaibo add 5G network detect feature on x55 platform. 20200605 + /* + for 9x07 later, QMINAS_GET_SERVING_SYSTEM_REQ has been declara as Deprecated + so sdx55 NR5G register info can not get by QMINAS_GET_SERVING_SYSTEM_REQ. + coninue use QMINAS_GET_SERVING_SYSTEM_REQ, fibocom-dial will show network as UNKNOWN + */ + //begin modified by zhaofei delete incorrect registration interface on x55/x24 platform. 20200603 +// #if 0 +// if (s_9x07) { +//eturn requestRegistrationState2(pPSAttachedState); +// } +// #endif + //end modified by zhaofei delete incorrect registration interface on x55/x24 platform.20200603 +//begin modified by zhangkaibo add 5G network detect feature on x55 platform. 20200605 + pRequest = ComposeQMUXMsg(QMUX_TYPE_NAS, QMINAS_GET_SERVING_SYSTEM_REQ, + NULL, NULL); + err = QmiThreadSendQMI(pRequest, &pResponse); + qmi_rsp_check_and_return(); + + pCurrentPlmn = + (PQMINAS_CURRENT_PLMN_MSG)GetTLV(&pResponse->MUXMsg.QMUXMsgHdr, 0x12); + if (pCurrentPlmn) { + MobileCountryCode = le16_to_cpu(pCurrentPlmn->MobileCountryCode); + MobileNetworkCode = le16_to_cpu(pCurrentPlmn->MobileNetworkCode); + } + + *pPSAttachedState = 0; + pServingSystem = + (PSERVING_SYSTEM)GetTLV(&pResponse->MUXMsg.QMUXMsgHdr, 0x01); + if (pServingSystem) { + // Packet-switched domain attach state of the mobile. + // 0x00 PS_UNKNOWN ?Unknown or not applicable + // 0x01 PS_ATTACHED ?Attached + // 0x02 PS_DETACHED ?Detached + *pPSAttachedState = pServingSystem->RegistrationState; + if (pServingSystem->RegistrationState == + 0x01) // 0x01 ?C REGISTERED ?C Registered with a network + *pPSAttachedState = pServingSystem->PSAttachedState; + else { + // MobileCountryCode = MobileNetworkCode = 0; + *pPSAttachedState = 0x02; + } + } + + pDataCap = (PQMINAS_DATA_CAP)GetTLV(&pResponse->MUXMsg.QMUXMsgHdr, 0x11); + if (pDataCap && pDataCap->DataCapListLen) { + UCHAR *DataCap = &pDataCap->DataCap; + if (pDataCap->DataCapListLen == 2) { + if ((DataCap[0] == 0x06) && + ((DataCap[1] == 0x08) || (DataCap[1] == 0x0A))) + DataCap[0] = DataCap[1]; + } + switch (DataCap[0]) { + case 0x01: + pDataCapStr = "GPRS"; + break; + case 0x02: + pDataCapStr = "EDGE"; + break; + case 0x03: + pDataCapStr = "HSDPA"; + break; + case 0x04: + pDataCapStr = "HSUPA"; + break; + case 0x05: + pDataCapStr = "UMTS"; + break; + case 0x06: + pDataCapStr = "1XRTT"; + break; + case 0x07: + pDataCapStr = "1XEVDO"; + break; + case 0x08: + pDataCapStr = "1XEVDO_REVA"; + break; + case 0x09: + pDataCapStr = "GPRS"; + break; + case 0x0A: + pDataCapStr = "1XEVDO_REVB"; + break; + case 0x0B: + pDataCapStr = "LTE"; + break; + case 0x0C: + pDataCapStr = "HSDPA"; + break; + case 0x0D: + pDataCapStr = "HSDPA"; + break; + default: + pDataCapStr = "UNKNOW"; + break; + } + } + + if (pServingSystem && pServingSystem->RegistrationState == 0x01 && + pServingSystem->InUseRadioIF && pServingSystem->RadioIF == 0x09) { + pDataCapStr = "TD-SCDMA"; + } + + s_is_cdma = 0; + if (pServingSystem && pServingSystem->RegistrationState == 0x01 && + pServingSystem->InUseRadioIF && + (pServingSystem->RadioIF == 0x01 || pServingSystem->RadioIF == 0x02)) { + USHORT cmda_mcc = 0, cdma_mnc = 0; + s_is_cdma = 1; + if (!requestGetHomeNetwork(&cmda_mcc, &cdma_mnc, NULL, NULL) && + cmda_mcc) { + fibo_convert_cdma_mcc_2_ascii_mcc(&MobileCountryCode, cmda_mcc); + fibo_convert_cdma_mnc_2_ascii_mnc(&MobileNetworkCode, cdma_mnc); + } + if (1) { + PQCQMUX_TLV pTLV = + (PQCQMUX_TLV)GetTLV(&pResponse->MUXMsg.QMUXMsgHdr, 0x23); + if (pTLV) + s_hdr_personality = pTLV->Value; + else + s_hdr_personality = 0; + if (s_hdr_personality == 2) + pDataCapStr = "eHRPD"; + } + } + + dbg_time("%s MCC: %d, MNC: %d, PS: %s, DataCap: %s", __func__, + MobileCountryCode, MobileNetworkCode, + (*pPSAttachedState == 1) ? "Attached" : "Detached", pDataCapStr); + + free(pResponse); + + return 0; +} + +int requestQueryDataCall(UCHAR *pConnectionStatus, int curIpFamily) +{ + PQCQMIMSG pRequest; + PQCQMIMSG pResponse; + PQMUX_MSG pMUXMsg; + int err; + PQMIWDS_PKT_SRVC_TLV pPktSrvc; + UCHAR oldConnectionStatus = *pConnectionStatus; + UCHAR QMIType = + (curIpFamily == IpFamilyV4) ? QMUX_TYPE_WDS : QMUX_TYPE_WDS_IPV6; + + pRequest = + ComposeQMUXMsg(QMIType, QMIWDS_GET_PKT_SRVC_STATUS_REQ, NULL, NULL); + err = QmiThreadSendQMI(pRequest, &pResponse); + qmi_rsp_check_and_return(); + + *pConnectionStatus = QWDS_PKT_DATA_DISCONNECTED; + pPktSrvc = + (PQMIWDS_PKT_SRVC_TLV)GetTLV(&pResponse->MUXMsg.QMUXMsgHdr, 0x01); + if (pPktSrvc) { + *pConnectionStatus = pPktSrvc->ConnectionStatus; + if ((le16_to_cpu(pPktSrvc->TLVLength) == 2) && + (pPktSrvc->ReconfigReqd == 0x01)) + *pConnectionStatus = QWDS_PKT_DATA_DISCONNECTED; + } + + if (*pConnectionStatus == QWDS_PKT_DATA_DISCONNECTED) { + if (curIpFamily == IpFamilyV4) + WdsConnectionIPv4Handle = 0; + else + WdsConnectionIPv6Handle = 0; + } + + if (oldConnectionStatus != *pConnectionStatus || debug_qmi) { + dbg_time("%s %sConnectionStatus: %s", __func__, + (curIpFamily == IpFamilyV4) ? "IPv4" : "IPv6", + (*pConnectionStatus == QWDS_PKT_DATA_CONNECTED) + ? "CONNECTED" + : "DISCONNECTED"); + } + + free(pResponse); + return 0; +} + +int requestSetupDataCall(PROFILE_T *profile, int curIpFamily) +{ + PQCQMIMSG pRequest; + PQCQMIMSG pResponse; + PQMUX_MSG pMUXMsg; + int err = 0; + UCHAR QMIType = + (curIpFamily == IpFamilyV4) ? QMUX_TYPE_WDS : QMUX_TYPE_WDS_IPV6; + + // DualIPSupported means can get ipv4 & ipv6 address at the same time, one + // wds for ipv4, the other wds for ipv6 + profile->curIpFamily = curIpFamily; + pRequest = ComposeQMUXMsg(QMIType, QMIWDS_START_NETWORK_INTERFACE_REQ, + WdsStartNwInterfaceReq, profile); + err = QmiThreadSendQMITimeout(pRequest, &pResponse, 120 * 1000); + qmi_rsp_check(); + + if (le16_to_cpu(pMUXMsg->QMUXMsgHdrResp.QMUXResult) || + le16_to_cpu(pMUXMsg->QMUXMsgHdrResp.QMUXError)) { + PQMI_TLV_HDR pTLVHdr; + + pTLVHdr = GetTLV(&pResponse->MUXMsg.QMUXMsgHdr, 0x10); + if (pTLVHdr) { + uint16_t *data16 = (uint16_t *)(pTLVHdr + 1); + uint16_t call_end_reason = le16_to_cpu(data16[0]); + dbg_time("call_end_reason is %d", call_end_reason); + } + + pTLVHdr = GetTLV(&pResponse->MUXMsg.QMUXMsgHdr, 0x11); + if (pTLVHdr) { + uint16_t *data16 = (uint16_t *)(pTLVHdr + 1); + uint16_t call_end_reason_type = le16_to_cpu(data16[0]); + uint16_t verbose_call_end_reason = le16_to_cpu(data16[1]); + + dbg_time("call_end_reason_type is %d", call_end_reason_type); + dbg_time("call_end_reason_verbose is %d", verbose_call_end_reason); + } + + free(pResponse); + return le16_to_cpu(pMUXMsg->QMUXMsgHdrResp.QMUXError); + } + + if (curIpFamily == IpFamilyV4) { + WdsConnectionIPv4Handle = + le32_to_cpu(pResponse->MUXMsg.StartNwInterfaceResp.Handle); + dbg_time("%s WdsConnectionIPv4Handle: 0x%08x", __func__, + WdsConnectionIPv4Handle); + } else { + WdsConnectionIPv6Handle = + le32_to_cpu(pResponse->MUXMsg.StartNwInterfaceResp.Handle); + dbg_time("%s WdsConnectionIPv6Handle: 0x%08x", __func__, + WdsConnectionIPv6Handle); + } + + free(pResponse); + + return 0; +} + +int requestDeactivateDefaultPDP(PROFILE_T *profile, int curIpFamily) +{ + PQCQMIMSG pRequest; + PQCQMIMSG pResponse; + PQMUX_MSG pMUXMsg; + int err; + UCHAR QMIType = (curIpFamily == 0x04) ? QMUX_TYPE_WDS : QMUX_TYPE_WDS_IPV6; + + if (curIpFamily == IpFamilyV4 && WdsConnectionIPv4Handle == 0) + return 0; + if (curIpFamily == IpFamilyV6 && WdsConnectionIPv6Handle == 0) + return 0; + + pRequest = ComposeQMUXMsg(QMIType, QMIWDS_STOP_NETWORK_INTERFACE_REQ, + WdsStopNwInterfaceReq, &curIpFamily); + err = QmiThreadSendQMI(pRequest, &pResponse); + qmi_rsp_check_and_return(); + + if (curIpFamily == IpFamilyV4) + WdsConnectionIPv4Handle = 0; + else + WdsConnectionIPv6Handle = 0; + free(pResponse); + return 0; +} + +int requestGetIPAddress(PROFILE_T *profile, int curIpFamily) +{ + PQCQMIMSG pRequest; + PQCQMIMSG pResponse; + PQMUX_MSG pMUXMsg; + int err; + PQMIWDS_GET_RUNTIME_SETTINGS_TLV_IPV4_ADDR pIpv4Addr; + PQMIWDS_GET_RUNTIME_SETTINGS_TLV_IPV6_ADDR pIpv6Addr = NULL; + PQMIWDS_GET_RUNTIME_SETTINGS_TLV_IPV6_DNS_ADDR pIpv6DNSAddr = NULL; + PQMIWDS_GET_RUNTIME_SETTINGS_TLV_MTU pMtu; + IPV4_T *pIpv4 = &profile->ipv4; + IPV6_T *pIpv6 = &profile->ipv6; + UCHAR QMIType = (curIpFamily == 0x04) ? QMUX_TYPE_WDS : QMUX_TYPE_WDS_IPV6; + + if (curIpFamily == IpFamilyV4) { + memset(pIpv4, 0x00, sizeof(IPV4_T)); + if (WdsConnectionIPv4Handle == 0) + return 0; + } else if (curIpFamily == IpFamilyV6) { + memset(pIpv6, 0x00, sizeof(IPV6_T)); + if (WdsConnectionIPv6Handle == 0) + return 0; + } + + pRequest = ComposeQMUXMsg(QMIType, QMIWDS_GET_RUNTIME_SETTINGS_REQ, + WdsGetRuntimeSettingReq, NULL); + err = QmiThreadSendQMI(pRequest, &pResponse); + qmi_rsp_check_and_return(); + + pIpv4Addr = (PQMIWDS_GET_RUNTIME_SETTINGS_TLV_IPV4_ADDR)GetTLV( + &pResponse->MUXMsg.QMUXMsgHdr, + QMIWDS_GET_RUNTIME_SETTINGS_TLV_TYPE_IPV4PRIMARYDNS); + if (pIpv4Addr) { + pIpv4->DnsPrimary = pIpv4Addr->IPV4Address; + } + + pIpv4Addr = (PQMIWDS_GET_RUNTIME_SETTINGS_TLV_IPV4_ADDR)GetTLV( + &pResponse->MUXMsg.QMUXMsgHdr, + QMIWDS_GET_RUNTIME_SETTINGS_TLV_TYPE_IPV4SECONDARYDNS); + if (pIpv4Addr) { + pIpv4->DnsSecondary = pIpv4Addr->IPV4Address; + } + + pIpv4Addr = (PQMIWDS_GET_RUNTIME_SETTINGS_TLV_IPV4_ADDR)GetTLV( + &pResponse->MUXMsg.QMUXMsgHdr, + QMIWDS_GET_RUNTIME_SETTINGS_TLV_TYPE_IPV4GATEWAY); + if (pIpv4Addr) { + pIpv4->Gateway = pIpv4Addr->IPV4Address; + } + + pIpv4Addr = (PQMIWDS_GET_RUNTIME_SETTINGS_TLV_IPV4_ADDR)GetTLV( + &pResponse->MUXMsg.QMUXMsgHdr, + QMIWDS_GET_RUNTIME_SETTINGS_TLV_TYPE_IPV4SUBNET); + if (pIpv4Addr) { + pIpv4->SubnetMask = pIpv4Addr->IPV4Address; + } + + pIpv4Addr = (PQMIWDS_GET_RUNTIME_SETTINGS_TLV_IPV4_ADDR)GetTLV( + &pResponse->MUXMsg.QMUXMsgHdr, + QMIWDS_GET_RUNTIME_SETTINGS_TLV_TYPE_IPV4); + if (pIpv4Addr) { + pIpv4->Address = pIpv4Addr->IPV4Address; + } + + pIpv6DNSAddr = (PQMIWDS_GET_RUNTIME_SETTINGS_TLV_IPV6_DNS_ADDR)GetTLV( + &pResponse->MUXMsg.QMUXMsgHdr, + QMIWDS_GET_RUNTIME_SETTINGS_TLV_TYPE_IPV6PRIMARYDNS); + if (pIpv6DNSAddr) { + memcpy(pIpv6->DnsPrimary, pIpv6DNSAddr->IPV6Address, 16); + } + + pIpv6DNSAddr = (PQMIWDS_GET_RUNTIME_SETTINGS_TLV_IPV6_DNS_ADDR)GetTLV( + &pResponse->MUXMsg.QMUXMsgHdr, + QMIWDS_GET_RUNTIME_SETTINGS_TLV_TYPE_IPV6SECONDARYDNS); + if (pIpv6DNSAddr) { + memcpy(pIpv6->DnsSecondary, pIpv6DNSAddr->IPV6Address, 16); + } + +//2021-02-25 willa.liu@fibocom.com changed begin for support eipd SN-20210129001 + +/* + pIpv6Addr = (PQMIWDS_GET_RUNTIME_SETTINGS_TLV_IPV6_ADDR)GetTLV( + &pResponse->MUXMsg.QMUXMsgHdr, + QMIWDS_GET_RUNTIME_SETTINGS_TLV_TYPE_IPV6GATEWAY); + if(pIpv6Addr) { + memcpy(pIpv6->Gateway, pIpv6Addr->IPV6Address, 16); + pIpv6->PrefixLengthGateway = pIpv6Addr->PrefixLength; + } +*/ + + if(profile->ipv6_prigateway_flag == 1) + { + char localip6gateway[1024] = {0}; + get_private_gateway(localip6gateway); + int length = sizeof(localip6gateway)/sizeof(localip6gateway[0]); + if (pIpv6Addr) + { + int i = 0; + char *token = strtok(localip6gateway, "."); + while(token != NULL) + { + pIpv6->Gateway[i++] = atoi(token); + //printf("token:%s, pIpv6->Gateway[%d]:%d\n", token, i-1, pIpv6->Gateway[i-1]); + token = strtok(NULL, "."); + } + pIpv6->PrefixLengthGateway = 16; + } + } + else + { + pIpv6Addr = (PQMIWDS_GET_RUNTIME_SETTINGS_TLV_IPV6_ADDR)GetTLV( + &pResponse->MUXMsg.QMUXMsgHdr, + QMIWDS_GET_RUNTIME_SETTINGS_TLV_TYPE_IPV6GATEWAY); + if(pIpv6Addr) + { + memcpy(pIpv6->Gateway, pIpv6Addr->IPV6Address, 16); + pIpv6->PrefixLengthGateway = pIpv6Addr->PrefixLength; + } + } +//2021-02-25 willa.liu@fibocom.com changed end for support eipd SN-20210129001 + + + pIpv6Addr = (PQMIWDS_GET_RUNTIME_SETTINGS_TLV_IPV6_ADDR)GetTLV( + &pResponse->MUXMsg.QMUXMsgHdr, + QMIWDS_GET_RUNTIME_SETTINGS_TLV_TYPE_IPV6); + if (pIpv6Addr) { + memcpy(pIpv6->Address, pIpv6Addr->IPV6Address, 16); + pIpv6->PrefixLengthIPAddr = pIpv6Addr->PrefixLength; + } + + pMtu = (PQMIWDS_GET_RUNTIME_SETTINGS_TLV_MTU)GetTLV( + &pResponse->MUXMsg.QMUXMsgHdr, + QMIWDS_GET_RUNTIME_SETTINGS_TLV_TYPE_MTU); + if (pMtu) { + pIpv4->Mtu = pIpv6->Mtu = le32_to_cpu(pMtu->Mtu); + } + + free(pResponse); + return 0; +} + +#ifdef CONFIG_APN +int requestSetProfile(PROFILE_T *profile) +{ + PQCQMIMSG pRequest; + PQCQMIMSG pResponse; + PQMUX_MSG pMUXMsg; + int err; + + if (!profile->pdp) + return 0; + + dbg_time("%s[%d] %s/%s/%s/%d", __func__, profile->pdpindex, profile->apn, + profile->user, profile->password, profile->auth); + + UCHAR QMIType = (profile->ipv4_flag) ? QMUX_TYPE_WDS : QMUX_TYPE_WDS_IPV6; + pRequest = ComposeQMUXMsg(QMIType, QMIWDS_MODIFY_PROFILE_SETTINGS_REQ, + WdsModifyProfileSettingsReq, profile); + err = QmiThreadSendQMI(pRequest, &pResponse); +//begin modified by zhangkaibo add create profile qmi. mantis 0049137,0048741 20200610 + //modify profile no check return value, try create + qmi_rsp_check(); + if(le16_to_cpu(pMUXMsg->QMUXMsgHdrResp.QMUXError)) + { + pRequest = ComposeQMUXMsg(QMIType, QMIWDS_CREATE_PROFILE_SETTINGS_REQ, + WdsCreateProfileSettingsReq, profile); + err = QmiThreadSendQMI(pRequest, &pResponse); + qmi_rsp_check(); + if(le16_to_cpu(pMUXMsg->QMUXMsgHdrResp.QMUXError)){ + free(pResponse); + return -1; + } + dbg_time("WdsCreateProfileSettingsReq[%d] %s/%s/%s/%d", profile->pdpindex, profile->apn, + profile->user, profile->password, profile->auth); + } +//end modified by zhangkaibo add create profile qmi. mantis 0049137,0048741 20200610 + free(pResponse); + return 0; +} + +int requestGetProfile(PROFILE_T *profile) +{ + PQCQMIMSG pRequest; + PQCQMIMSG pResponse; + PQMUX_MSG pMUXMsg; + int err; + char *apn = NULL; + char *user = NULL; + char *password = NULL; + int auth = 0; + PQMIWDS_APNNAME pApnName; + PQMIWDS_USERNAME pUserName; + PQMIWDS_PASSWD pPassWd; + PQMIWDS_AUTH_PREFERENCE pAuthPref; + + if (!profile->pdp) + return 0; + + UCHAR QMIType = (profile->ipv4_flag) ? QMUX_TYPE_WDS : QMUX_TYPE_WDS_IPV6; + pRequest = ComposeQMUXMsg(QMIType, QMIWDS_GET_PROFILE_SETTINGS_REQ, + WdsGetProfileSettingsReqSend, profile); + err = QmiThreadSendQMI(pRequest, &pResponse); + qmi_rsp_check_and_return(); + + pApnName = (PQMIWDS_APNNAME)GetTLV(&pResponse->MUXMsg.QMUXMsgHdr, 0x14); + pUserName = (PQMIWDS_USERNAME)GetTLV(&pResponse->MUXMsg.QMUXMsgHdr, 0x1B); + pPassWd = (PQMIWDS_PASSWD)GetTLV(&pResponse->MUXMsg.QMUXMsgHdr, 0x1C); + pAuthPref = + (PQMIWDS_AUTH_PREFERENCE)GetTLV(&pResponse->MUXMsg.QMUXMsgHdr, 0x1D); + + if (pApnName /* && le16_to_cpu(pApnName->TLVLength)*/) + apn = strndup((const char *)(&pApnName->ApnName), + le16_to_cpu(pApnName->TLVLength)); + if (pUserName /* && pUserName->UserName*/) + user = strndup((const char *)(&pUserName->UserName), + le16_to_cpu(pUserName->TLVLength)); + if (pPassWd /* && le16_to_cpu(pPassWd->TLVLength)*/) + password = strndup((const char *)(&pPassWd->Passwd), + le16_to_cpu(pPassWd->TLVLength)); + if (pAuthPref /* && le16_to_cpu(pAuthPref->TLVLength)*/) { + auth = pAuthPref->AuthPreference; + } + +#if 0 + if (profile) { + profile->apn = apn; + profile->user = user; + profile->password = password; + profile->auth = auth; + } +#endif + + dbg_time("%s[%d] %s/%s/%s/%d", __func__, profile->pdpindex, apn, user, password, + auth); + + free(pResponse); + return 0; +} +#endif + +#ifdef CONFIG_VERSION +int requestBaseBandVersion(const char **pp_reversion) +{ + PQCQMIMSG pRequest; + PQCQMIMSG pResponse; + PQMUX_MSG pMUXMsg; + PDEVICE_REV_ID revId; + int err; + + if (pp_reversion) + *pp_reversion = NULL; + + pRequest = + ComposeQMUXMsg(QMUX_TYPE_DMS, QMIDMS_GET_DEVICE_REV_ID_REQ, NULL, NULL); + err = QmiThreadSendQMI(pRequest, &pResponse); + qmi_rsp_check_and_return(); + + revId = (PDEVICE_REV_ID)GetTLV(&pResponse->MUXMsg.QMUXMsgHdr, 0x01); + + if (revId && le16_to_cpu(revId->TLVLength)) { + char *DeviceRevisionID = strndup((const char *)(&revId->RevisionID), + le16_to_cpu(revId->TLVLength)); + dbg_time("%s %s", __func__, DeviceRevisionID); + + if (pp_reversion) + *pp_reversion = DeviceRevisionID; + } + + free(pResponse); + return 0; +} +#endif + +#ifdef CONFIG_RESET_RADIO +static USHORT DmsSetOperatingModeReq(PQMUX_MSG pMUXMsg, void *arg) +{ + pMUXMsg->SetOperatingModeReq.TLVType = 0x01; + pMUXMsg->SetOperatingModeReq.TLVLength = cpu_to_le16(1); + pMUXMsg->SetOperatingModeReq.OperatingMode = *((UCHAR *)arg); + + return sizeof(QMIDMS_SET_OPERATING_MODE_REQ_MSG); +} + +int requestSetOperatingMode(UCHAR OperatingMode) +{ + PQCQMIMSG pRequest; + PQCQMIMSG pResponse; + PQMUX_MSG pMUXMsg; + int err; + + dbg_time("%s(%d)", __func__, OperatingMode); + + pRequest = ComposeQMUXMsg(QMUX_TYPE_DMS, QMIDMS_SET_OPERATING_MODE_REQ, + DmsSetOperatingModeReq, &OperatingMode); + err = QmiThreadSendQMI(pRequest, &pResponse); + qmi_rsp_check_and_return(); + + free(pResponse); + return 0; +} +#endif diff --git a/package/wwan/app/fibocom-dial/src/QMIThread.h b/package/wwan/app/fibocom-dial/src/QMIThread.h new file mode 100755 index 000000000..9be0956b2 --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/QMIThread.h @@ -0,0 +1,260 @@ +#ifndef __QMI_THREAD_H__ +#define __QMI_THREAD_H__ + +#define CONFIG_GOBINET +#define CONFIG_QMIWWAN +#define CONFIG_SIM +#define CONFIG_APN +#define CONFIG_VERSION +//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817 +#define CONFIG_IMSI_ICCID +//2021-03-24 willa.liu@fibocom.com changed end for support mantis 0071817 +#define CONFIG_DEFAULT_PDP 1 +#define CONFIG_DEFAULT_PDPINDEX 1 +//#define CONFIG_IMSI_ICCID + +#define CONFIG_RESET_RADIO \ + (45) // Reset Radiao(AT+CFUN=4,AT+CFUN=1) when cann not register network or + // setup data call in 45 seconds + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MPQCTL.h" +#include "MPQMI.h" +#include "MPQMUX.h" + +#define DEVICE_CLASS_UNKNOWN 0 +#define DEVICE_CLASS_CDMA 1 +#define DEVICE_CLASS_GSM 2 + +#define WWAN_DATA_CLASS_NONE 0x00000000 +#define WWAN_DATA_CLASS_GPRS 0x00000001 +#define WWAN_DATA_CLASS_EDGE 0x00000002 /* EGPRS */ +#define WWAN_DATA_CLASS_UMTS 0x00000004 +#define WWAN_DATA_CLASS_HSDPA 0x00000008 +#define WWAN_DATA_CLASS_HSUPA 0x00000010 +#define WWAN_DATA_CLASS_LTE 0x00000020 +//begin modified by zhangkaibo add 5G network detect feature on x55 platform. 20200605 +#define WWAN_DATA_CLASS_5G 0x00000040 +//end modified by zhangkaibo add 5G network detect feature on x55 platform. 20200605 +#define WWAN_DATA_CLASS_1XRTT 0x00010000 +#define WWAN_DATA_CLASS_1XEVDO 0x00020000 +#define WWAN_DATA_CLASS_1XEVDO_REVA 0x00040000 +#define WWAN_DATA_CLASS_1XEVDV 0x00080000 +#define WWAN_DATA_CLASS_3XRTT 0x00100000 +#define WWAN_DATA_CLASS_1XEVDO_REVB 0x00200000 /* for future use */ +#define WWAN_DATA_CLASS_UMB 0x00400000 +#define WWAN_DATA_CLASS_CUSTOM 0x80000000 + +struct wwan_data_class_str { + ULONG class; + CHAR *str; +}; + +#pragma pack(push, 1) + +typedef struct _QCQMIMSG { + QCQMI_HDR QMIHdr; + union { + QMICTL_MSG CTLMsg; + QMUX_MSG MUXMsg; +//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817 + QMUX_MSG QMUXMsgHdrResp; +//2021-03-24 willa.liu@fibocom.com changed end for support mantis 0071817 + }; +} __attribute__((packed)) QCQMIMSG, *PQCQMIMSG; + +#pragma pack(pop) + +typedef struct __IPV4 { + uint32_t Address; + uint32_t Gateway; + uint32_t SubnetMask; + uint32_t DnsPrimary; + uint32_t DnsSecondary; + uint32_t Mtu; +} IPV4_T; + +typedef struct __IPV6 { + UCHAR Address[16]; + UCHAR Gateway[16]; + UCHAR SubnetMask[16]; + UCHAR DnsPrimary[16]; + UCHAR DnsSecondary[16]; + UCHAR PrefixLengthIPAddr; + UCHAR PrefixLengthGateway; + ULONG Mtu; +} IPV6_T; + +#define IpFamilyV4 (0x04) +#define IpFamilyV6 (0x06) + +struct __PROFILE; +struct qmi_device_ops { + int (*init)(struct __PROFILE *profile); + int (*deinit)(void); + int (*send)(PQCQMIMSG pRequest); + void *(*read)(void *pData); +}; +extern int (*qmidev_send)(PQCQMIMSG pRequest); + +#ifndef bool +#define bool uint8_t +#endif +//2021-03-15 zhangkaibo@fibocom.com changed begin for oa 20210311037 +typedef struct { + unsigned int size; + unsigned int rx_urb_size; + unsigned int ep_type; + unsigned int iface_id; + unsigned int qmap_mode; + unsigned int qmap_version; + unsigned int dl_minimum_padding; + char ifname[8][16]; + unsigned char mux_id[8]; +} RMNET_INFO; +//2021-03-15 zhangkaibo@fibocom.com changed end for oa 20210311037 + +typedef struct __PROFILE { + char *qmichannel; + char *usbnet_adapter; + char *qmapnet_adapter; + const char *driver_name; + int qmap_mode; + int qmap_size; + int qmap_version; + const char *apn; + const char *user; + const char *password; + const char *pincode; + int auth; + int pdp; + int pdpindex; + int pdpnum; + int curIpFamily; + int rawIP; + int muxid; + IPV4_T ipv4; + IPV6_T ipv6; + int ipv4_flag; + int ipv6_flag; + +//2021-02-25 willa.liu@fibocom.com changed begin for support eipd SN-20210129001 + int ipv6_prigateway_flag; +//2021-02-25 willa.liu@fibocom.com changed begin for support eipd SN-20210129001 + + int dual_flag; + int apntype; + const struct qmi_device_ops *qmi_ops; + bool loopback_state; + int replication_factor; +//2021-02-08 zhangkaibo@fibocom.com changed begin for mantis 0070613 + int interfacenum; +//2021-02-08 zhangkaibo@fibocom.com changed end for mantis 0070613 +//2021-03-15 zhangkaibo@fibocom.com changed begin for oa 20210311037 + RMNET_INFO rmnet_info; +//2021-03-15 zhangkaibo@fibocom.com changed end for oa 20210311037 +} PROFILE_T; + +typedef enum { + SIM_ABSENT = 0, + SIM_NOT_READY = 1, + SIM_READY = + 2, /* SIM_READY means the radio state is RADIO_STATE_SIM_READY */ + SIM_PIN = 3, + SIM_PUK = 4, + SIM_NETWORK_PERSONALIZATION = 5, + SIM_BAD = 6, +} SIM_Status; +//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817 +typedef enum { + SIM_Card0 = 0, + SIM_Card1 = 1 +} SIM_Select; +//2021-03-24 willa.liu@fibocom.com changed end for support mantis 0071817 +#define WDM_DEFAULT_BUFSIZE 256 +#define RIL_REQUEST_QUIT 0x1000 +#define RIL_INDICATE_DEVICE_CONNECTED 0x1002 +#define RIL_INDICATE_DEVICE_DISCONNECTED 0x1003 +#define RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED 0x1004 +#define RIL_UNSOL_DATA_CALL_LIST_CHANGED 0x1005 + +extern int pthread_cond_timeout_np(pthread_cond_t *cond, pthread_mutex_t *mutex, + unsigned msecs); +extern int QmiThreadSendQMI(PQCQMIMSG pRequest, PQCQMIMSG *ppResponse); +extern int QmiThreadSendQMITimeout(PQCQMIMSG pRequest, PQCQMIMSG *ppResponse, + unsigned msecs); +extern void QmiThreadRecvQMI(PQCQMIMSG pResponse); +extern int fibo_raw_ip_mode_check(const char *ifname); +extern void udhcpc_start(PROFILE_T *profile); +extern void udhcpc_stop(PROFILE_T *profile); +extern void udhcpc_start_pcie(PROFILE_T *profile); +extern void udhcpc_stop_pcie(PROFILE_T *profile); + +extern void dump_qmi(void *dataBuffer, int dataLen); +extern void qmidevice_send_event_to_main(int triger_event); +extern int requestSetEthMode(PROFILE_T *profile); +//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817 +//extern int requestGetSIMStatus(SIM_Status *pSIMStatus); +extern int requestGetSIMStatus(SIM_Status *pSIMStatus , const int sim_select); +//2021-03-24 willa.liu@fibocom.com changed end for support mantis 0071817 +extern int requestEnterSimPin(const CHAR *pPinCode); +extern int requestGetICCID(void); +extern int requestGetIMSI(void); +extern int requestRegistrationState(UCHAR *pPSAttachedState); +extern int requestQueryDataCall(UCHAR *pConnectionStatus, int curIpFamily); +extern int requestSetupDataCall(PROFILE_T *profile, int curIpFamily); +extern int requestDeactivateDefaultPDP(PROFILE_T *profile, int curIpFamily); +extern int requestSetProfile(PROFILE_T *profile); +extern int requestGetProfile(PROFILE_T *profile); +extern int requestBaseBandVersion(const char **pp_reversion); +extern int requestGetIPAddress(PROFILE_T *profile, int curIpFamily); +extern int requestSetOperatingMode(UCHAR OperatingMode); +int requestRegistrationState2(UCHAR *pPSAttachedState); + +extern int fibo_qmap_mode_set(PROFILE_T *profile); +extern int fibo_bridge_mode_detect(PROFILE_T *profile); +extern int fibo_qmap_mode_detect(PROFILE_T *profile); +extern const struct qmi_device_ops qmiwwan_qmidev_ops; + +#define qmidev_is_gobinet(_qmichannel) \ + (strncmp(_qmichannel, "/dev/qcqmi", strlen("/dev/qcqmi")) == 0) +#define qmidev_is_qmiwwan(_qmichannel) \ + (strncmp(_qmichannel, "/dev/cdc-wdm", strlen("/dev/cdc-wdm")) == 0) +#define qmidev_is_pciemhi(_qmichannel) \ + (strncmp(_qmichannel, "/dev/mhi_", strlen("/dev/mhi_")) == 0) + +#define driver_is_qmi(_drv_name) \ + (strncasecmp(_drv_name, "qmi_wwan", strlen("qmi_wwan")) == 0) +#define driver_is_mbim(_drv_name) \ + (strncasecmp(_drv_name, "cdc_mbim", strlen("cdc_mbim")) == 0) + +extern FILE *logfilefp; +extern int debug_qmi; +extern USHORT g_MobileCountryCode; +extern USHORT g_MobileNetworkCode; +extern int qmidevice_control_fd[2]; +extern int qmiclientId[QMUX_TYPE_WDS_ADMIN + 1]; +extern void dbg_time(const char *fmt, ...); +extern USHORT le16_to_cpu(USHORT v16); +extern UINT le32_to_cpu(UINT v32); +extern USHORT cpu_to_le16(USHORT v16); +extern UINT cpu_to_le32(UINT v32); +#endif diff --git a/package/wwan/app/fibocom-dial/src/QmiWwanCM.c b/package/wwan/app/fibocom-dial/src/QmiWwanCM.c new file mode 100755 index 000000000..0e0cf64ea --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/QmiWwanCM.c @@ -0,0 +1,426 @@ +#include +#include +#include +#include +typedef unsigned short sa_family_t; +#include + +#include "QMIThread.h" + +#ifdef CONFIG_QMIWWAN +#define FIBO_QMI_PROXY "fibo_qmimsg_server" +static int cdc_wdm_fd = -1; + +static UCHAR GetQCTLTransactionId(void) +{ + static int TransactionId = 0; + if (++TransactionId > 0xFF) + TransactionId = 1; + return TransactionId; +} + +typedef USHORT (*CUSTOMQCTL)(PQMICTL_MSG pCTLMsg, void *arg); + +static PQCQMIMSG ComposeQCTLMsg(USHORT QMICTLType, + CUSTOMQCTL customQctlMsgFunction, void *arg) +{ + UCHAR QMIBuf[WDM_DEFAULT_BUFSIZE]; + PQCQMIMSG pRequest = (PQCQMIMSG)QMIBuf; + int Length; + + pRequest->QMIHdr.IFType = USB_CTL_MSG_TYPE_QMI; + pRequest->QMIHdr.CtlFlags = 0x00; + pRequest->QMIHdr.QMIType = QMUX_TYPE_CTL; + pRequest->QMIHdr.ClientId = 0x00; + + pRequest->CTLMsg.QMICTLMsgHdr.CtlFlags = QMICTL_FLAG_REQUEST; + pRequest->CTLMsg.QMICTLMsgHdr.TransactionId = GetQCTLTransactionId(); + pRequest->CTLMsg.QMICTLMsgHdr.QMICTLType = cpu_to_le16(QMICTLType); + if (customQctlMsgFunction) + pRequest->CTLMsg.QMICTLMsgHdr.Length = + cpu_to_le16(customQctlMsgFunction(&pRequest->CTLMsg, arg) - + sizeof(QCQMICTL_MSG_HDR)); + else + pRequest->CTLMsg.QMICTLMsgHdr.Length = cpu_to_le16(0x0000); + + pRequest->QMIHdr.Length = + cpu_to_le16(le16_to_cpu(pRequest->CTLMsg.QMICTLMsgHdr.Length) + + sizeof(QCQMICTL_MSG_HDR) + sizeof(QCQMI_HDR) - 1); + Length = le16_to_cpu(pRequest->QMIHdr.Length) + 1; + + pRequest = (PQCQMIMSG)malloc(Length); + if (pRequest == NULL) { + dbg_time("%s fail to malloc", __func__); + } else { + memcpy(pRequest, QMIBuf, Length); + } + + return pRequest; +} + +static USHORT CtlGetVersionReq(PQMICTL_MSG QCTLMsg, void *arg) +{ + QCTLMsg->GetVersionReq.TLVType = QCTLV_TYPE_REQUIRED_PARAMETER; + QCTLMsg->GetVersionReq.TLVLength = cpu_to_le16(0x0001); + QCTLMsg->GetVersionReq.QMUXTypes = QMUX_TYPE_ALL; + return sizeof(QMICTL_GET_VERSION_REQ_MSG); +} + +static USHORT CtlGetClientIdReq(PQMICTL_MSG QCTLMsg, void *arg) +{ + QCTLMsg->GetClientIdReq.TLVType = QCTLV_TYPE_REQUIRED_PARAMETER; + QCTLMsg->GetClientIdReq.TLVLength = cpu_to_le16(0x0001); + QCTLMsg->GetClientIdReq.QMIType = ((UCHAR *)arg)[0]; + return sizeof(QMICTL_GET_CLIENT_ID_REQ_MSG); +} + +static USHORT CtlReleaseClientIdReq(PQMICTL_MSG QCTLMsg, void *arg) +{ + QCTLMsg->ReleaseClientIdReq.TLVType = QCTLV_TYPE_REQUIRED_PARAMETER; + QCTLMsg->ReleaseClientIdReq.TLVLength = cpu_to_le16(0x0002); + QCTLMsg->ReleaseClientIdReq.QMIType = ((UCHAR *)arg)[0]; + QCTLMsg->ReleaseClientIdReq.ClientId = ((UCHAR *)arg)[1]; + return sizeof(QMICTL_RELEASE_CLIENT_ID_REQ_MSG); +} + +static int QmiWwanSendQMI(PQCQMIMSG pRequest) +{ + struct pollfd pollfds[] = {{cdc_wdm_fd, POLLOUT, 0}}; + int ret; + + if (cdc_wdm_fd == -1) { + dbg_time("%s cdc_wdm_fd = -1", __func__); + return -ENODEV; + } + + if (pRequest->QMIHdr.QMIType == QMUX_TYPE_WDS_IPV6) + pRequest->QMIHdr.QMIType = QMUX_TYPE_WDS; + + do { + ret = poll(pollfds, sizeof(pollfds) / sizeof(pollfds[0]), 5000); + } while ((ret < 0) && (errno == EINTR)); + + if (pollfds[0].revents & POLLOUT) { + ssize_t nwrites = le16_to_cpu(pRequest->QMIHdr.Length) + 1; + ret = write(cdc_wdm_fd, pRequest, nwrites); + if (ret == nwrites) { + ret = 0; + } else { + dbg_time("%s write=%d, errno: %d (%s)", __func__, ret, errno, + strerror(errno)); + } + } else { + dbg_time("%s poll=%d, revents = 0x%x, errno: %d (%s)", __func__, ret, + pollfds[0].revents, errno, strerror(errno)); + } + + return ret; +} + +static int QmiWwanGetClientID(UCHAR QMIType) +{ + PQCQMIMSG pResponse; + + QmiThreadSendQMI( + ComposeQCTLMsg(QMICTL_GET_CLIENT_ID_REQ, CtlGetClientIdReq, &QMIType), + &pResponse); + + if (pResponse) { + USHORT QMUXResult = cpu_to_le16(pResponse->CTLMsg.QMICTLMsgHdrRsp + .QMUXResult); // QMI_RESULT_SUCCESS + USHORT QMUXError = cpu_to_le16(pResponse->CTLMsg.QMICTLMsgHdrRsp + .QMUXError); // QMI_ERR_INVALID_ARG + // UCHAR QMIType = pResponse->CTLMsg.GetClientIdRsp.QMIType; + UCHAR ClientId = pResponse->CTLMsg.GetClientIdRsp.ClientId; + + dbg_time("%s: QMIType = %d clientid %d", __func__, QMIType, ClientId); + + if (!QMUXResult && !QMUXError && + (QMIType == pResponse->CTLMsg.GetClientIdRsp.QMIType)) { + switch (QMIType) { + case QMUX_TYPE_WDS: + dbg_time("Get clientWDS = %d", ClientId); + break; + case QMUX_TYPE_DMS: + dbg_time("Get clientDMS = %d", ClientId); + break; + case QMUX_TYPE_NAS: + dbg_time("Get clientNAS = %d", ClientId); + break; + case QMUX_TYPE_QOS: + dbg_time("Get clientQOS = %d", ClientId); + break; + case QMUX_TYPE_WMS: + dbg_time("Get clientWMS = %d", ClientId); + break; + case QMUX_TYPE_PDS: + dbg_time("Get clientPDS = %d", ClientId); + break; + case QMUX_TYPE_UIM: + dbg_time("Get clientUIM = %d", ClientId); + break; + case QMUX_TYPE_WDS_ADMIN: + dbg_time("Get clientWDA = %d", ClientId); + break; + default: + break; + } + return ClientId; + } + } + return 0; +} + +static int QmiWwanReleaseClientID(QMI_SERVICE_TYPE QMIType, UCHAR ClientId) +{ + UCHAR argv[] = {QMIType, ClientId}; + QmiThreadSendQMI(ComposeQCTLMsg(QMICTL_RELEASE_CLIENT_ID_REQ, + CtlReleaseClientIdReq, argv), + NULL); + return 0; +} + +static int QmiWwanInit(PROFILE_T *profile) +{ + unsigned i; + int ret; + PQCQMIMSG pResponse; + + if (profile->qmap_mode == 0 || profile->qmap_mode == 1) { + for (i = 0; i < 10; i++) { + ret = QmiThreadSendQMITimeout( + ComposeQCTLMsg(QMICTL_SYNC_REQ, NULL, NULL), NULL, 1 * 1000); + if (!ret) + break; + sleep(1); + } + if (ret) + return ret; + } + + QmiThreadSendQMI( + ComposeQCTLMsg(QMICTL_GET_VERSION_REQ, CtlGetVersionReq, NULL), + &pResponse); + if (profile->qmap_mode) { + if (pResponse) { + if (pResponse->CTLMsg.QMICTLMsgHdrRsp.QMUXResult == 0 && + pResponse->CTLMsg.QMICTLMsgHdrRsp.QMUXError == 0) { + uint8_t NumElements = 0; + + for (NumElements = 0; + NumElements < pResponse->CTLMsg.GetVersionRsp.NumElements; + NumElements++) { + if (pResponse->CTLMsg.GetVersionRsp.TypeVersion[NumElements] + .QMUXType == QMUX_TYPE_WDS_ADMIN) + profile->qmap_version = (pResponse->CTLMsg.GetVersionRsp + .TypeVersion[NumElements] + .MinorVersion > 16); + } + } + } + } + if (pResponse) + free(pResponse); + if (profile->ipv4_flag) + qmiclientId[QMUX_TYPE_WDS] = QmiWwanGetClientID(QMUX_TYPE_WDS); + if (profile->ipv6_flag) + qmiclientId[QMUX_TYPE_WDS_IPV6] = QmiWwanGetClientID(QMUX_TYPE_WDS); + qmiclientId[QMUX_TYPE_DMS] = QmiWwanGetClientID(QMUX_TYPE_DMS); + qmiclientId[QMUX_TYPE_NAS] = QmiWwanGetClientID(QMUX_TYPE_NAS); + qmiclientId[QMUX_TYPE_UIM] = QmiWwanGetClientID(QMUX_TYPE_UIM); + if (profile->qmap_mode == 0 || profile->qmap_mode == 1) + qmiclientId[QMUX_TYPE_WDS_ADMIN] = + QmiWwanGetClientID(QMUX_TYPE_WDS_ADMIN); + + return 0; +} + +static int QmiWwanDeInit(void) +{ + unsigned int i; + for (i = 0; i < sizeof(qmiclientId) / sizeof(qmiclientId[0]); i++) { + if (qmiclientId[i] != 0) { + QmiWwanReleaseClientID(i, qmiclientId[i]); + qmiclientId[i] = 0; + } + } + + return 0; +} + +static int qmi_proxy_open(const char *name) +{ + int sockfd = -1; + int reuse_addr = 1; + struct sockaddr_un sockaddr; + socklen_t alen; + + /*Create server socket*/ + (sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)); + if (sockfd < 0) + return sockfd; + + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sun_family = AF_LOCAL; + sockaddr.sun_path[0] = 0; + memcpy(sockaddr.sun_path + 1, name, strlen(name)); + + alen = strlen(name) + offsetof(struct sockaddr_un, sun_path) + 1; + if (connect(sockfd, (struct sockaddr *)&sockaddr, alen) < 0) { + close(sockfd); + dbg_time("%s connect %s errno: %d (%s)\n", __func__, name, errno, + strerror(errno)); + return -1; + } + (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, + sizeof(reuse_addr))); + + dbg_time("connect to %s sockfd = %d\n", name, sockfd); + + return sockfd; +} + +static ssize_t qmi_proxy_read(int fd, void *buf, size_t size) +{ + ssize_t nreads; + PQCQMI_HDR pHdr = (PQCQMI_HDR)buf; + + nreads = read(fd, pHdr, sizeof(QCQMI_HDR)); + if (nreads == sizeof(QCQMI_HDR)) { + nreads += read(fd, pHdr + 1, + le16_to_cpu(pHdr->Length) + 1 - sizeof(QCQMI_HDR)); + } + + return nreads; +} + +static void *QmiWwanThread(void *pData) +{ + PROFILE_T *profile = (PROFILE_T *)pData; + const char *cdc_wdm = (const char *)profile->qmichannel; + + if (profile->qmap_mode == 0 || profile->qmap_mode == 1) + cdc_wdm_fd = open(cdc_wdm, O_RDWR | O_NONBLOCK | O_NOCTTY); + else + cdc_wdm_fd = qmi_proxy_open(FIBO_QMI_PROXY); + + if (cdc_wdm_fd == -1) { + dbg_time("%s Failed to open %s, errno: %d (%s)", __func__, cdc_wdm, + errno, strerror(errno)); + qmidevice_send_event_to_main(RIL_INDICATE_DEVICE_DISCONNECTED); + pthread_exit(NULL); + return NULL; + } + + fcntl(cdc_wdm_fd, F_SETFL, fcntl(cdc_wdm_fd, F_GETFL) | O_NONBLOCK); + fcntl(cdc_wdm_fd, F_SETFD, FD_CLOEXEC); + + dbg_time("cdc_wdm_fd = %d", cdc_wdm_fd); + + qmidevice_send_event_to_main(RIL_INDICATE_DEVICE_CONNECTED); + + while (1) { + struct pollfd pollfds[] = {{qmidevice_control_fd[1], POLLIN, 0}, + {cdc_wdm_fd, POLLIN, 0}}; + int ne, ret, nevents = sizeof(pollfds) / sizeof(pollfds[0]); + + do { + ret = poll(pollfds, nevents, -1); + } while ((ret < 0) && (errno == EINTR)); + + if (ret <= 0) { + dbg_time("%s poll=%d, errno: %d (%s)", __func__, ret, errno, + strerror(errno)); + break; + } + + for (ne = 0; ne < nevents; ne++) { + int fd = pollfds[ne].fd; + short revents = pollfds[ne].revents; + + // dbg_time("{%d, %x, %x}", pollfds[ne].fd, pollfds[ne].events, + // pollfds[ne].revents); + + if (revents & (POLLERR | POLLHUP | POLLNVAL)) { + dbg_time("%s poll err/hup/inval", __func__); + dbg_time("poll fd = %d, events = 0x%04x", fd, revents); + if (fd == cdc_wdm_fd) { + } else { + } + if (revents & + (POLLHUP | POLLNVAL)) // EC20 bug, Can get POLLERR + goto __QmiWwanThread_quit; + } + + if ((revents & POLLIN) == 0) + continue; + + if (fd == qmidevice_control_fd[1]) { + int triger_event; + if (read(fd, &triger_event, sizeof(triger_event)) == + sizeof(triger_event)) { + // DBG("triger_event = 0x%x", triger_event); + switch (triger_event) { + case RIL_REQUEST_QUIT: + goto __QmiWwanThread_quit; + break; + case SIGTERM: + case SIGHUP: + case SIGINT: + QmiThreadRecvQMI(NULL); + break; + default: + break; + } + } + } + + if (fd == cdc_wdm_fd) { + ssize_t nreads; + UCHAR QMIBuf[4096]; + PQCQMIMSG pResponse = (PQCQMIMSG)QMIBuf; + + if (profile->qmap_mode == 0 || profile->qmap_mode == 1) + nreads = read(fd, QMIBuf, sizeof(QMIBuf)); + else + nreads = qmi_proxy_read(fd, QMIBuf, sizeof(QMIBuf)); + // dbg_time("%s read=%d errno: %d (%s)", __func__, (int)nreads, + // errno, strerror(errno)); + if (nreads <= 0) { + dbg_time("%s read=%d errno: %d (%s)", __func__, (int)nreads, + errno, strerror(errno)); + break; + } + + if (nreads != (le16_to_cpu(pResponse->QMIHdr.Length) + 1)) { + dbg_time("%s nreads=%d, pQCQMI->QMIHdr.Length = %d", + __func__, (int)nreads, + le16_to_cpu(pResponse->QMIHdr.Length)); + continue; + } + + QmiThreadRecvQMI(pResponse); + } + } + } + +__QmiWwanThread_quit: + if (cdc_wdm_fd != -1) { + close(cdc_wdm_fd); + cdc_wdm_fd = -1; + } + qmidevice_send_event_to_main(RIL_INDICATE_DEVICE_DISCONNECTED); + QmiThreadRecvQMI(NULL); // main thread may pending on QmiThreadSendQMI() + dbg_time("%s exit", __func__); + pthread_exit(NULL); + return NULL; +} + +#endif + +const struct qmi_device_ops qmiwwan_qmidev_ops = { + .init = QmiWwanInit, + .deinit = QmiWwanDeInit, + .send = QmiWwanSendQMI, + .read = QmiWwanThread, +}; diff --git a/package/wwan/driver/quectel_cm_5G/src/default.script b/package/wwan/app/fibocom-dial/src/default.script old mode 100644 new mode 100755 similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/default.script rename to package/wwan/app/fibocom-dial/src/default.script diff --git a/package/wwan/app/fibocom-dial/src/fibo_qmimsg_server.c b/package/wwan/app/fibocom-dial/src/fibo_qmimsg_server.c new file mode 100755 index 000000000..89c60575e --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/fibo_qmimsg_server.c @@ -0,0 +1,1331 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; + +#define cpu_to_le16(x) (x) +#define cpu_to_le32(x) (x) +#define le16_to_cpu(x) (x) +#define le32_to_cpu(x) (x) + +#define dprintf(fmt, arg...) do { printf(fmt, ##arg); } while(0) +#define SYSCHECK(c) do{if((c)<0) {dprintf("%s %d error: '%s' (code: %d)\n", __func__, __LINE__, strerror(errno), errno); return -1;}}while(0) +#define cfmakenoblock(fd) do{fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) | O_NONBLOCK);}while(0) + +#define qmidev_is_pciemhi(_qmichannel) (strncmp(_qmichannel, "/dev/mhi_", strlen("/dev/mhi_")) == 0) + +typedef struct _QCQMI_HDR +{ + uint8_t IFType; + uint16_t Length; + uint8_t CtlFlags; // reserved + uint8_t QMIType; + uint8_t ClientId; +} __attribute__ ((packed)) QCQMI_HDR, *PQCQMI_HDR; + +typedef struct _QMICTL_SYNC_REQ_MSG +{ + uint8_t CtlFlags; // QMICTL_FLAG_REQUEST + uint8_t TransactionId; + uint16_t QMICTLType; // QMICTL_CTL_SYNC_REQ + uint16_t Length; // 0 +} __attribute__ ((packed)) QMICTL_SYNC_REQ_MSG, *PQMICTL_SYNC_REQ_MSG; + +typedef struct _QMICTL_SYNC_RESP_MSG +{ + uint8_t CtlFlags; // QMICTL_FLAG_RESPONSE + uint8_t TransactionId; + uint16_t QMICTLType; // QMICTL_CTL_SYNC_RESP + uint16_t Length; + uint8_t TLVType; // QCTLV_TYPE_RESULT_CODE + uint16_t TLVLength; // 0x0004 + uint16_t QMIResult; + uint16_t QMIError; +} __attribute__ ((packed)) QMICTL_SYNC_RESP_MSG, *PQMICTL_SYNC_RESP_MSG; + +typedef struct _QMICTL_SYNC_IND_MSG +{ + uint8_t CtlFlags; // QMICTL_FLAG_INDICATION + uint8_t TransactionId; + uint16_t QMICTLType; // QMICTL_REVOKE_CLIENT_ID_IND + uint16_t Length; +} __attribute__ ((packed)) QMICTL_SYNC_IND_MSG, *PQMICTL_SYNC_IND_MSG; + +typedef struct _QMICTL_GET_CLIENT_ID_REQ_MSG +{ + uint8_t CtlFlags; // QMICTL_FLAG_REQUEST + uint8_t TransactionId; + uint16_t QMICTLType; // QMICTL_GET_CLIENT_ID_REQ + uint16_t Length; + uint8_t TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER + uint16_t TLVLength; // 1 + uint8_t QMIType; // QMUX type +} __attribute__ ((packed)) QMICTL_GET_CLIENT_ID_REQ_MSG, *PQMICTL_GET_CLIENT_ID_REQ_MSG; + +typedef struct _QMICTL_GET_CLIENT_ID_RESP_MSG +{ + uint8_t CtlFlags; // QMICTL_FLAG_RESPONSE + uint8_t TransactionId; + uint16_t QMICTLType; // QMICTL_GET_CLIENT_ID_RESP + uint16_t Length; + uint8_t TLVType; // QCTLV_TYPE_RESULT_CODE + uint16_t TLVLength; // 0x0004 + uint16_t QMIResult; // result code + uint16_t QMIError; // error code + uint8_t TLV2Type; // QCTLV_TYPE_REQUIRED_PARAMETER + uint16_t TLV2Length; // 2 + uint8_t QMIType; + uint8_t ClientId; +} __attribute__ ((packed)) QMICTL_GET_CLIENT_ID_RESP_MSG, *PQMICTL_GET_CLIENT_ID_RESP_MSG; + +typedef struct _QMICTL_RELEASE_CLIENT_ID_REQ_MSG +{ + uint8_t CtlFlags; // QMICTL_FLAG_REQUEST + uint8_t TransactionId; + uint16_t QMICTLType; // QMICTL_RELEASE_CLIENT_ID_REQ + uint16_t Length; + uint8_t TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER + uint16_t TLVLength; // 0x0002 + uint8_t QMIType; + uint8_t ClientId; +} __attribute__ ((packed)) QMICTL_RELEASE_CLIENT_ID_REQ_MSG, *PQMICTL_RELEASE_CLIENT_ID_REQ_MSG; + +typedef struct _QMICTL_RELEASE_CLIENT_ID_RESP_MSG +{ + uint8_t CtlFlags; // QMICTL_FLAG_RESPONSE + uint8_t TransactionId; + uint16_t QMICTLType; // QMICTL_RELEASE_CLIENT_ID_RESP + uint16_t Length; + uint8_t TLVType; // QCTLV_TYPE_RESULT_CODE + uint16_t TLVLength; // 0x0004 + uint16_t QMIResult; // result code + uint16_t QMIError; // error code + uint8_t TLV2Type; // QCTLV_TYPE_REQUIRED_PARAMETER + uint16_t TLV2Length; // 2 + uint8_t QMIType; + uint8_t ClientId; +} __attribute__ ((packed)) QMICTL_RELEASE_CLIENT_ID_RESP_MSG, *PQMICTL_RELEASE_CLIENT_ID_RESP_MSG; + +// QMICTL Control Flags +#define QMICTL_CTL_FLAG_CMD 0x00 +#define QMICTL_CTL_FLAG_RSP 0x01 +#define QMICTL_CTL_FLAG_IND 0x02 + +typedef struct _QCQMICTL_MSG_HDR +{ + uint8_t CtlFlags; // 00-cmd, 01-rsp, 10-ind + uint8_t TransactionId; + uint16_t QMICTLType; + uint16_t Length; +} __attribute__ ((packed)) QCQMICTL_MSG_HDR, *PQCQMICTL_MSG_HDR; + +#define QCQMICTL_MSG_HDR_SIZE sizeof(QCQMICTL_MSG_HDR) + +typedef struct _QCQMICTL_MSG_HDR_RESP +{ + uint8_t CtlFlags; // 00-cmd, 01-rsp, 10-ind + uint8_t TransactionId; + uint16_t QMICTLType; + uint16_t Length; + uint8_t TLVType; // 0x02 - result code + uint16_t TLVLength; // 4 + uint16_t QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + uint16_t QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT +} __attribute__ ((packed)) QCQMICTL_MSG_HDR_RESP, *PQCQMICTL_MSG_HDR_RESP; + +typedef struct _QMICTL_GET_VERSION_REQ_MSG +{ + uint8_t CtlFlags; // QMICTL_FLAG_REQUEST + uint8_t TransactionId; + uint16_t QMICTLType; // QMICTL_GET_VERSION_REQ + uint16_t Length; // 0 + uint8_t TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER + uint16_t TLVLength; // var + uint8_t QMUXTypes; // List of one byte QMUX_TYPE values + // 0xFF returns a list of versions for all + // QMUX_TYPEs implemented on the device +} __attribute__ ((packed)) QMICTL_GET_VERSION_REQ_MSG, *PQMICTL_GET_VERSION_REQ_MSG; + +typedef struct _QMUX_TYPE_VERSION_STRUCT +{ + uint8_t QMUXType; + uint16_t MajorVersion; + uint16_t MinorVersion; +} __attribute__ ((packed)) QMUX_TYPE_VERSION_STRUCT, *PQMUX_TYPE_VERSION_STRUCT; + +typedef struct _QMICTL_GET_VERSION_RESP_MSG +{ + uint8_t CtlFlags; // QMICTL_FLAG_RESPONSE + uint8_t TransactionId; + uint16_t QMICTLType; // QMICTL_GET_VERSION_RESP + uint16_t Length; + uint8_t TLVType; // QCTLV_TYPE_RESULT_CODE + uint16_t TLVLength; // 0x0004 + uint16_t QMIResult; + uint16_t QMIError; + uint8_t TLV2Type; // QCTLV_TYPE_REQUIRED_PARAMETER + uint16_t TLV2Length; // var + uint8_t NumElements; // Num of QMUX_TYPE_VERSION_STRUCT + QMUX_TYPE_VERSION_STRUCT TypeVersion[0]; +} __attribute__ ((packed)) QMICTL_GET_VERSION_RESP_MSG, *PQMICTL_GET_VERSION_RESP_MSG; + + +typedef struct _QMICTL_MSG +{ + union + { + // Message Header + QCQMICTL_MSG_HDR QMICTLMsgHdr; + QCQMICTL_MSG_HDR_RESP QMICTLMsgHdrRsp; + + // QMICTL Message + //QMICTL_SET_INSTANCE_ID_REQ_MSG SetInstanceIdReq; + //QMICTL_SET_INSTANCE_ID_RESP_MSG SetInstanceIdRsp; + QMICTL_GET_VERSION_REQ_MSG GetVersionReq; + QMICTL_GET_VERSION_RESP_MSG GetVersionRsp; + QMICTL_GET_CLIENT_ID_REQ_MSG GetClientIdReq; + QMICTL_GET_CLIENT_ID_RESP_MSG GetClientIdRsp; + //QMICTL_RELEASE_CLIENT_ID_REQ_MSG ReleaseClientIdReq; + QMICTL_RELEASE_CLIENT_ID_RESP_MSG ReleaseClientIdRsp; + //QMICTL_REVOKE_CLIENT_ID_IND_MSG RevokeClientIdInd; + //QMICTL_INVALID_CLIENT_ID_IND_MSG InvalidClientIdInd; + //QMICTL_SET_DATA_FORMAT_REQ_MSG SetDataFormatReq; + //QMICTL_SET_DATA_FORMAT_RESP_MSG SetDataFormatRsp; + QMICTL_SYNC_REQ_MSG SyncReq; + QMICTL_SYNC_RESP_MSG SyncRsp; + QMICTL_SYNC_IND_MSG SyncInd; + }; +} __attribute__ ((packed)) QMICTL_MSG, *PQMICTL_MSG; + +typedef struct _QCQMUX_MSG_HDR +{ + uint8_t CtlFlags; // 0: single QMUX Msg; 1: + uint16_t TransactionId; + uint16_t Type; + uint16_t Length; + uint8_t payload[0]; +} __attribute__ ((packed)) QCQMUX_MSG_HDR, *PQCQMUX_MSG_HDR; + +typedef struct _QCQMUX_MSG_HDR_RESP +{ + uint8_t CtlFlags; // 0: single QMUX Msg; 1: + uint16_t TransactionId; + uint16_t Type; + uint16_t Length; + uint8_t TLVType; // 0x02 - result code + uint16_t TLVLength; // 4 + uint16_t QMUXResult; // QMI_RESULT_SUCCESS + // QMI_RESULT_FAILURE + uint16_t QMUXError; // QMI_ERR_INVALID_ARG + // QMI_ERR_NO_MEMORY + // QMI_ERR_INTERNAL + // QMI_ERR_FAULT +} __attribute__ ((packed)) QCQMUX_MSG_HDR_RESP, *PQCQMUX_MSG_HDR_RESP; + +typedef struct _QMIWDS_ADMIN_SET_DATA_FORMAT +{ + uint16_t Type; // QMUX type 0x0000 + uint16_t Length; +} __attribute__ ((packed)) QMIWDS_ADMIN_SET_DATA_FORMAT, *PQMIWDS_ADMIN_SET_DATA_FORMAT; + +typedef struct _QMIWDS_ADMIN_SET_DATA_FORMAT_TLV_QOS +{ + uint8_t TLVType; + uint16_t TLVLength; + uint8_t QOSSetting; +} __attribute__ ((packed)) QMIWDS_ADMIN_SET_DATA_FORMAT_TLV_QOS, *PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV_QOS; + +typedef struct _QMIWDS_ADMIN_SET_DATA_FORMAT_TLV +{ + uint8_t TLVType; + uint16_t TLVLength; + uint32_t Value; +} __attribute__ ((packed)) QMIWDS_ADMIN_SET_DATA_FORMAT_TLV, *PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV; + +typedef struct _QMIWDS_ENDPOINT_TLV +{ + uint8_t TLVType; + uint16_t TLVLength; + uint32_t ep_type; + uint32_t iface_id; +} __attribute__ ((packed)) QMIWDS_ENDPOINT_TLV, *PQMIWDS_ENDPOINT_TLV; + +typedef struct _QMIWDS_ADMIN_SET_DATA_FORMAT_REQ_MSG +{ + uint8_t CtlFlags; // 0: single QMUX Msg; 1: + uint16_t TransactionId; + uint16_t Type; + uint16_t Length; + QMIWDS_ADMIN_SET_DATA_FORMAT_TLV_QOS QosDataFormatTlv; + QMIWDS_ADMIN_SET_DATA_FORMAT_TLV UnderlyingLinkLayerProtocolTlv; + QMIWDS_ADMIN_SET_DATA_FORMAT_TLV UplinkDataAggregationProtocolTlv; + QMIWDS_ADMIN_SET_DATA_FORMAT_TLV DownlinkDataAggregationProtocolTlv; + QMIWDS_ADMIN_SET_DATA_FORMAT_TLV DownlinkDataAggregationMaxDatagramsTlv; + QMIWDS_ADMIN_SET_DATA_FORMAT_TLV DownlinkDataAggregationMaxSizeTlv; + QMIWDS_ENDPOINT_TLV epTlv; +} __attribute__ ((packed)) QMIWDS_ADMIN_SET_DATA_FORMAT_REQ_MSG, *PQMIWDS_ADMIN_SET_DATA_FORMAT_REQ_MSG; + +typedef struct _QCQMUX_TLV +{ + uint8_t Type; + uint16_t Length; + uint8_t Value[0]; +} __attribute__ ((packed)) QCQMUX_TLV, *PQCQMUX_TLV; + +typedef struct _QMUX_MSG +{ + union + { + // Message Header + QCQMUX_MSG_HDR QMUXMsgHdr; + QCQMUX_MSG_HDR_RESP QMUXMsgHdrResp; + QMIWDS_ADMIN_SET_DATA_FORMAT_REQ_MSG SetDataFormatReq; + }; +} __attribute__ ((packed)) QMUX_MSG, *PQMUX_MSG; + +typedef struct _QCQMIMSG { + QCQMI_HDR QMIHdr; +//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817 + //QMUX_MSG QMUXMsgHdrResp; +//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817 + union { + QMICTL_MSG CTLMsg; + QMUX_MSG MUXMsg; + }; +} __attribute__ ((packed)) QCQMIMSG, *PQCQMIMSG; + +// QMUX Message Definitions -- QMI SDU +#define QMUX_CTL_FLAG_SINGLE_MSG 0x00 +#define QMUX_CTL_FLAG_COMPOUND_MSG 0x01 +#define QMUX_CTL_FLAG_TYPE_CMD 0x00 +#define QMUX_CTL_FLAG_TYPE_RSP 0x02 +#define QMUX_CTL_FLAG_TYPE_IND 0x04 +#define QMUX_CTL_FLAG_MASK_COMPOUND 0x01 +#define QMUX_CTL_FLAG_MASK_TYPE 0x06 // 00-cmd, 01-rsp, 10-ind + +#define USB_CTL_MSG_TYPE_QMI 0x01 + +#define QMICTL_FLAG_REQUEST 0x00 +#define QMICTL_FLAG_RESPONSE 0x01 +#define QMICTL_FLAG_INDICATION 0x02 + +// QMICTL Type +#define QMICTL_SET_INSTANCE_ID_REQ 0x0020 +#define QMICTL_SET_INSTANCE_ID_RESP 0x0020 +#define QMICTL_GET_VERSION_REQ 0x0021 +#define QMICTL_GET_VERSION_RESP 0x0021 +#define QMICTL_GET_CLIENT_ID_REQ 0x0022 +#define QMICTL_GET_CLIENT_ID_RESP 0x0022 +#define QMICTL_RELEASE_CLIENT_ID_REQ 0x0023 +#define QMICTL_RELEASE_CLIENT_ID_RESP 0x0023 +#define QMICTL_REVOKE_CLIENT_ID_IND 0x0024 +#define QMICTL_INVALID_CLIENT_ID_IND 0x0025 +#define QMICTL_SET_DATA_FORMAT_REQ 0x0026 +#define QMICTL_SET_DATA_FORMAT_RESP 0x0026 +#define QMICTL_SYNC_REQ 0x0027 +#define QMICTL_SYNC_RESP 0x0027 +#define QMICTL_SYNC_IND 0x0027 + +#define QCTLV_TYPE_REQUIRED_PARAMETER 0x01 + +// Define QMI Type +typedef enum _QMI_SERVICE_TYPE +{ + QMUX_TYPE_CTL = 0x00, + QMUX_TYPE_WDS = 0x01, + QMUX_TYPE_DMS = 0x02, + QMUX_TYPE_NAS = 0x03, + QMUX_TYPE_QOS = 0x04, + QMUX_TYPE_WMS = 0x05, + QMUX_TYPE_PDS = 0x06, + QMUX_TYPE_UIM = 0x0B, + QMUX_TYPE_WDS_IPV6 = 0x11, + QMUX_TYPE_WDS_ADMIN = 0x1A, + QMUX_TYPE_MAX = 0xFF, + QMUX_TYPE_ALL = 0xFF +} QMI_SERVICE_TYPE; + +#define QMIWDS_ADMIN_SET_DATA_FORMAT_REQ 0x0020 +#define QMIWDS_ADMIN_SET_DATA_FORMAT_RESP 0x0020 + +struct qlistnode +{ + struct qlistnode *next; + struct qlistnode *prev; +}; + +#define qnode_to_item(node, container, member) \ + (container *) (((char*) (node)) - offsetof(container, member)) + +#define qlist_for_each(node, list) \ + for (node = (list)->next; node != (list); node = node->next) + +#define qlist_empty(list) ((list) == (list)->next) +#define qlist_head(list) ((list)->next) +#define qlist_tail(list) ((list)->prev) + +typedef struct { + struct qlistnode qnode; + uint8_t ClientFd; + QCQMIMSG qmi[0]; +} QMI_PROXY_MSG; + +typedef struct { + struct qlistnode qnode; + uint8_t QMIType; + uint8_t ClientId; + unsigned AccessTime; +} QMI_PROXY_CLINET; + +typedef struct { + struct qlistnode qnode; + struct qlistnode client_qnode; + uint8_t ClientFd; + unsigned AccessTime; +} QMI_PROXY_CONNECTION; + +static int qmi_proxy_quit = 0; +static pthread_t thread_id = 0; +static int cdc_wdm_fd = -1; +static int qmi_proxy_server_fd = -1; +static struct qlistnode qmi_proxy_connection; +static struct qlistnode qmi_proxy_ctl_msg; +static PQCQMIMSG s_pCtlReq; +static PQCQMIMSG s_pCtlRsq; +static pthread_mutex_t s_ctlmutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t s_ctlcond = PTHREAD_COND_INITIALIZER; +static int verbose_debug = 0; + +static void qlist_init(struct qlistnode *node) +{ + node->next = node; + node->prev = node; +} + +static void qlist_add_tail(struct qlistnode *head, struct qlistnode *item) +{ + item->next = head; + item->prev = head->prev; + head->prev->next = item; + head->prev = item; +} + +static void qlist_remove(struct qlistnode *item) +{ + item->next->prev = item->prev; + item->prev->next = item->next; +} + + + +static void setTimespecRelative(struct timespec *p_ts, long long msec) +{ + struct timeval tv; + + gettimeofday(&tv, (struct timezone *) NULL); + + /* what's really funny about this is that I know + pthread_cond_timedwait just turns around and makes this + a relative time again */ + p_ts->tv_sec = tv.tv_sec + (msec / 1000); + p_ts->tv_nsec = (tv.tv_usec + (msec % 1000) * 1000L ) * 1000L; +} + +static int pthread_cond_timeout_np(pthread_cond_t *cond, pthread_mutex_t * mutex, unsigned msecs) { + if (msecs != 0) { + struct timespec ts; + setTimespecRelative(&ts, msecs); + return pthread_cond_timedwait(cond, mutex, &ts); + } else { + return pthread_cond_wait(cond, mutex); + } +} + +static int create_local_server(const char *name) { + int sockfd = -1; + int reuse_addr = 1; + struct sockaddr_un sockaddr; + socklen_t alen; + + /*Create server socket*/ + SYSCHECK(sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)); + + memset(&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sun_family = AF_LOCAL; + sockaddr.sun_path[0] = 0; + memcpy(sockaddr.sun_path + 1, name, strlen(name) ); + + alen = strlen(name) + offsetof(struct sockaddr_un, sun_path) + 1; + SYSCHECK(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse_addr,sizeof(reuse_addr))); + if(bind(sockfd, (struct sockaddr *)&sockaddr, alen) < 0) { + close(sockfd); + dprintf("%s bind %s errno: %d (%s)\n", __func__, name, errno, strerror(errno)); + return -1; + } + + dprintf("local server: %s sockfd = %d\n", name, sockfd); + cfmakenoblock(sockfd); + listen(sockfd, 1); + + return sockfd; +} + +static void accept_qmi_connection(int serverfd) { + int clientfd = -1; + unsigned char addr[128]; + socklen_t alen = sizeof(addr); + QMI_PROXY_CONNECTION *qmi_con; + + clientfd = accept(serverfd, (struct sockaddr *)addr, &alen); + + qmi_con = (QMI_PROXY_CONNECTION *)malloc(sizeof(QMI_PROXY_CONNECTION)); + if (qmi_con) { + qlist_init(&qmi_con->qnode); + qlist_init(&qmi_con->client_qnode); + qmi_con->ClientFd= clientfd; + qmi_con->AccessTime = 0; + dprintf("+++ ClientFd=%d\n", qmi_con->ClientFd); + qlist_add_tail(&qmi_proxy_connection, &qmi_con->qnode); + } + + cfmakenoblock(clientfd); +} + +static void cleanup_qmi_connection(int clientfd) { + struct qlistnode *con_node, *qmi_node; + + qlist_for_each(con_node, &qmi_proxy_connection) { + QMI_PROXY_CONNECTION *qmi_con = qnode_to_item(con_node, QMI_PROXY_CONNECTION, qnode); + + if (qmi_con->ClientFd == clientfd) { + while (!qlist_empty(&qmi_con->client_qnode)) { + QMI_PROXY_CLINET *qmi_client = qnode_to_item(qlist_head(&qmi_con->client_qnode), QMI_PROXY_CLINET, qnode); + + dprintf("xxx ClientFd=%d QMIType=%d ClientId=%d\n", qmi_con->ClientFd, qmi_client->QMIType, qmi_client->ClientId); + + qlist_remove(&qmi_client->qnode); + free(qmi_client); + } + + qlist_for_each(qmi_node, &qmi_proxy_ctl_msg) { + QMI_PROXY_MSG *qmi_msg = qnode_to_item(qmi_node, QMI_PROXY_MSG, qnode); + + if (qmi_msg->ClientFd == qmi_con->ClientFd) { + qlist_remove(&qmi_msg->qnode); + free(qmi_msg); + break; + } + } + + dprintf("--- ClientFd=%d\n", qmi_con->ClientFd); + close(qmi_con->ClientFd); + qlist_remove(&qmi_con->qnode); + free(qmi_con); + break; + } + } +} + +static void get_client_id(QMI_PROXY_CONNECTION *qmi_con, PQMICTL_GET_CLIENT_ID_RESP_MSG pClient) { + if (pClient->QMIResult == 0 && pClient->QMIError == 0) { + QMI_PROXY_CLINET *qmi_client = (QMI_PROXY_CLINET *)malloc(sizeof(QMI_PROXY_CLINET)); + + qlist_init(&qmi_client->qnode); + qmi_client->QMIType = pClient->QMIType; + qmi_client->ClientId = pClient->ClientId; + qmi_client->AccessTime = 0; + + dprintf("+++ ClientFd=%d QMIType=%d ClientId=%d\n", qmi_con->ClientFd, qmi_client->QMIType, qmi_client->ClientId); + qlist_add_tail(&qmi_con->client_qnode, &qmi_client->qnode); + } +} + +static void release_client_id(QMI_PROXY_CONNECTION *qmi_con, PQMICTL_RELEASE_CLIENT_ID_RESP_MSG pClient) { + struct qlistnode *client_node; + + if (pClient->QMIResult == 0 && pClient->QMIError == 0) { + qlist_for_each (client_node, &qmi_con->client_qnode) { + QMI_PROXY_CLINET *qmi_client = qnode_to_item(client_node, QMI_PROXY_CLINET, qnode); + + if (pClient->QMIType == qmi_client->QMIType && pClient->ClientId == qmi_client->ClientId) { + dprintf("--- ClientFd=%d QMIType=%d ClientId=%d\n", qmi_con->ClientFd, qmi_client->QMIType, qmi_client->ClientId); + qlist_remove(&qmi_client->qnode); + free(qmi_client); + break; + } + } + } +} + + +static int send_qmi_to_cdc_wdm(PQCQMIMSG pQMI) { + struct pollfd pollfds[]= {{cdc_wdm_fd, POLLOUT, 0}}; + ssize_t ret = 0; + + do { + ret = poll(pollfds, sizeof(pollfds)/sizeof(pollfds[0]), 5000); + } while ((ret < 0) && (errno == EINTR)); + + if (pollfds[0].revents & POLLOUT) { + ssize_t size = le16_to_cpu(pQMI->QMIHdr.Length) + 1; + ret = write(cdc_wdm_fd, pQMI, size); + if (verbose_debug) + { + ssize_t i; + printf("w %d %zd: ", cdc_wdm_fd, ret); + for (i = 0; i < 16; i++) + printf("%02x ", ((uint8_t *)pQMI)[i]); + printf("\n"); + } + } + + return ret; +} + +static int send_qmi_to_client(PQCQMIMSG pQMI, int clientFd) { + struct pollfd pollfds[]= {{clientFd, POLLOUT, 0}}; + ssize_t ret = 0; + + do { + ret = poll(pollfds, sizeof(pollfds)/sizeof(pollfds[0]), 5000); + } while ((ret < 0) && (errno == EINTR)); + + if (pollfds[0].revents & POLLOUT) { + ssize_t size = le16_to_cpu(pQMI->QMIHdr.Length) + 1; + ret = write(clientFd, pQMI, size); + if (verbose_debug) + { + ssize_t i; + printf("w %d %zd: ", clientFd, ret); + for (i = 0; i < 16; i++) + printf("%02x ", ((uint8_t *)pQMI)[i]); + printf("\n"); + } + } + + return ret; +} + + +static void recv_qmi(PQCQMIMSG pQMI, unsigned size) { + struct qlistnode *con_node, *client_node; + + if (qmi_proxy_server_fd <= 0) { + pthread_mutex_lock(&s_ctlmutex); + + if (s_pCtlReq != NULL) { + if (pQMI->QMIHdr.QMIType == QMUX_TYPE_CTL + && s_pCtlReq->CTLMsg.QMICTLMsgHdrRsp.TransactionId == pQMI->CTLMsg.QMICTLMsgHdrRsp.TransactionId) { + s_pCtlRsq = malloc(size); + memcpy(s_pCtlRsq, pQMI, size); + pthread_cond_signal(&s_ctlcond); + } + else if (pQMI->QMIHdr.QMIType != QMUX_TYPE_CTL + && s_pCtlReq->MUXMsg.QMUXMsgHdr.TransactionId == pQMI->MUXMsg.QMUXMsgHdr.TransactionId) { + s_pCtlRsq = malloc(size); + memcpy(s_pCtlRsq, pQMI, size); + pthread_cond_signal(&s_ctlcond); + } + } + + pthread_mutex_unlock(&s_ctlmutex); + } + else if (pQMI->QMIHdr.QMIType == QMUX_TYPE_CTL) { + if (pQMI->CTLMsg.QMICTLMsgHdr.CtlFlags == QMICTL_CTL_FLAG_RSP) { + if (!qlist_empty(&qmi_proxy_ctl_msg)) { + QMI_PROXY_MSG *qmi_msg = qnode_to_item(qlist_head(&qmi_proxy_ctl_msg), QMI_PROXY_MSG, qnode); + + qlist_for_each(con_node, &qmi_proxy_connection) { + QMI_PROXY_CONNECTION *qmi_con = qnode_to_item(con_node, QMI_PROXY_CONNECTION, qnode); + + if (qmi_con->ClientFd == qmi_msg->ClientFd) { + send_qmi_to_client(pQMI, qmi_msg->ClientFd); + + if (pQMI->CTLMsg.QMICTLMsgHdrRsp.QMICTLType == QMICTL_GET_CLIENT_ID_RESP) + get_client_id(qmi_con, &pQMI->CTLMsg.GetClientIdRsp); + else if (pQMI->CTLMsg.QMICTLMsgHdrRsp.QMICTLType == QMICTL_RELEASE_CLIENT_ID_RESP) + release_client_id(qmi_con, &pQMI->CTLMsg.ReleaseClientIdRsp); + else { + } + } + } + + qlist_remove(&qmi_msg->qnode); + free(qmi_msg); + } + } + + if (!qlist_empty(&qmi_proxy_ctl_msg)) { + QMI_PROXY_MSG *qmi_msg = qnode_to_item(qlist_head(&qmi_proxy_ctl_msg), QMI_PROXY_MSG, qnode); + + qlist_for_each(con_node, &qmi_proxy_connection) { + QMI_PROXY_CONNECTION *qmi_con = qnode_to_item(con_node, QMI_PROXY_CONNECTION, qnode); + + if (qmi_con->ClientFd == qmi_msg->ClientFd) { + send_qmi_to_cdc_wdm(qmi_msg->qmi); + } + } + } + } + else { + qlist_for_each(con_node, &qmi_proxy_connection) { + QMI_PROXY_CONNECTION *qmi_con = qnode_to_item(con_node, QMI_PROXY_CONNECTION, qnode); + + qlist_for_each(client_node, &qmi_con->client_qnode) { + QMI_PROXY_CLINET *qmi_client = qnode_to_item(client_node, QMI_PROXY_CLINET, qnode); + if (pQMI->QMIHdr.QMIType == qmi_client->QMIType) { + if (pQMI->QMIHdr.ClientId == 0 || pQMI->QMIHdr.ClientId == qmi_client->ClientId) { + send_qmi_to_client(pQMI, qmi_con->ClientFd); + } + } + } + } + } +} + +static int send_qmi(PQCQMIMSG pQMI, unsigned size, int clientfd) { + if (qmi_proxy_server_fd <= 0) { + send_qmi_to_cdc_wdm(pQMI); + } + else if (pQMI->QMIHdr.QMIType == QMUX_TYPE_CTL) { + QMI_PROXY_MSG *qmi_msg; + + if (qlist_empty(&qmi_proxy_ctl_msg)) + send_qmi_to_cdc_wdm(pQMI); + + qmi_msg = malloc(sizeof(QMI_PROXY_MSG) + size); + qlist_init(&qmi_msg->qnode); + qmi_msg->ClientFd = clientfd; + memcpy(qmi_msg->qmi, pQMI, size); + qlist_add_tail(&qmi_proxy_ctl_msg, &qmi_msg->qnode); + } + else { + send_qmi_to_cdc_wdm(pQMI); + } + + return 0; +} + +static int send_qmi_timeout(PQCQMIMSG pRequest, PQCQMIMSG *ppResponse, unsigned mseconds) { + int ret; + + pthread_mutex_lock(&s_ctlmutex); + + s_pCtlReq = pRequest; + s_pCtlRsq = NULL; + if (ppResponse) *ppResponse = NULL; + + send_qmi_to_cdc_wdm(pRequest); + ret = pthread_cond_timeout_np(&s_ctlcond, &s_ctlmutex, mseconds); + if (!ret) { + if (s_pCtlRsq && ppResponse) { + *ppResponse = s_pCtlRsq; + } else if (s_pCtlRsq) { + free(s_pCtlRsq); + } + } else { + dprintf("%s ret=%d\n", __func__, ret); + } + + s_pCtlReq = NULL; + pthread_mutex_unlock(&s_ctlmutex); + + return ret; +} + +static PQCQMUX_TLV qmi_find_tlv (PQCQMIMSG pQMI, uint8_t TLVType) { + int Length = 0; + + while (Length < le16_to_cpu(pQMI->MUXMsg.QMUXMsgHdr.Length)) { + PQCQMUX_TLV pTLV = (PQCQMUX_TLV)(&pQMI->MUXMsg.QMUXMsgHdr.payload[Length]); + + //dprintf("TLV {%02x, %04x}\n", pTLV->Type, pTLV->Length); + if (pTLV->Type == TLVType) { + return pTLV; + } + + Length += (le16_to_cpu((pTLV->Length)) + sizeof(QCQMUX_TLV)); + } + + return NULL; +} + +static int qmi_proxy_init(char *qmi_device, char* getidproduct) { + unsigned i; + int ret; + QCQMIMSG _QMI; + PQCQMIMSG pQMI = &_QMI; + PQCQMIMSG pRsp; + uint8_t TransactionId = 0xC1; + uint8_t WDAClientId = 0; + unsigned rx_urb_size = 0; + unsigned ep_type, iface_id; + + dprintf("%s enter\n", __func__); + + pQMI->QMIHdr.IFType = USB_CTL_MSG_TYPE_QMI; + pQMI->QMIHdr.CtlFlags = 0x00; + pQMI->QMIHdr.QMIType = QMUX_TYPE_CTL; + pQMI->QMIHdr.ClientId= 0x00; + + pQMI->CTLMsg.QMICTLMsgHdr.CtlFlags = QMICTL_FLAG_REQUEST; + + for (i = 0; i < 10; i++) { + pQMI->CTLMsg.SyncReq.TransactionId = TransactionId++; + pQMI->CTLMsg.SyncReq.QMICTLType = QMICTL_SYNC_REQ; + pQMI->CTLMsg.SyncReq.Length = 0; + + pQMI->QMIHdr.Length = pQMI->CTLMsg.QMICTLMsgHdr.Length + sizeof(QCQMI_HDR) + sizeof(QCQMICTL_MSG_HDR) - 1; + + ret = send_qmi_timeout(pQMI, NULL, 1000); + if (!ret) + break; + } + + if (ret) + goto qmi_proxy_init_fail; + + pQMI->CTLMsg.GetVersionReq.TransactionId = TransactionId++; + pQMI->CTLMsg.GetVersionReq.QMICTLType = QMICTL_GET_VERSION_REQ; + pQMI->CTLMsg.GetVersionReq.Length = 0x0004; + pQMI->CTLMsg.GetVersionReq.TLVType= QCTLV_TYPE_REQUIRED_PARAMETER; + pQMI->CTLMsg.GetVersionReq.TLVLength = 0x0001; + pQMI->CTLMsg.GetVersionReq.QMUXTypes = QMUX_TYPE_ALL; + + pQMI->QMIHdr.Length = pQMI->CTLMsg.QMICTLMsgHdr.Length + sizeof(QCQMI_HDR) + sizeof(QCQMICTL_MSG_HDR) - 1; + + ret = send_qmi_timeout(pQMI, &pRsp, 3000); + if (ret || (pRsp == NULL)) + goto qmi_proxy_init_fail; + + if (pRsp) { + uint8_t NumElements = 0; + if (pRsp->CTLMsg.QMICTLMsgHdrRsp.QMUXResult ||pRsp->CTLMsg.QMICTLMsgHdrRsp.QMUXError) { + dprintf("QMICTL_GET_VERSION_REQ QMUXResult=%d, QMUXError=%d\n", + pRsp->CTLMsg.QMICTLMsgHdrRsp.QMUXResult, pRsp->CTLMsg.QMICTLMsgHdrRsp.QMUXError); + goto qmi_proxy_init_fail; + } + + for (NumElements = 0; NumElements < pRsp->CTLMsg.GetVersionRsp.NumElements; NumElements++) { + if (verbose_debug) + dprintf("QMUXType = %02x Version = %d.%d\n", + pRsp->CTLMsg.GetVersionRsp.TypeVersion[NumElements].QMUXType, + pRsp->CTLMsg.GetVersionRsp.TypeVersion[NumElements].MajorVersion, + pRsp->CTLMsg.GetVersionRsp.TypeVersion[NumElements].MinorVersion); + } + } + free(pRsp); + + pQMI->CTLMsg.GetClientIdReq.TransactionId = TransactionId++; + pQMI->CTLMsg.GetClientIdReq.QMICTLType = QMICTL_GET_CLIENT_ID_REQ; + pQMI->CTLMsg.GetClientIdReq.Length = 0x0004; + pQMI->CTLMsg.GetClientIdReq.TLVType= QCTLV_TYPE_REQUIRED_PARAMETER; + pQMI->CTLMsg.GetClientIdReq.TLVLength = 0x0001; + pQMI->CTLMsg.GetClientIdReq.QMIType = QMUX_TYPE_WDS_ADMIN; + + pQMI->QMIHdr.Length = pQMI->CTLMsg.QMICTLMsgHdr.Length + sizeof(QCQMI_HDR) + sizeof(QCQMICTL_MSG_HDR) - 1; + + ret = send_qmi_timeout(pQMI, &pRsp, 3000); + if (ret || (pRsp == NULL)) + goto qmi_proxy_init_fail; + + if (pRsp) { + if (pRsp->CTLMsg.QMICTLMsgHdrRsp.QMUXResult ||pRsp->CTLMsg.QMICTLMsgHdrRsp.QMUXError) { + dprintf("QMICTL_GET_CLIENT_ID_REQ QMUXResult=%d, QMUXError=%d\n", + pRsp->CTLMsg.QMICTLMsgHdrRsp.QMUXResult, pRsp->CTLMsg.QMICTLMsgHdrRsp.QMUXError); + goto qmi_proxy_init_fail; + } + + WDAClientId = pRsp->CTLMsg.GetClientIdRsp.ClientId; + if (verbose_debug) dprintf("WDAClientId = %d\n", WDAClientId); + } + free(pRsp); + + if(qmidev_is_pciemhi(qmi_device)) + { + rx_urb_size = 32*1024; //must same as rx_urb_size defined in GobiNet&qmi_wwan driver //SDX24&SDX55 support 32KB + ep_type = 0x03; + } + else + { + rx_urb_size = 4*1024; //must same as rx_urb_size defined in GobiNet&qmi_wwan driver //SDX24&SDX55 support 32KB + ep_type = 0x02; + } + + printf("getidproduct=%s\n", getidproduct); + if(!strncasecmp(getidproduct, "0104", 4)|| !strncasecmp(getidproduct, "1001", 4) || !strncasecmp(getidproduct, "9025", 4)) + iface_id = 0x04; + else if(!strncasecmp(getidproduct, "0109", 4) || !strncasecmp(getidproduct, "1000", 4)) + iface_id = 0x02; + else if(!strncasecmp(getidproduct, "0113", 4)) + iface_id = 0x00; + + /*begin added by minchao.zhao@fibocom.com for mantis 91283 on 2021-09-27*/ + if(qmidev_is_pciemhi(qmi_device)) + iface_id = 0x04; //mhi_QMI0 enumeration arrangement + /*end added by minchao.zhao@fibocom.com for mantis 91283 on 2021-09-27*/ + printf("iface_id=%d\n", iface_id); + + pQMI->QMIHdr.IFType = USB_CTL_MSG_TYPE_QMI; + pQMI->QMIHdr.CtlFlags = 0x00; + pQMI->QMIHdr.QMIType = QMUX_TYPE_WDS_ADMIN; + pQMI->QMIHdr.ClientId= WDAClientId; + + pQMI->MUXMsg.QMUXMsgHdr.CtlFlags = QMICTL_FLAG_REQUEST; + pQMI->MUXMsg.QMUXMsgHdr.TransactionId = TransactionId++; + + pQMI->MUXMsg.SetDataFormatReq.Type = QMIWDS_ADMIN_SET_DATA_FORMAT_REQ; + pQMI->MUXMsg.SetDataFormatReq.Length = sizeof(QMIWDS_ADMIN_SET_DATA_FORMAT_REQ_MSG) - sizeof(QCQMUX_MSG_HDR); + +//Indicates whether the Quality of Service(QOS) data format is used by the client. + pQMI->MUXMsg.SetDataFormatReq.QosDataFormatTlv.TLVType = 0x10; + pQMI->MUXMsg.SetDataFormatReq.QosDataFormatTlv.TLVLength = cpu_to_le16(0x0001); + pQMI->MUXMsg.SetDataFormatReq.QosDataFormatTlv.QOSSetting = 0; /* no-QOS header */ +//Underlying Link Layer Protocol + pQMI->MUXMsg.SetDataFormatReq.UnderlyingLinkLayerProtocolTlv.TLVType = 0x11; + pQMI->MUXMsg.SetDataFormatReq.UnderlyingLinkLayerProtocolTlv.TLVLength = cpu_to_le16(4); + pQMI->MUXMsg.SetDataFormatReq.UnderlyingLinkLayerProtocolTlv.Value = cpu_to_le32(0x02); /* Set IP mode */ +//Uplink (UL) data aggregation protocol to be used for uplink data transfer. + pQMI->MUXMsg.SetDataFormatReq.UplinkDataAggregationProtocolTlv.TLVType = 0x12; + pQMI->MUXMsg.SetDataFormatReq.UplinkDataAggregationProtocolTlv.TLVLength = cpu_to_le16(4); + pQMI->MUXMsg.SetDataFormatReq.UplinkDataAggregationProtocolTlv.Value = cpu_to_le32(0x05); //UL QMAP is enabled +//Downlink (DL) data aggregation protocol to be used for downlink data transfer + pQMI->MUXMsg.SetDataFormatReq.DownlinkDataAggregationProtocolTlv.TLVType = 0x13; + pQMI->MUXMsg.SetDataFormatReq.DownlinkDataAggregationProtocolTlv.TLVLength = cpu_to_le16(4); + pQMI->MUXMsg.SetDataFormatReq.DownlinkDataAggregationProtocolTlv.Value = cpu_to_le32(0x05); //UL QMAP is enabled +//Maximum number of datagrams in a single aggregated packet on downlink + pQMI->MUXMsg.SetDataFormatReq.DownlinkDataAggregationMaxDatagramsTlv.TLVType = 0x15; + pQMI->MUXMsg.SetDataFormatReq.DownlinkDataAggregationMaxDatagramsTlv.TLVLength = cpu_to_le16(4); + if(qmidev_is_pciemhi(qmi_device)) + { + pQMI->MUXMsg.SetDataFormatReq.DownlinkDataAggregationMaxDatagramsTlv.Value = cpu_to_le32((rx_urb_size>2048)?(rx_urb_size/512):1); + } + else + { + pQMI->MUXMsg.SetDataFormatReq.DownlinkDataAggregationMaxDatagramsTlv.Value = cpu_to_le32((rx_urb_size>2048)?(rx_urb_size/1024):1); + } +//Maximum size in bytes of a single aggregated packet allowed on downlink + pQMI->MUXMsg.SetDataFormatReq.DownlinkDataAggregationMaxSizeTlv.TLVType = 0x16; + pQMI->MUXMsg.SetDataFormatReq.DownlinkDataAggregationMaxSizeTlv.TLVLength = cpu_to_le16(4); + pQMI->MUXMsg.SetDataFormatReq.DownlinkDataAggregationMaxSizeTlv.Value = cpu_to_le32(rx_urb_size); +//Peripheral End Point ID + pQMI->MUXMsg.SetDataFormatReq.epTlv.TLVType = 0x17; + pQMI->MUXMsg.SetDataFormatReq.epTlv.TLVLength = cpu_to_le16(8); + pQMI->MUXMsg.SetDataFormatReq.epTlv.ep_type = cpu_to_le32(ep_type); // DATA_EP_TYPE_BAM_DMUX + pQMI->MUXMsg.SetDataFormatReq.epTlv.iface_id = cpu_to_le32(iface_id); + + pQMI->QMIHdr.Length = pQMI->MUXMsg.QMUXMsgHdr.Length + sizeof(QCQMI_HDR) + sizeof(QCQMUX_MSG_HDR) - 1; + + ret = send_qmi_timeout(pQMI, &pRsp, 3000); + if (ret || (pRsp == NULL)) + goto qmi_proxy_init_fail; + + if (pRsp) { + PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV pFormat; + + if (pRsp->MUXMsg.QMUXMsgHdrResp.QMUXResult || pRsp->MUXMsg.QMUXMsgHdrResp.QMUXError) { + dprintf("QMIWDS_ADMIN_SET_DATA_FORMAT_REQ QMUXResult=%d, QMUXError=%d\n", + pRsp->MUXMsg.QMUXMsgHdrResp.QMUXResult, pRsp->MUXMsg.QMUXMsgHdrResp.QMUXError); + goto qmi_proxy_init_fail; + } + + pFormat = (PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV)qmi_find_tlv(pRsp, 0x11); + if (pFormat) + dprintf("link_prot %d\n", le32_to_cpu(pFormat->Value)); + pFormat = (PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV)qmi_find_tlv(pRsp, 0x12); + if (pFormat) + dprintf("ul_data_aggregation_protocol %d\n", le32_to_cpu(pFormat->Value)); + pFormat = (PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV)qmi_find_tlv(pRsp, 0x13); + if (pFormat) + dprintf("dl_data_aggregation_protocol %d\n", le32_to_cpu(pFormat->Value)); + pFormat = (PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV)qmi_find_tlv(pRsp, 0x15); + if (pFormat) + dprintf("dl_data_aggregation_max_datagrams %d\n", le32_to_cpu(pFormat->Value)); + pFormat = (PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV)qmi_find_tlv(pRsp, 0x16); + if (pFormat) { + dprintf("dl_data_aggregation_max_size %d\n", le32_to_cpu(pFormat->Value)); + rx_urb_size = le32_to_cpu(pFormat->Value); + } + pFormat = (PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV)qmi_find_tlv(pRsp, 0x17); + if (pFormat) + dprintf("ul_data_aggregation_max_datagrams %d\n", le32_to_cpu(pFormat->Value)); + pFormat = (PQMIWDS_ADMIN_SET_DATA_FORMAT_TLV)qmi_find_tlv(pRsp, 0x18); + if (pFormat) + dprintf("ul_data_aggregation_max_size %d\n", le32_to_cpu(pFormat->Value)); + } + free(pRsp); + + dprintf("%s finished, rx_urb_size is %u\n", __func__, rx_urb_size); + return 0; + +qmi_proxy_init_fail: + dprintf("%s failed\n", __func__); + return -1; +} +//2021-06-03 willa.liu@fibocom.com changed begin +static void qmi_start_server(void) { + qmi_proxy_server_fd = create_local_server("fibo_qmimsg_server"); + printf("%s: qmi_proxy_server_fd = %d\n", __func__, qmi_proxy_server_fd); + if (qmi_proxy_server_fd == -1) { + dprintf("%s Failed to create %s, errno: %d (%s)\n", __func__, "fibocom-qmi-proxy", errno, strerror(errno)); + } +} + +static void qmi_close_server(void) { + if (qmi_proxy_server_fd != -1) { + dprintf("%s %s close server\n", __func__, "fibocom-qmi-proxy"); + close(qmi_proxy_server_fd); + qmi_proxy_server_fd = -1; + } +} +//2021-06-03 willa.liu@fibocom.com changed end +static void *qmi_proxy_loop(void *param) +{ + static uint8_t qmi_buf[2048]; + PQCQMIMSG pQMI = (PQCQMIMSG)qmi_buf; + struct qlistnode *con_node; + QMI_PROXY_CONNECTION *qmi_con; + + dprintf("%s enter thread_id %ld\n", __func__, pthread_self()); + + qlist_init(&qmi_proxy_connection); + qlist_init(&qmi_proxy_ctl_msg); + + while (cdc_wdm_fd > 0 && qmi_proxy_quit == 0) { + struct pollfd pollfds[2+64]; + int ne, ret, nevents = 0; + ssize_t nreads; + + pollfds[nevents].fd = cdc_wdm_fd; + pollfds[nevents].events = POLLIN; + pollfds[nevents].revents= 0; + nevents++; + + if (qmi_proxy_server_fd > 0) { + pollfds[nevents].fd = qmi_proxy_server_fd; + pollfds[nevents].events = POLLIN; + pollfds[nevents].revents= 0; + nevents++; + } + + qlist_for_each(con_node, &qmi_proxy_connection) { + qmi_con = qnode_to_item(con_node, QMI_PROXY_CONNECTION, qnode); + + pollfds[nevents].fd = qmi_con->ClientFd; + pollfds[nevents].events = POLLIN; + pollfds[nevents].revents= 0; + nevents++; + + if (nevents == (sizeof(pollfds)/sizeof(pollfds[0]))) + break; + } + + do { + //ret = poll(pollfds, nevents, -1); + ret = poll(pollfds, nevents, (qmi_proxy_server_fd > 0) ? -1 : 200); + } while (ret < 0 && errno == EINTR && qmi_proxy_quit == 0); + + if (ret < 0) { + dprintf("%s poll=%d, errno: %d (%s)\n", __func__, ret, errno, strerror(errno)); + goto qmi_proxy_loop_exit; + } + + for (ne = 0; ne < nevents; ne++) { + int fd = pollfds[ne].fd; + short revents = pollfds[ne].revents; + + if (revents & (POLLERR | POLLHUP | POLLNVAL)) { + dprintf("%s poll fd = %d, revents = %04x\n", __func__, fd, revents); + if (fd == cdc_wdm_fd) { + goto qmi_proxy_loop_exit; + } else if(fd == qmi_proxy_server_fd) { + + } else { + cleanup_qmi_connection(fd); + } + + continue; + } + + if (!(pollfds[ne].revents & POLLIN)) { + continue; + } + + if (fd == qmi_proxy_server_fd) { + accept_qmi_connection(fd); + } + else if (fd == cdc_wdm_fd) { + nreads = read(fd, pQMI, sizeof(qmi_buf)); + if (verbose_debug) + { + ssize_t i; + printf("r %d %zd: ", fd, nreads); + for (i = 0; i < 16; i++) + printf("%02x ", ((uint8_t *)pQMI)[i]); + printf("\n"); + } + if (nreads <= 0) { + dprintf("%s read=%d errno: %d (%s)\n", __func__, (int)nreads, errno, strerror(errno)); + goto qmi_proxy_loop_exit; + } + + if (nreads != ((pQMI->QMIHdr.Length) + 1)) { + dprintf("%s nreads=%d, pQCQMI->QMIHdr.Length = %d\n", __func__, (int)nreads, (pQMI->QMIHdr.Length)); + continue; + } + + recv_qmi(pQMI, nreads); + } + else { + nreads = read(fd, pQMI, sizeof(qmi_buf)); + if (verbose_debug) + { + ssize_t i; + printf("r %d %zd: ", fd, nreads); + for (i = 0; i < 16; i++) + printf("%02x ", ((uint8_t *)pQMI)[i]); + printf("\n"); + } + if (nreads <= 0) { + dprintf("%s read=%d errno: %d (%s)", __func__, (int)nreads, errno, strerror(errno)); + cleanup_qmi_connection(fd); + break; + } + + if (nreads != ((pQMI->QMIHdr.Length) + 1)) { + dprintf("%s nreads=%d, pQCQMI->QMIHdr.Length = %d\n", __func__, (int)nreads, (pQMI->QMIHdr.Length)); + continue; + } + + send_qmi(pQMI, nreads, fd); + } + } + } + +qmi_proxy_loop_exit: + while (!qlist_empty(&qmi_proxy_connection)) { + QMI_PROXY_CONNECTION *qmi_con = qnode_to_item(qlist_head(&qmi_proxy_connection), QMI_PROXY_CONNECTION, qnode); + + cleanup_qmi_connection(qmi_con->ClientFd); + } + + dprintf("%s exit, thread_id %ld\n", __func__, pthread_self()); + + return NULL; +} + +static void qmidevice_detect(char **device_name, char **idproduct) { + struct dirent* ent = NULL; + DIR *pDir; + + char dir[255] = "/sys/bus/usb/devices"; + pDir = opendir(dir); + if (pDir) { + struct { + char subdir[255 * 2]; + char qmifile[255 * 2]; + } *pl; + pl = (typeof(pl)) malloc(sizeof(*pl)); + memset(pl, 0x00, sizeof(*pl)); + + while ((ent = readdir(pDir)) != NULL) { + struct dirent* subent = NULL; + DIR *psubDir; + char idVendor[4+1] = {0}; + char idProduct[4+1] = {0}; + int fd = 0; + + memset(pl, 0x00, sizeof(*pl)); + snprintf(pl->subdir, sizeof(pl->subdir), "%s/%s/idVendor", dir, ent->d_name); + fd = open(pl->subdir, O_RDONLY); + if (fd > 0) { + read(fd, idVendor, 4); + close(fd); + } + + snprintf(pl->subdir, sizeof(pl->subdir), "%s/%s/idProduct", dir, ent->d_name); + fd = open(pl->subdir, O_RDONLY); + if (fd > 0) { + read(fd, idProduct, 4); + close(fd); + } + + + if (strncasecmp(idVendor, "05c6", 4) && strncasecmp(idVendor, "2cb7", 4) && strncasecmp(idVendor, "1508", 4)) + continue; + + dprintf("Find %s/%s idVendor=%s idProduct=%s\n", dir, ent->d_name, idVendor, idProduct); + + if(((!strncasecmp(idVendor, "2cb7", 4)) && (!strncasecmp(idProduct, "0104", 4))) || ((!strncasecmp(idVendor, "1508", 4)) && (!strncasecmp(idProduct, "1001", 4))) || ((!strncasecmp(idVendor, "05c6", 4)) && (!strncasecmp(idProduct, "9025", 4)))) + { + snprintf(pl->subdir, sizeof(pl->subdir), "%s/%s:1.4/usbmisc", dir, ent->d_name); + if (access(pl->subdir, R_OK)) { + snprintf(pl->subdir, sizeof(pl->subdir), "%s/%s:1.4/usb", dir, ent->d_name); + if (access(pl->subdir, R_OK)) { + dprintf("no GobiQMI/usbmic/usb found in %s/%s:1.4\n", dir, ent->d_name); + continue; + } + } + } + else if((!strncasecmp(idVendor, "2cb7", 4) && !strncasecmp(idProduct, "0109", 4)) || (!strncasecmp(idVendor, "1508", 4) && !strncasecmp(idProduct, "1000", 4))) + { + snprintf(pl->subdir, sizeof(pl->subdir), "%s/%s:1.2/usbmisc", dir, ent->d_name); + if (access(pl->subdir, R_OK)) { + snprintf(pl->subdir, sizeof(pl->subdir), "%s/%s:1.2/usb", dir, ent->d_name); + if (access(pl->subdir, R_OK)) { + dprintf("no GobiQMI/usbmic/usb found in %s/%s:1.2\n", dir, ent->d_name); + continue; + } + } + } + else if(!strncasecmp(idVendor, "2cb7", 4) && !strncasecmp(idProduct, "0113", 4)) + { + snprintf(pl->subdir, sizeof(pl->subdir), "%s/%s:1.0/usbmisc", dir, ent->d_name); + if (access(pl->subdir, R_OK)) { + snprintf(pl->subdir, sizeof(pl->subdir), "%s/%s:1.0/usb", dir, ent->d_name); + if (access(pl->subdir, R_OK)) { + dprintf("no GobiQMI/usbmic/usb found in %s/%s:1.0\n", dir, ent->d_name); + continue; + } + } + } + + strncpy(idproduct,idProduct, sizeof(idProduct)); + psubDir = opendir(pl->subdir); + if (pDir == NULL) { + dprintf("Cannot open directory: %s, errno: %d (%s)\n", dir, errno, strerror(errno)); + continue; + } + + while ((subent = readdir(psubDir)) != NULL) { + if (subent->d_name[0] == '.') + continue; + dprintf("Find %s/%s\n", pl->subdir, subent->d_name); + snprintf(pl->qmifile, sizeof(pl->qmifile), "/dev/%s", subent->d_name); + break; + } + *device_name = strdup(pl->qmifile); + closedir(psubDir); + } + closedir(pDir); + free(pl); + } +} + +static void usage(void) { + dprintf(" -d A valid qmi device\n" + " default /dev/cdc-wdm0, but cdc-wdm0 may be invalid\n" + " -v Will show all details\n"); +} + +static void sig_action(int sig) { + if (qmi_proxy_quit == 0) { + qmi_proxy_quit = 1; + if (thread_id) + pthread_kill(thread_id, sig); + } +} + +int main(int argc, char *argv[]) { + int opt; + char *cdc_wdm = NULL; + int retry_times = 0; + char getidproduct[5] = {0}; + optind = 1; + + signal(SIGINT, sig_action); + + while ( -1 != (opt = getopt(argc, argv, "d:v"))) { + switch (opt) { + case 'd': + cdc_wdm = strdup(optarg); + break; + case 'v': + verbose_debug = 1; + break; + default: + usage(); + break; + } + } + + if (cdc_wdm == NULL) + qmidevice_detect(&cdc_wdm, &getidproduct); + if (cdc_wdm == NULL) { + dprintf("Fail to find any /dev/cdc-wdm device. break\n"); + return -1; + } + + if (access(cdc_wdm, R_OK | W_OK)) { + dprintf("Fail to access %s, errno: %d (%s). break\n", cdc_wdm, errno, strerror(errno)); + free(cdc_wdm); + return -1; + } + + while (qmi_proxy_quit == 0) { + if (access(cdc_wdm, R_OK | W_OK)) { + dprintf("Fail to access %s, errno: %d (%s). continue\n", cdc_wdm, errno, strerror(errno)); + // wait device + sleep(3); + continue; + } + + dprintf("Will use cdc-wdm %s\n", cdc_wdm); + + cdc_wdm_fd = open(cdc_wdm, O_RDWR | O_NONBLOCK | O_NOCTTY); + if (cdc_wdm_fd == -1) { + dprintf("Failed to open %s, errno: %d (%s). break\n", cdc_wdm, errno, strerror(errno)); + return -1; + } + cfmakenoblock(cdc_wdm_fd); + + /* no qmi_proxy_loop lives, create one */ + pthread_create(&thread_id, NULL, qmi_proxy_loop, NULL); + /* try to redo init if failed, init function must be successfully */ + while (qmi_proxy_init(cdc_wdm, getidproduct) != 0) { + if (retry_times < 5) { + dprintf("fail to init proxy, try again in 2 seconds.\n"); + sleep(2); + retry_times++; + } else { + dprintf("has failed too much times, restart the modem and have a try...\n"); + break; + } + /* break loop if modem is detached */ + if (access(cdc_wdm, F_OK|R_OK|W_OK)) + break; + } + retry_times = 0; + qmi_start_server(); + pthread_join(thread_id, NULL); + + /* close local server at last */ + qmi_close_server(); + close(cdc_wdm_fd); + } + + if (cdc_wdm) { + free(cdc_wdm); + } + return 0; +} diff --git a/package/wwan/app/fibocom-dial/src/libmnl/README b/package/wwan/app/fibocom-dial/src/libmnl/README new file mode 100755 index 000000000..fbac9d2a8 --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/libmnl/README @@ -0,0 +1,28 @@ += What is libmnl? = + +libmnl is a minimalistic user-space library oriented to Netlink developers. +There are a lot of common tasks in parsing, validating, constructing of +both the Netlink header and TLVs that are repetitive and easy to get wrong. +This library aims to provide simple helpers that allows you to re-use code +and to avoid re-inventing the wheel. The main features of this library are: + +* Small: the shared library requires around 30KB for an x86-based computer. +* Simple: this library avoids complexity and elaborated abstractions that +tend to hide Netlink details. +* Easy to use: the library simplifies the work for Netlink-wise developers. +It provides functions to make socket handling, message building, validating, +parsing and sequence tracking, easier. +* Easy to re-use: you can use the library to build your own abstraction layer +on top of this library. +* Decoupling: the interdependency of the main bricks that compose the library +is reduced, i.e. the library provides many helpers, but the programmer is not +forced to use them. + += Example files = + +You can find several example files under examples/ that you can compile by +invoking `make check'. + +-- +08/sep/2010 +Pablo Neira Ayuso diff --git a/package/wwan/app/fibocom-dial/src/libmnl/attr.c b/package/wwan/app/fibocom-dial/src/libmnl/attr.c new file mode 100755 index 000000000..30eb537b4 --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/libmnl/attr.c @@ -0,0 +1,722 @@ +/* + * (C) 2008-2012 by Pablo Neira Ayuso + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + */ +#include /* for INT_MAX */ +#include +#include + +#include "libmnl.h" + +/** + * \defgroup attr Netlink attribute helpers + * + * Netlink Type-Length-Value (TLV) attribute: + * \verbatim + |<-- 2 bytes -->|<-- 2 bytes -->|<-- variable -->| + ------------------------------------------------- + | length | type | value | + ------------------------------------------------- + |<--------- header ------------>|<-- payload --->| +\endverbatim + * The payload of the Netlink message contains sequences of attributes that are + * expressed in TLV format. + * + * @{ + */ + +/** + * mnl_attr_get_type - get type of netlink attribute + * \param attr pointer to netlink attribute + * + * This function returns the attribute type. + */ +uint16_t mnl_attr_get_type(const struct nlattr *attr) +{ + return attr->nla_type & NLA_TYPE_MASK; +} + +/** + * mnl_attr_get_len - get length of netlink attribute + * \param attr pointer to netlink attribute + * + * This function returns the attribute length that is the attribute header + * plus the attribute payload. + */ +uint16_t mnl_attr_get_len(const struct nlattr *attr) +{ + return attr->nla_len; +} + +/** + * mnl_attr_get_payload_len - get the attribute payload-value length + * \param attr pointer to netlink attribute + * + * This function returns the attribute payload-value length. + */ +uint16_t mnl_attr_get_payload_len(const struct nlattr *attr) +{ + return attr->nla_len - MNL_ATTR_HDRLEN; +} + +/** + * mnl_attr_get_payload - get pointer to the attribute payload + * \param attr pointer to netlink attribute + * + * This function return a pointer to the attribute payload. + */ +void *mnl_attr_get_payload(const struct nlattr *attr) +{ + return (void *)attr + MNL_ATTR_HDRLEN; +} + +/** + * mnl_attr_ok - check if there is room for an attribute in a buffer + * \param attr attribute that we want to check if there is room for + * \param len remaining bytes in a buffer that contains the attribute + * + * This function is used to check that a buffer, which is supposed to contain + * an attribute, has enough room for the attribute that it stores, i.e. this + * function can be used to verify that an attribute is neither malformed nor + * truncated. + * + * This function does not set errno in case of error since it is intended + * for iterations. Thus, it returns true on success and false on error. + * + * The len parameter may be negative in the case of malformed messages during + * attribute iteration, that is why we use a signed integer. + */ +bool mnl_attr_ok(const struct nlattr *attr, int len) +{ + return len >= (int)sizeof(struct nlattr) && + attr->nla_len >= sizeof(struct nlattr) && + (int)attr->nla_len <= len; +} + +/** + * mnl_attr_next - get the next attribute in the payload of a netlink message + * \param attr pointer to the current attribute + * + * This function returns a pointer to the next attribute after the one passed + * as parameter. You have to use mnl_attr_ok() to ensure that the next + * attribute is valid. + */ +struct nlattr *mnl_attr_next(const struct nlattr *attr) +{ + return (struct nlattr *)((void *)attr + MNL_ALIGN(attr->nla_len)); +} + +/** + * mnl_attr_type_valid - check if the attribute type is valid + * \param attr pointer to attribute to be checked + * \param max maximum attribute type + * + * This function allows to check if the attribute type is higher than the + * maximum supported type. If the attribute type is invalid, this function + * returns -1 and errno is explicitly set. On success, this function returns 1. + * + * Strict attribute checking in user-space is not a good idea since you may + * run an old application with a newer kernel that supports new attributes. + * This leads to backward compatibility breakages in user-space. Better check + * if you support an attribute, if not, skip it. + */ +int mnl_attr_type_valid(const struct nlattr *attr, uint16_t max) +{ + if (mnl_attr_get_type(attr) > max) { + errno = EOPNOTSUPP; + return -1; + } + return 1; +} + +static int __mnl_attr_validate(const struct nlattr *attr, + enum mnl_attr_data_type type, size_t exp_len) +{ + uint16_t attr_len = mnl_attr_get_payload_len(attr); + const char *attr_data = mnl_attr_get_payload(attr); + + if (attr_len < exp_len) { + errno = ERANGE; + return -1; + } + switch(type) { + case MNL_TYPE_FLAG: + if (attr_len > 0) { + errno = ERANGE; + return -1; + } + break; + case MNL_TYPE_NUL_STRING: + if (attr_len == 0) { + errno = ERANGE; + return -1; + } + if (attr_data[attr_len-1] != '\0') { + errno = EINVAL; + return -1; + } + break; + case MNL_TYPE_STRING: + if (attr_len == 0) { + errno = ERANGE; + return -1; + } + break; + case MNL_TYPE_NESTED: + /* empty nested attributes are OK. */ + if (attr_len == 0) + break; + /* if not empty, they must contain one header, eg. flag */ + if (attr_len < MNL_ATTR_HDRLEN) { + errno = ERANGE; + return -1; + } + break; + default: + /* make gcc happy. */ + break; + } + if (exp_len && attr_len > exp_len) { + errno = ERANGE; + return -1; + } + return 0; +} + +static const size_t mnl_attr_data_type_len[MNL_TYPE_MAX] = { + [MNL_TYPE_U8] = sizeof(uint8_t), + [MNL_TYPE_U16] = sizeof(uint16_t), + [MNL_TYPE_U32] = sizeof(uint32_t), + [MNL_TYPE_U64] = sizeof(uint64_t), + [MNL_TYPE_MSECS] = sizeof(uint64_t), +}; + +/** + * mnl_attr_validate - validate netlink attribute (simplified version) + * \param attr pointer to netlink attribute that we want to validate + * \param type data type (see enum mnl_attr_data_type) + * + * The validation is based on the data type. Specifically, it checks that + * integers (u8, u16, u32 and u64) have enough room for them. This function + * returns -1 in case of error, and errno is explicitly set. + */ +int mnl_attr_validate(const struct nlattr *attr, enum mnl_attr_data_type type) +{ + int exp_len; + + if (type >= MNL_TYPE_MAX) { + errno = EINVAL; + return -1; + } + exp_len = mnl_attr_data_type_len[type]; + return __mnl_attr_validate(attr, type, exp_len); +} + +/** + * mnl_attr_validate2 - validate netlink attribute (extended version) + * \param attr pointer to netlink attribute that we want to validate + * \param type attribute type (see enum mnl_attr_data_type) + * \param exp_len expected attribute data size + * + * This function allows to perform a more accurate validation for attributes + * whose size is variable. If the size of the attribute is not what we expect, + * this functions returns -1 and errno is explicitly set. + */ +int mnl_attr_validate2(const struct nlattr *attr, + enum mnl_attr_data_type type, + size_t exp_len) +{ + if (type >= MNL_TYPE_MAX) { + errno = EINVAL; + return -1; + } + return __mnl_attr_validate(attr, type, exp_len); +} + +/** + * mnl_attr_parse - parse attributes + * \param nlh pointer to netlink message + * \param offset offset to start parsing from (if payload is after any header) + * \param cb callback function that is called for each attribute + * \param data pointer to data that is passed to the callback function + * + * This function allows to iterate over the sequence of attributes that compose + * the Netlink message. You can then put the attribute in an array as it + * usually happens at this stage or you can use any other data structure (such + * as lists or trees). + * + * This function propagates the return value of the callback, which can be + * MNL_CB_ERROR, MNL_CB_OK or MNL_CB_STOP. + */ +int mnl_attr_parse(const struct nlmsghdr *nlh, + unsigned int offset, mnl_attr_cb_t cb, + void *data) +{ + int ret = MNL_CB_OK; + const struct nlattr *attr; + + mnl_attr_for_each(attr, nlh, offset) + if ((ret = cb(attr, data)) <= MNL_CB_STOP) + return ret; + return ret; +} + +/** + * mnl_attr_parse_nested - parse attributes inside a nest + * \param nested pointer to netlink attribute that contains a nest + * \param cb callback function that is called for each attribute in the nest + * \param data pointer to data passed to the callback function + * + * This function allows to iterate over the sequence of attributes that compose + * the Netlink message. You can then put the attribute in an array as it + * usually happens at this stage or you can use any other data structure (such + * as lists or trees). + * + * This function propagates the return value of the callback, which can be + * MNL_CB_ERROR, MNL_CB_OK or MNL_CB_STOP. + */ +int mnl_attr_parse_nested(const struct nlattr *nested, + mnl_attr_cb_t cb, void *data) +{ + int ret = MNL_CB_OK; + const struct nlattr *attr; + + mnl_attr_for_each_nested(attr, nested) + if ((ret = cb(attr, data)) <= MNL_CB_STOP) + return ret; + return ret; +} + +/** + * mnl_attr_parse_payload - parse attributes in payload of Netlink message + * \param payload pointer to payload of the Netlink message + * \param payload_len payload length that contains the attributes + * \param cb callback function that is called for each attribute + * \param data pointer to data that is passed to the callback function + * + * This function takes a pointer to the area that contains the attributes, + * commonly known as the payload of the Netlink message. Thus, you have to + * pass a pointer to the Netlink message payload, instead of the entire + * message. + * + * This function allows you to iterate over the sequence of attributes that are + * located at some payload offset. You can then put the attributes in one array + * as usual, or you can use any other data structure (such as lists or trees). + * + * This function propagates the return value of the callback, which can be + * MNL_CB_ERROR, MNL_CB_OK or MNL_CB_STOP. + */ +int mnl_attr_parse_payload(const void *payload, + size_t payload_len, + mnl_attr_cb_t cb, void *data) +{ + int ret = MNL_CB_OK; + const struct nlattr *attr; + + mnl_attr_for_each_payload(payload, payload_len) + if ((ret = cb(attr, data)) <= MNL_CB_STOP) + return ret; + return ret; +} + +/** + * mnl_attr_get_u8 - returns 8-bit unsigned integer attribute payload + * \param attr pointer to netlink attribute + * + * This function returns the 8-bit value of the attribute payload. + */ +uint8_t mnl_attr_get_u8(const struct nlattr *attr) +{ + return *((uint8_t *)mnl_attr_get_payload(attr)); +} + +/** + * mnl_attr_get_u16 - returns 16-bit unsigned integer attribute payload + * \param attr pointer to netlink attribute + * + * This function returns the 16-bit value of the attribute payload. + */ +uint16_t mnl_attr_get_u16(const struct nlattr *attr) +{ + return *((uint16_t *)mnl_attr_get_payload(attr)); +} + +/** + * mnl_attr_get_u32 - returns 32-bit unsigned integer attribute payload + * \param attr pointer to netlink attribute + * + * This function returns the 32-bit value of the attribute payload. + */ +uint32_t mnl_attr_get_u32(const struct nlattr *attr) +{ + return *((uint32_t *)mnl_attr_get_payload(attr)); +} + +/** + * mnl_attr_get_u64 - returns 64-bit unsigned integer attribute. + * \param attr pointer to netlink attribute + * + * This function returns the 64-bit value of the attribute payload. This + * function is align-safe, since accessing 64-bit Netlink attributes is a + * common source of alignment issues. + */ +uint64_t mnl_attr_get_u64(const struct nlattr *attr) +{ + uint64_t tmp; + memcpy(&tmp, mnl_attr_get_payload(attr), sizeof(tmp)); + return tmp; +} + +/** + * mnl_attr_get_str - returns pointer to string attribute. + * \param attr pointer to netlink attribute + * + * This function returns the payload of string attribute value. + */ +const char *mnl_attr_get_str(const struct nlattr *attr) +{ + return mnl_attr_get_payload(attr); +} + +/** + * mnl_attr_put - add an attribute to netlink message + * \param nlh pointer to the netlink message + * \param type netlink attribute type that you want to add + * \param len netlink attribute payload length + * \param data pointer to the data that will be stored by the new attribute + * + * This function updates the length field of the Netlink message (nlmsg_len) + * by adding the size (header + payload) of the new attribute. + */ +void mnl_attr_put(struct nlmsghdr *nlh, uint16_t type, + size_t len, const void *data) +{ + struct nlattr *attr = mnl_nlmsg_get_payload_tail(nlh); + uint16_t payload_len = MNL_ALIGN(sizeof(struct nlattr)) + len; + int pad; + + attr->nla_type = type; + attr->nla_len = payload_len; + memcpy(mnl_attr_get_payload(attr), data, len); + pad = MNL_ALIGN(len) - len; + if (pad > 0) + memset(mnl_attr_get_payload(attr) + len, 0, pad); + + nlh->nlmsg_len += MNL_ALIGN(payload_len); +} + +/** + * mnl_attr_put_u8 - add 8-bit unsigned integer attribute to netlink message + * \param nlh pointer to the netlink message + * \param type netlink attribute type + * \param data 8-bit unsigned integer data that is stored by the new attribute + * + * This function updates the length field of the Netlink message (nlmsg_len) + * by adding the size (header + payload) of the new attribute. + */ +void mnl_attr_put_u8(struct nlmsghdr *nlh, uint16_t type, + uint8_t data) +{ + mnl_attr_put(nlh, type, sizeof(uint8_t), &data); +} + +/** + * mnl_attr_put_u16 - add 16-bit unsigned integer attribute to netlink message + * \param nlh pointer to the netlink message + * \param type netlink attribute type + * \param data 16-bit unsigned integer data that is stored by the new attribute + * + * This function updates the length field of the Netlink message (nlmsg_len) + * by adding the size (header + payload) of the new attribute. + */ +void mnl_attr_put_u16(struct nlmsghdr *nlh, uint16_t type, + uint16_t data) +{ + mnl_attr_put(nlh, type, sizeof(uint16_t), &data); +} + +/** + * mnl_attr_put_u32 - add 32-bit unsigned integer attribute to netlink message + * \param nlh pointer to the netlink message + * \param type netlink attribute type + * \param data 32-bit unsigned integer data that is stored by the new attribute + * + * This function updates the length field of the Netlink message (nlmsg_len) + * by adding the size (header + payload) of the new attribute. + */ +void mnl_attr_put_u32(struct nlmsghdr *nlh, uint16_t type, + uint32_t data) +{ + mnl_attr_put(nlh, type, sizeof(uint32_t), &data); +} + +/** + * mnl_attr_put_u64 - add 64-bit unsigned integer attribute to netlink message + * \param nlh pointer to the netlink message + * \param type netlink attribute type + * \param data 64-bit unsigned integer data that is stored by the new attribute + * + * This function updates the length field of the Netlink message (nlmsg_len) + * by adding the size (header + payload) of the new attribute. + */ +void mnl_attr_put_u64(struct nlmsghdr *nlh, uint16_t type, + uint64_t data) +{ + mnl_attr_put(nlh, type, sizeof(uint64_t), &data); +} + +/** + * mnl_attr_put_str - add string attribute to netlink message + * \param nlh pointer to the netlink message + * \param type netlink attribute type + * \param data pointer to string data that is stored by the new attribute + * + * This function updates the length field of the Netlink message (nlmsg_len) + * by adding the size (header + payload) of the new attribute. + */ +void mnl_attr_put_str(struct nlmsghdr *nlh, uint16_t type, + const char *data) +{ + mnl_attr_put(nlh, type, strlen(data), data); +} + +/** + * mnl_attr_put_strz - add string attribute to netlink message + * \param nlh pointer to the netlink message + * \param type netlink attribute type + * \param data pointer to string data that is stored by the new attribute + * + * This function is similar to mnl_attr_put_str, but it includes the + * NUL/zero ('\0') terminator at the end of the string. + * + * This function updates the length field of the Netlink message (nlmsg_len) + * by adding the size (header + payload) of the new attribute. + */ +void mnl_attr_put_strz(struct nlmsghdr *nlh, uint16_t type, + const char *data) +{ + mnl_attr_put(nlh, type, strlen(data)+1, data); +} + +/** + * mnl_attr_nest_start - start an attribute nest + * \param nlh pointer to the netlink message + * \param type netlink attribute type + * + * This function adds the attribute header that identifies the beginning of + * an attribute nest. This function always returns a valid pointer to the + * beginning of the nest. + */ +struct nlattr *mnl_attr_nest_start(struct nlmsghdr *nlh, + uint16_t type) +{ + struct nlattr *start = mnl_nlmsg_get_payload_tail(nlh); + + /* set start->nla_len in mnl_attr_nest_end() */ + start->nla_type = NLA_F_NESTED | type; + nlh->nlmsg_len += MNL_ALIGN(sizeof(struct nlattr)); + + return start; +} + +/** + * mnl_attr_put_check - add an attribute to netlink message + * \param nlh pointer to the netlink message + * \param buflen size of buffer which stores the message + * \param type netlink attribute type that you want to add + * \param len netlink attribute payload length + * \param data pointer to the data that will be stored by the new attribute + * + * This function first checks that the data can be added to the message + * (fits into the buffer) and then updates the length field of the Netlink + * message (nlmsg_len) by adding the size (header + payload) of the new + * attribute. The function returns true if the attribute could be added + * to the message, otherwise false is returned. + */ +bool mnl_attr_put_check(struct nlmsghdr *nlh, size_t buflen, + uint16_t type, size_t len, + const void *data) +{ + if (nlh->nlmsg_len + MNL_ATTR_HDRLEN + MNL_ALIGN(len) > buflen) + return false; + mnl_attr_put(nlh, type, len, data); + return true; +} + +/** + * mnl_attr_put_u8_check - add 8-bit unsigned int attribute to netlink message + * \param nlh pointer to the netlink message + * \param buflen size of buffer which stores the message + * \param type netlink attribute type + * \param data 8-bit unsigned integer data that is stored by the new attribute + * + * This function first checks that the data can be added to the message + * (fits into the buffer) and then updates the length field of the Netlink + * message (nlmsg_len) by adding the size (header + payload) of the new + * attribute. The function returns true if the attribute could be added + * to the message, otherwise false is returned. + */ +bool mnl_attr_put_u8_check(struct nlmsghdr *nlh, size_t buflen, + uint16_t type, uint8_t data) +{ + return mnl_attr_put_check(nlh, buflen, type, sizeof(uint8_t), &data); +} + +/** + * mnl_attr_put_u16_check - add 16-bit unsigned int attribute to netlink message + * \param nlh pointer to the netlink message + * \param buflen size of buffer which stores the message + * \param type netlink attribute type + * \param data 16-bit unsigned integer data that is stored by the new attribute + * + * This function first checks that the data can be added to the message + * (fits into the buffer) and then updates the length field of the Netlink + * message (nlmsg_len) by adding the size (header + payload) of the new + * attribute. The function returns true if the attribute could be added + * to the message, otherwise false is returned. + * This function updates the length field of the Netlink message (nlmsg_len) + * by adding the size (header + payload) of the new attribute. + */ +bool mnl_attr_put_u16_check(struct nlmsghdr *nlh, size_t buflen, + uint16_t type, uint16_t data) +{ + return mnl_attr_put_check(nlh, buflen, type, sizeof(uint16_t), &data); +} + +/** + * mnl_attr_put_u32_check - add 32-bit unsigned int attribute to netlink message + * \param nlh pointer to the netlink message + * \param buflen size of buffer which stores the message + * \param type netlink attribute type + * \param data 32-bit unsigned integer data that is stored by the new attribute + * + * This function first checks that the data can be added to the message + * (fits into the buffer) and then updates the length field of the Netlink + * message (nlmsg_len) by adding the size (header + payload) of the new + * attribute. The function returns true if the attribute could be added + * to the message, otherwise false is returned. + * This function updates the length field of the Netlink message (nlmsg_len) + * by adding the size (header + payload) of the new attribute. + */ +bool mnl_attr_put_u32_check(struct nlmsghdr *nlh, size_t buflen, + uint16_t type, uint32_t data) +{ + return mnl_attr_put_check(nlh, buflen, type, sizeof(uint32_t), &data); +} + +/** + * mnl_attr_put_u64_check - add 64-bit unsigned int attribute to netlink message + * \param nlh pointer to the netlink message + * \param buflen size of buffer which stores the message + * \param type netlink attribute type + * \param data 64-bit unsigned integer data that is stored by the new attribute + * + * This function first checks that the data can be added to the message + * (fits into the buffer) and then updates the length field of the Netlink + * message (nlmsg_len) by adding the size (header + payload) of the new + * attribute. The function returns true if the attribute could be added + * to the message, otherwise false is returned. + * This function updates the length field of the Netlink message (nlmsg_len) + * by adding the size (header + payload) of the new attribute. + */ +bool mnl_attr_put_u64_check(struct nlmsghdr *nlh, size_t buflen, + uint16_t type, uint64_t data) +{ + return mnl_attr_put_check(nlh, buflen, type, sizeof(uint64_t), &data); +} + +/** + * mnl_attr_put_str_check - add string attribute to netlink message + * \param nlh pointer to the netlink message + * \param buflen size of buffer which stores the message + * \param type netlink attribute type + * \param data pointer to string data that is stored by the new attribute + * + * This function first checks that the data can be added to the message + * (fits into the buffer) and then updates the length field of the Netlink + * message (nlmsg_len) by adding the size (header + payload) of the new + * attribute. The function returns true if the attribute could be added + * to the message, otherwise false is returned. + * This function updates the length field of the Netlink message (nlmsg_len) + * by adding the size (header + payload) of the new attribute. + */ +bool mnl_attr_put_str_check(struct nlmsghdr *nlh, size_t buflen, + uint16_t type, const char *data) +{ + return mnl_attr_put_check(nlh, buflen, type, strlen(data), data); +} + +/** + * mnl_attr_put_strz_check - add string attribute to netlink message + * \param nlh pointer to the netlink message + * \param buflen size of buffer which stores the message + * \param type netlink attribute type + * \param data pointer to string data that is stored by the new attribute + * + * This function is similar to mnl_attr_put_str, but it includes the + * NUL/zero ('\0') terminator at the end of the string. + * + * This function first checks that the data can be added to the message + * (fits into the buffer) and then updates the length field of the Netlink + * message (nlmsg_len) by adding the size (header + payload) of the new + * attribute. The function returns true if the attribute could be added + * to the message, otherwise false is returned. + */ +bool mnl_attr_put_strz_check(struct nlmsghdr *nlh, size_t buflen, + uint16_t type, const char *data) +{ + return mnl_attr_put_check(nlh, buflen, type, strlen(data)+1, data); +} + +/** + * mnl_attr_nest_start_check - start an attribute nest + * \param buflen size of buffer which stores the message + * \param nlh pointer to the netlink message + * \param type netlink attribute type + * + * This function adds the attribute header that identifies the beginning of + * an attribute nest. If the nested attribute cannot be added then NULL, + * otherwise valid pointer to the beginning of the nest is returned. + */ +struct nlattr *mnl_attr_nest_start_check(struct nlmsghdr *nlh, + size_t buflen, + uint16_t type) +{ + if (nlh->nlmsg_len + MNL_ATTR_HDRLEN > buflen) + return NULL; + return mnl_attr_nest_start(nlh, type); +} + +/** + * mnl_attr_nest_end - end an attribute nest + * \param nlh pointer to the netlink message + * \param start pointer to the attribute nest returned by mnl_attr_nest_start() + * + * This function updates the attribute header that identifies the nest. + */ +void mnl_attr_nest_end(struct nlmsghdr *nlh, + struct nlattr *start) +{ + start->nla_len = mnl_nlmsg_get_payload_tail(nlh) - (void *)start; +} + +/** + * mnl_attr_nest_cancel - cancel an attribute nest + * \param nlh pointer to the netlink message + * \param start pointer to the attribute nest returned by mnl_attr_nest_start() + * + * This function updates the attribute header that identifies the nest. + */ +void mnl_attr_nest_cancel(struct nlmsghdr *nlh, + struct nlattr *start) +{ + nlh->nlmsg_len -= mnl_nlmsg_get_payload_tail(nlh) - (void *)start; +} + +/** + * @} + */ diff --git a/package/wwan/app/fibocom-dial/src/libmnl/callback.c b/package/wwan/app/fibocom-dial/src/libmnl/callback.c new file mode 100755 index 000000000..8283a93b9 --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/libmnl/callback.c @@ -0,0 +1,167 @@ +/* + * (C) 2008-2010 by Pablo Neira Ayuso + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + */ + +#include + +#include "libmnl.h" + +static int mnl_cb_noop(const struct nlmsghdr *nlh, void *data) +{ + return MNL_CB_OK; +} + +static int mnl_cb_error(const struct nlmsghdr *nlh, void *data) +{ + const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh); + + if (nlh->nlmsg_len < mnl_nlmsg_size(sizeof(struct nlmsgerr))) { + errno = EBADMSG; + return MNL_CB_ERROR; + } + /* Netlink subsystems returns the errno value with different signess */ + if (err->error < 0) + errno = -err->error; + else + errno = err->error; + + return err->error == 0 ? MNL_CB_STOP : MNL_CB_ERROR; +} + +static int mnl_cb_stop(const struct nlmsghdr *nlh, void *data) +{ + return MNL_CB_STOP; +} + +static const mnl_cb_t default_cb_array[NLMSG_MIN_TYPE] = { + [NLMSG_NOOP] = mnl_cb_noop, + [NLMSG_ERROR] = mnl_cb_error, + [NLMSG_DONE] = mnl_cb_stop, + [NLMSG_OVERRUN] = mnl_cb_noop, +}; + +static inline int __mnl_cb_run(const void *buf, size_t numbytes, + unsigned int seq, unsigned int portid, + mnl_cb_t cb_data, void *data, + const mnl_cb_t *cb_ctl_array, + unsigned int cb_ctl_array_len) +{ + int ret = MNL_CB_OK, len = numbytes; + const struct nlmsghdr *nlh = buf; + + while (mnl_nlmsg_ok(nlh, len)) { + /* check message source */ + if (!mnl_nlmsg_portid_ok(nlh, portid)) { + errno = ESRCH; + return -1; + } + /* perform sequence tracking */ + if (!mnl_nlmsg_seq_ok(nlh, seq)) { + errno = EPROTO; + return -1; + } + + /* dump was interrupted */ + if (nlh->nlmsg_flags & NLM_F_DUMP_INTR) { + errno = EINTR; + return -1; + } + + /* netlink data message handling */ + if (nlh->nlmsg_type >= NLMSG_MIN_TYPE) { + if (cb_data){ + ret = cb_data(nlh, data); + if (ret <= MNL_CB_STOP) + goto out; + } + } else if (nlh->nlmsg_type < cb_ctl_array_len) { + if (cb_ctl_array && cb_ctl_array[nlh->nlmsg_type]) { + ret = cb_ctl_array[nlh->nlmsg_type](nlh, data); + if (ret <= MNL_CB_STOP) + goto out; + } + } else if (default_cb_array[nlh->nlmsg_type]) { + ret = default_cb_array[nlh->nlmsg_type](nlh, data); + if (ret <= MNL_CB_STOP) + goto out; + } + nlh = mnl_nlmsg_next(nlh, &len); + } +out: + return ret; +} + +/** + * \defgroup callback Callback helpers + * @{ + */ + +/** + * mnl_cb_run2 - callback runqueue for netlink messages + * \param buf buffer that contains the netlink messages + * \param numbytes number of bytes stored in the buffer + * \param seq sequence number that we expect to receive + * \param portid Netlink PortID that we expect to receive + * \param cb_data callback handler for data messages + * \param data pointer to data that will be passed to the data callback handler + * \param cb_ctl_array array of custom callback handlers from control messages + * \param cb_ctl_array_len array length of custom control callback handlers + * + * You can set the cb_ctl_array to NULL if you want to use the default control + * callback handlers, in that case, the parameter cb_ctl_array_len is not + * checked. + * + * Your callback may return three possible values: + * - MNL_CB_ERROR (<=-1): an error has occurred. Stop callback runqueue. + * - MNL_CB_STOP (=0): stop callback runqueue. + * - MNL_CB_OK (>=1): no problem has occurred. + * + * This function propagates the callback return value. On error, it returns + * -1 and errno is explicitly set. If the portID is not the expected, errno + * is set to ESRCH. If the sequence number is not the expected, errno is set + * to EPROTO. If the dump was interrupted, errno is set to EINTR and you should + * request a new fresh dump again. + */ +int mnl_cb_run2(const void *buf, size_t numbytes, + unsigned int seq, unsigned int portid, + mnl_cb_t cb_data, void *data, + const mnl_cb_t *cb_ctl_array, + unsigned int cb_ctl_array_len) +{ + return __mnl_cb_run(buf, numbytes, seq, portid, cb_data, data, + cb_ctl_array, cb_ctl_array_len); +} + +/** + * mnl_cb_run - callback runqueue for netlink messages (simplified version) + * \param buf buffer that contains the netlink messages + * \param numbytes number of bytes stored in the buffer + * \param seq sequence number that we expect to receive + * \param portid Netlink PortID that we expect to receive + * \param cb_data callback handler for data messages + * \param data pointer to data that will be passed to the data callback handler + * + * This function is like mnl_cb_run2() but it does not allow you to set + * the control callback handlers. + * + * Your callback may return three possible values: + * - MNL_CB_ERROR (<=-1): an error has occurred. Stop callback runqueue. + * - MNL_CB_STOP (=0): stop callback runqueue. + * - MNL_CB_OK (>=1): no problems has occurred. + * + * This function propagates the callback return value. + */ +int mnl_cb_run(const void *buf, size_t numbytes, unsigned int seq, + unsigned int portid, mnl_cb_t cb_data, void *data) +{ + return __mnl_cb_run(buf, numbytes, seq, portid, cb_data, data, NULL, 0); +} + +/** + * @} + */ diff --git a/package/wwan/app/fibocom-dial/src/libmnl/dhcp/dhcp.h b/package/wwan/app/fibocom-dial/src/libmnl/dhcp/dhcp.h new file mode 100755 index 000000000..f48028552 --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/libmnl/dhcp/dhcp.h @@ -0,0 +1,5 @@ +#ifndef __DHCP_H__ +#define __DHCP_H__ + +int do_dhcp(char *iname); +#endif //__DHCP_H__ \ No newline at end of file diff --git a/package/wwan/app/fibocom-dial/src/libmnl/dhcp/dhcpclient.c b/package/wwan/app/fibocom-dial/src/libmnl/dhcp/dhcpclient.c new file mode 100755 index 000000000..ccb71b5d8 --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/libmnl/dhcp/dhcpclient.c @@ -0,0 +1,515 @@ +/* + * Copyright 2008, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../ifutils.h" +#include "dhcpmsg.h" +#include "packet.h" + +#define VERBOSE 2 + +static int verbose = 1; +static char errmsg[2048]; + +typedef unsigned long long msecs_t; +#if VERBOSE +void dump_dhcp_msg(); +#endif + +msecs_t get_msecs(void) +{ + struct timespec ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts)) { + return 0; + } else { + return (((msecs_t) ts.tv_sec) * ((msecs_t) 1000)) + + (((msecs_t) ts.tv_nsec) / ((msecs_t) 1000000)); + } +} + +void printerr(char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vsnprintf(errmsg, sizeof(errmsg), fmt, ap); + va_end(ap); + + printf("%s\n", errmsg); +} + +const char *dhcp_lasterror() +{ + return errmsg; +} + +int fatal(const char *reason) +{ + printerr("%s: %s\n", reason, strerror(errno)); + return -1; +// exit(1); +} + +typedef struct dhcp_info dhcp_info; + +struct dhcp_info { + uint32_t type; + + uint32_t ipaddr; + uint32_t gateway; + uint32_t prefixLength; + + uint32_t dns1; + uint32_t dns2; + + uint32_t serveraddr; + uint32_t lease; +}; + +dhcp_info last_good_info; + +void get_dhcp_info(uint32_t *ipaddr, uint32_t *gateway, uint32_t *prefixLength, + uint32_t *dns1, uint32_t *dns2, uint32_t *server, + uint32_t *lease) +{ + *ipaddr = last_good_info.ipaddr; + *gateway = last_good_info.gateway; + *prefixLength = last_good_info.prefixLength; + *dns1 = last_good_info.dns1; + *dns2 = last_good_info.dns2; + *server = last_good_info.serveraddr; + *lease = last_good_info.lease; +} + +static int dhcp_configure(const char *ifname, dhcp_info *info) +{ + last_good_info = *info; + return if_set_network_v4(ifname, info->ipaddr, info->prefixLength, info->gateway, + info->dns1, info->dns2); +} + +static const char *dhcp_type_to_name(uint32_t type) +{ + switch(type) { + case DHCPDISCOVER: return "discover"; + case DHCPOFFER: return "offer"; + case DHCPREQUEST: return "request"; + case DHCPDECLINE: return "decline"; + case DHCPACK: return "ack"; + case DHCPNAK: return "nak"; + case DHCPRELEASE: return "release"; + case DHCPINFORM: return "inform"; + default: return "???"; + } +} + +void dump_dhcp_info(dhcp_info *info) +{ + char addr[20], gway[20]; + printf("--- dhcp %s (%d) ---\n", + dhcp_type_to_name(info->type), info->type); + strcpy(addr, ipaddr_to_string_v4(info->ipaddr)); + strcpy(gway, ipaddr_to_string_v4(info->gateway)); + printf("ip %s gw %s prefixLength %d\n", addr, gway, info->prefixLength); + if (info->dns1) printf("dns1: %s\n", ipaddr_to_string_v4(info->dns1)); + if (info->dns2) printf("dns2: %s\n", ipaddr_to_string_v4(info->dns2)); + printf("server %s, lease %d seconds\n", + ipaddr_to_string_v4(info->serveraddr), info->lease); +} + + +int decode_dhcp_msg(dhcp_msg *msg, int len, dhcp_info *info) +{ + uint8_t *x; + unsigned int opt; + int optlen; + + memset(info, 0, sizeof(dhcp_info)); + if (len < (DHCP_MSG_FIXED_SIZE + 4)) return -1; + + len -= (DHCP_MSG_FIXED_SIZE + 4); + + if (msg->options[0] != OPT_COOKIE1) return -1; + if (msg->options[1] != OPT_COOKIE2) return -1; + if (msg->options[2] != OPT_COOKIE3) return -1; + if (msg->options[3] != OPT_COOKIE4) return -1; + + x = msg->options + 4; + + while (len > 2) { + opt = *x++; + if (opt == OPT_PAD) { + len--; + continue; + } + if (opt == OPT_END) { + break; + } + optlen = *x++; + len -= 2; + if (optlen > len) { + break; + } + switch(opt) { + case OPT_SUBNET_MASK: + if (optlen >= 4) { + in_addr_t mask; + memcpy(&mask, x, 4); + info->prefixLength = mask_to_prefix_v4(mask); + } + break; + case OPT_GATEWAY: + if (optlen >= 4) memcpy(&info->gateway, x, 4); + break; + case OPT_DNS: + if (optlen >= 4) memcpy(&info->dns1, x + 0, 4); + if (optlen >= 8) memcpy(&info->dns2, x + 4, 4); + break; + case OPT_LEASE_TIME: + if (optlen >= 4) { + memcpy(&info->lease, x, 4); + info->lease = ntohl(info->lease); + } + break; + case OPT_SERVER_ID: + if (optlen >= 4) memcpy(&info->serveraddr, x, 4); + break; + case OPT_MESSAGE_TYPE: + info->type = *x; + break; + default: + break; + } + x += optlen; + len -= optlen; + } + + info->ipaddr = msg->yiaddr; + + return 0; +} + +#if VERBOSE + +static void hex2str(char *buf, size_t buf_size, const unsigned char *array, int len) +{ + int i; + char *cp = buf; + char *buf_end = buf + buf_size; + for (i = 0; i < len; i++) { + cp += snprintf(cp, buf_end - cp, " %02x ", array[i]); + } +} + +void dump_dhcp_msg(dhcp_msg *msg, int len) +{ + unsigned char *x; + unsigned int n,c; + int optsz; + const char *name; + char buf[2048]; + + if (len < DHCP_MSG_FIXED_SIZE) { + printf("Invalid length %d, should be %d", len, DHCP_MSG_FIXED_SIZE); + return; + } + + len -= DHCP_MSG_FIXED_SIZE; + + if (msg->op == OP_BOOTREQUEST) + name = "BOOTREQUEST"; + else if (msg->op == OP_BOOTREPLY) + name = "BOOTREPLY"; + else + name = "????"; + + c = msg->hlen > 16 ? 16 : msg->hlen; + hex2str(buf, sizeof(buf), msg->chaddr, c); + + for (n = 0; n < 64; n++) { + unsigned char x = msg->sname[n]; + if ((x < ' ') || (x > 127)) { + if (x == 0) break; + msg->sname[n] = '.'; + } + } + msg->sname[63] = 0; + + for (n = 0; n < 128; n++) { + unsigned char x = msg->file[n]; + if ((x < ' ') || (x > 127)) { + if (x == 0) break; + msg->file[n] = '.'; + } + } + msg->file[127] = 0; + + if (len < 4) return; + len -= 4; + x = msg->options + 4; + + while (len > 2) { + if (*x == 0) { + x++; + len--; + continue; + } + if (*x == OPT_END) { + break; + } + len -= 2; + optsz = x[1]; + if (optsz > len) break; + if (x[0] == OPT_DOMAIN_NAME || x[0] == OPT_MESSAGE) { + if ((unsigned int)optsz < sizeof(buf) - 1) { + n = optsz; + } else { + n = sizeof(buf) - 1; + } + memcpy(buf, &x[2], n); + buf[n] = '\0'; + } else { + hex2str(buf, sizeof(buf), &x[2], optsz); + } + if (x[0] == OPT_MESSAGE_TYPE) + name = dhcp_type_to_name(x[2]); + else + name = NULL; + len -= optsz; + x = x + optsz + 2; + } +} + +#endif + +static int send_message(int sock, int if_index, dhcp_msg *msg, int size) +{ +#if VERBOSE > 1 + dump_dhcp_msg(msg, size); +#endif + return send_packet(sock, if_index, msg, size, INADDR_ANY, INADDR_BROADCAST, + PORT_BOOTP_CLIENT, PORT_BOOTP_SERVER); +} + +static int is_valid_reply(dhcp_msg *msg, dhcp_msg *reply, int sz) +{ + if (sz < DHCP_MSG_FIXED_SIZE) { + if (verbose) printf("Wrong size %d != %d\n", sz, DHCP_MSG_FIXED_SIZE); + return 0; + } + if (reply->op != OP_BOOTREPLY) { + if (verbose) printf("Wrong Op %d != %d\n", reply->op, OP_BOOTREPLY); + return 0; + } + if (reply->xid != msg->xid) { + if (verbose) printf("Wrong Xid 0x%x != 0x%x\n", ntohl(reply->xid), + ntohl(msg->xid)); + return 0; + } + if (reply->htype != msg->htype) { + if (verbose) printf("Wrong Htype %d != %d\n", reply->htype, msg->htype); + return 0; + } + if (reply->hlen != msg->hlen) { + if (verbose) printf("Wrong Hlen %d != %d\n", reply->hlen, msg->hlen); + return 0; + } + if (memcmp(msg->chaddr, reply->chaddr, msg->hlen)) { + if (verbose) printf("Wrong chaddr %x != %x\n", *(reply->chaddr),*(msg->chaddr)); + return 0; + } + return 1; +} + +#define STATE_SELECTING 1 +#define STATE_REQUESTING 2 + +#define TIMEOUT_INITIAL 4000 +#define TIMEOUT_MAX 32000 + +int dhcp_init_ifc(const char *ifname) +{ + dhcp_msg discover_msg; + dhcp_msg request_msg; + dhcp_msg reply; + dhcp_msg *msg; + dhcp_info info; + int s, r, size; + int valid_reply; + uint32_t xid; + unsigned char hwaddr[6]; + struct pollfd pfd; + unsigned int state; + unsigned int timeout; + int if_index; + + xid = (uint32_t) get_msecs(); + + if (if_get_hwaddr(ifname, hwaddr)) { + return fatal("cannot obtain interface address"); + } + if ((if_index = if_nametoindex(ifname)) == 0) { + return fatal("cannot obtain interface index"); + } + + s = open_raw_socket(ifname, hwaddr, if_index); + + timeout = TIMEOUT_INITIAL; + state = STATE_SELECTING; + info.type = 0; + goto transmit; + + for (;;) { + pfd.fd = s; + pfd.events = POLLIN; + pfd.revents = 0; + r = poll(&pfd, 1, timeout); + + if (r == 0) { +#if VERBOSE + printerr("TIMEOUT\n"); +#endif + if (timeout >= TIMEOUT_MAX) { + printerr("timed out\n"); + if ( info.type == DHCPOFFER ) { + printerr("no acknowledgement from DHCP server\nconfiguring %s with offered parameters\n", ifname); + return dhcp_configure(ifname, &info); + } + errno = ETIME; + close(s); + return -1; + } + timeout = timeout * 2; + + transmit: + size = 0; + msg = NULL; + switch(state) { + case STATE_SELECTING: + msg = &discover_msg; + size = init_dhcp_discover_msg(msg, hwaddr, xid); + break; + case STATE_REQUESTING: + msg = &request_msg; + size = init_dhcp_request_msg(msg, hwaddr, xid, info.ipaddr, info.serveraddr); + break; + default: + r = 0; + } + if (size != 0) { + r = send_message(s, if_index, msg, size); + if (r < 0) { + printerr("error sending dhcp msg: %s\n", strerror(errno)); + } + } + continue; + } + + if (r < 0) { + if ((errno == EAGAIN) || (errno == EINTR)) { + continue; + } + return fatal("poll failed"); + } + + errno = 0; + r = receive_packet(s, &reply); + if (r < 0) { + if (errno != 0) { + printf("receive_packet failed (%d): %s", r, strerror(errno)); + if (errno == ENETDOWN || errno == ENXIO) { + return -1; + } + } + continue; + } + +#if VERBOSE > 1 + dump_dhcp_msg(&reply, r); +#endif + decode_dhcp_msg(&reply, r, &info); + + if (state == STATE_SELECTING) { + valid_reply = is_valid_reply(&discover_msg, &reply, r); + } else { + valid_reply = is_valid_reply(&request_msg, &reply, r); + } + if (!valid_reply) { + printerr("invalid reply\n"); + continue; + } + + if (verbose) dump_dhcp_info(&info); + + switch(state) { + case STATE_SELECTING: + if (info.type == DHCPOFFER) { + state = STATE_REQUESTING; + timeout = TIMEOUT_INITIAL; + xid++; + goto transmit; + } + break; + case STATE_REQUESTING: + if (info.type == DHCPACK) { + printerr("configuring %s\n", ifname); + close(s); + return dhcp_configure(ifname, &info); + } else if (info.type == DHCPNAK) { + printerr("configuration request denied\n"); + close(s); + return -1; + } else { + printerr("ignoring %s message in state %d\n", + dhcp_type_to_name(info.type), state); + } + break; + } + } + close(s); + return 0; +} + +int do_dhcp(char *iname) +{ + if (if_set_addr_v4(iname, 0, 32)) { + printerr("failed to set ip addr for %s to 0.0.0.0: %s\n", iname, strerror(errno)); + return -1; + } + + if (if_link_up(iname)) { + printerr("failed to bring up interface %s: %s\n", iname, strerror(errno)); + return -1; + } + + return dhcp_init_ifc(iname); +} diff --git a/package/wwan/app/fibocom-dial/src/libmnl/dhcp/dhcpmsg.c b/package/wwan/app/fibocom-dial/src/libmnl/dhcp/dhcpmsg.c new file mode 100755 index 000000000..1e0a233fc --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/libmnl/dhcp/dhcpmsg.c @@ -0,0 +1,100 @@ +/* + * Copyright 2008, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include "dhcpmsg.h" + +static void *init_dhcp_msg(dhcp_msg *msg, int type, void *hwaddr, uint32_t xid) +{ + uint8_t *x; + + memset(msg, 0, sizeof(dhcp_msg)); + + msg->op = OP_BOOTREQUEST; + msg->htype = HTYPE_ETHER; + msg->hlen = 6; + msg->hops = 0; + + msg->flags = htons(FLAGS_BROADCAST); + + msg->xid = xid; + + memcpy(msg->chaddr, hwaddr, 6); + + x = msg->options; + + *x++ = OPT_COOKIE1; + *x++ = OPT_COOKIE2; + *x++ = OPT_COOKIE3; + *x++ = OPT_COOKIE4; + + *x++ = OPT_MESSAGE_TYPE; + *x++ = 1; + *x++ = type; + + return x; +} + +int init_dhcp_discover_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid) +{ + uint8_t *x; + + x = init_dhcp_msg(msg, DHCPDISCOVER, hwaddr, xid); + + *x++ = OPT_PARAMETER_LIST; + *x++ = 4; + *x++ = OPT_SUBNET_MASK; + *x++ = OPT_GATEWAY; + *x++ = OPT_DNS; + *x++ = OPT_BROADCAST_ADDR; + + *x++ = OPT_END; + + return DHCP_MSG_FIXED_SIZE + (x - msg->options); +} + +int init_dhcp_request_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid, + uint32_t ipaddr, uint32_t serveraddr) +{ + uint8_t *x; + + x = init_dhcp_msg(msg, DHCPREQUEST, hwaddr, xid); + + *x++ = OPT_PARAMETER_LIST; + *x++ = 4; + *x++ = OPT_SUBNET_MASK; + *x++ = OPT_GATEWAY; + *x++ = OPT_DNS; + *x++ = OPT_BROADCAST_ADDR; + + *x++ = OPT_REQUESTED_IP; + *x++ = 4; + memcpy(x, &ipaddr, 4); + x += 4; + + *x++ = OPT_SERVER_ID; + *x++ = 4; + memcpy(x, &serveraddr, 4); + x += 4; + + *x++ = OPT_END; + + return DHCP_MSG_FIXED_SIZE + (x - msg->options); +} diff --git a/package/wwan/app/fibocom-dial/src/libmnl/dhcp/dhcpmsg.h b/package/wwan/app/fibocom-dial/src/libmnl/dhcp/dhcpmsg.h new file mode 100755 index 000000000..fb99490ab --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/libmnl/dhcp/dhcpmsg.h @@ -0,0 +1,106 @@ +/* + * Copyright 2008, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _WIFI_DHCP_H_ +#define _WIFI_DHCP_H_ + +#include + +#define PORT_BOOTP_SERVER 67 +#define PORT_BOOTP_CLIENT 68 + +/* RFC 2131 p 9 */ +typedef struct dhcp_msg dhcp_msg; + +#define OP_BOOTREQUEST 1 +#define OP_BOOTREPLY 2 + +#define FLAGS_BROADCAST 0x8000 + +#define HTYPE_ETHER 1 + +struct dhcp_msg +{ + uint8_t op; /* BOOTREQUEST / BOOTREPLY */ + uint8_t htype; /* hw addr type */ + uint8_t hlen; /* hw addr len */ + uint8_t hops; /* client set to 0 */ + + uint32_t xid; /* transaction id */ + + uint16_t secs; /* seconds since start of acq */ + uint16_t flags; + + uint32_t ciaddr; /* client IP addr */ + uint32_t yiaddr; /* your (client) IP addr */ + uint32_t siaddr; /* ip addr of next server */ + /* (DHCPOFFER and DHCPACK) */ + uint32_t giaddr; /* relay agent IP addr */ + + uint8_t chaddr[16]; /* client hw addr */ + char sname[64]; /* asciiz server hostname */ + char file[128]; /* asciiz boot file name */ + + uint8_t options[1024]; /* optional parameters */ +}; + +#define DHCP_MSG_FIXED_SIZE 236 + +/* first four bytes of options are a cookie to indicate that +** the payload are DHCP options as opposed to some other BOOTP +** extension. +*/ +#define OPT_COOKIE1 0x63 +#define OPT_COOKIE2 0x82 +#define OPT_COOKIE3 0x53 +#define OPT_COOKIE4 0x63 + +/* BOOTP/DHCP options - see RFC 2132 */ +#define OPT_PAD 0 + +#define OPT_SUBNET_MASK 1 /* 4 */ +#define OPT_TIME_OFFSET 2 /* 4 */ +#define OPT_GATEWAY 3 /* 4*n * n */ +#define OPT_DNS 6 /* 4*n * n */ +#define OPT_DOMAIN_NAME 15 /* n */ +#define OPT_BROADCAST_ADDR 28 /* 4 */ + +#define OPT_REQUESTED_IP 50 /* 4 */ +#define OPT_LEASE_TIME 51 /* 4 */ +#define OPT_MESSAGE_TYPE 53 /* 1 */ +#define OPT_SERVER_ID 54 /* 4 */ +#define OPT_PARAMETER_LIST 55 /* n * n */ +#define OPT_MESSAGE 56 /* n */ +#define OPT_CLASS_ID 60 /* n */ +#define OPT_CLIENT_ID 61 /* n */ +#define OPT_END 255 + +/* DHCP message types */ +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 +#define DHCPINFORM 8 + +int init_dhcp_discover_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid); + +int init_dhcp_request_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid, + uint32_t ipaddr, uint32_t serveraddr); + +#endif diff --git a/package/wwan/app/fibocom-dial/src/libmnl/dhcp/packet.c b/package/wwan/app/fibocom-dial/src/libmnl/dhcp/packet.c new file mode 100755 index 000000000..9515dd1eb --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/libmnl/dhcp/packet.c @@ -0,0 +1,247 @@ +/* + * Copyright 2008, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dhcpmsg.h" + +int fatal(); + +int open_raw_socket(const char *ifname __attribute__((unused)), uint8_t *hwaddr, int if_index) +{ + int s; + struct sockaddr_ll bindaddr; + + if((s = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) { + return fatal("socket(PF_PACKET)"); + } + + memset(&bindaddr, 0, sizeof(bindaddr)); + bindaddr.sll_family = AF_PACKET; + bindaddr.sll_protocol = htons(ETH_P_IP); + bindaddr.sll_halen = ETH_ALEN; + memcpy(bindaddr.sll_addr, hwaddr, ETH_ALEN); + bindaddr.sll_ifindex = if_index; + + if (bind(s, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) { + return fatal("Cannot bind raw socket to interface"); + } + + return s; +} + +static uint32_t checksum(void *buffer, unsigned int count, uint32_t startsum) +{ + uint16_t *up = (uint16_t *)buffer; + uint32_t sum = startsum; + uint32_t upper16; + + while (count > 1) { + sum += *up++; + count -= 2; + } + if (count > 0) { + sum += (uint16_t) *(uint8_t *)up; + } + while ((upper16 = (sum >> 16)) != 0) { + sum = (sum & 0xffff) + upper16; + } + return sum; +} + +static uint32_t finish_sum(uint32_t sum) +{ + return ~sum & 0xffff; +} + +int send_packet(int s, int if_index, struct dhcp_msg *msg, int size, + uint32_t saddr, uint32_t daddr, uint32_t sport, uint32_t dport) +{ + struct iphdr ip; + struct udphdr udp; + struct iovec iov[3]; + uint32_t udpsum; + uint16_t temp; + struct msghdr msghdr; + struct sockaddr_ll destaddr; + + ip.version = IPVERSION; + ip.ihl = sizeof(ip) >> 2; + ip.tos = 0; + ip.tot_len = htons(sizeof(ip) + sizeof(udp) + size); + ip.id = 0; + ip.frag_off = 0; + ip.ttl = IPDEFTTL; + ip.protocol = IPPROTO_UDP; + ip.check = 0; + ip.saddr = saddr; + ip.daddr = daddr; + ip.check = finish_sum(checksum(&ip, sizeof(ip), 0)); + + udp.source = htons(sport); + udp.dest = htons(dport); + udp.len = htons(sizeof(udp) + size); + udp.check = 0; + + /* Calculate checksum for pseudo header */ + udpsum = checksum(&ip.saddr, sizeof(ip.saddr), 0); + udpsum = checksum(&ip.daddr, sizeof(ip.daddr), udpsum); + temp = htons(IPPROTO_UDP); + udpsum = checksum(&temp, sizeof(temp), udpsum); + temp = udp.len; + udpsum = checksum(&temp, sizeof(temp), udpsum); + + /* Add in the checksum for the udp header */ + udpsum = checksum(&udp, sizeof(udp), udpsum); + + /* Add in the checksum for the data */ + udpsum = checksum(msg, size, udpsum); + udp.check = finish_sum(udpsum); + + iov[0].iov_base = (char *)&ip; + iov[0].iov_len = sizeof(ip); + iov[1].iov_base = (char *)&udp; + iov[1].iov_len = sizeof(udp); + iov[2].iov_base = (char *)msg; + iov[2].iov_len = size; + memset(&destaddr, 0, sizeof(destaddr)); + destaddr.sll_family = AF_PACKET; + destaddr.sll_protocol = htons(ETH_P_IP); + destaddr.sll_ifindex = if_index; + destaddr.sll_halen = ETH_ALEN; + memcpy(destaddr.sll_addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN); + + msghdr.msg_name = &destaddr; + msghdr.msg_namelen = sizeof(destaddr); + msghdr.msg_iov = iov; + msghdr.msg_iovlen = sizeof(iov) / sizeof(struct iovec); + msghdr.msg_flags = 0; + msghdr.msg_control = 0; + msghdr.msg_controllen = 0; + return sendmsg(s, &msghdr, 0); +} + +int receive_packet(int s, struct dhcp_msg *msg) +{ + int nread; + int is_valid; + struct dhcp_packet { + struct iphdr ip; + struct udphdr udp; + struct dhcp_msg dhcp; + } packet; + int dhcp_size; + uint32_t sum; + uint16_t temp; + uint32_t saddr, daddr; + + nread = read(s, &packet, sizeof(packet)); + if (nread < 0) { + return -1; + } + /* + * The raw packet interface gives us all packets received by the + * network interface. We need to filter out all packets that are + * not meant for us. + */ + is_valid = 0; + if (nread < (int)(sizeof(struct iphdr) + sizeof(struct udphdr))) { +#if VERBOSE + ALOGD("Packet is too small (%d) to be a UDP datagram", nread); +#endif + } else if (packet.ip.version != IPVERSION || packet.ip.ihl != (sizeof(packet.ip) >> 2)) { +#if VERBOSE + ALOGD("Not a valid IP packet"); +#endif + } else if (nread < ntohs(packet.ip.tot_len)) { +#if VERBOSE + ALOGD("Packet was truncated (read %d, needed %d)", nread, ntohs(packet.ip.tot_len)); +#endif + } else if (packet.ip.protocol != IPPROTO_UDP) { +#if VERBOSE + ALOGD("IP protocol (%d) is not UDP", packet.ip.protocol); +#endif + } else if (packet.udp.dest != htons(PORT_BOOTP_CLIENT)) { +#if VERBOSE + ALOGD("UDP dest port (%d) is not DHCP client", ntohs(packet.udp.dest)); +#endif + } else { + is_valid = 1; + } + + if (!is_valid) { + return -1; + } + + /* Seems like it's probably a valid DHCP packet */ + /* validate IP header checksum */ + sum = finish_sum(checksum(&packet.ip, sizeof(packet.ip), 0)); + if (sum != 0) { + printf("IP header checksum failure (0x%x)\n", packet.ip.check); + return -1; + } + /* + * Validate the UDP checksum. + * Since we don't need the IP header anymore, we "borrow" it + * to construct the pseudo header used in the checksum calculation. + */ + dhcp_size = ntohs(packet.udp.len) - sizeof(packet.udp); + /* + * check validity of dhcp_size. + * 1) cannot be negative or zero. + * 2) src buffer contains enough bytes to copy + * 3) cannot exceed destination buffer + */ + if ((dhcp_size <= 0) || + ((int)(nread - sizeof(struct iphdr) - sizeof(struct udphdr)) < dhcp_size) || + ((int)sizeof(struct dhcp_msg) < dhcp_size)) { +#if VERBOSE + printf("Malformed Packet\n"); +#endif + return -1; + } + saddr = packet.ip.saddr; + daddr = packet.ip.daddr; + nread = ntohs(packet.ip.tot_len); + memset(&packet.ip, 0, sizeof(packet.ip)); + packet.ip.saddr = saddr; + packet.ip.daddr = daddr; + packet.ip.protocol = IPPROTO_UDP; + packet.ip.tot_len = packet.udp.len; + temp = packet.udp.check; + packet.udp.check = 0; + sum = finish_sum(checksum(&packet, nread, 0)); + packet.udp.check = temp; + if (!sum) + sum = finish_sum(sum); + if (temp != sum) { + printf("UDP header checksum failure (0x%x should be 0x%x)\n", sum, temp); + return -1; + } + memcpy(msg, &packet.dhcp, dhcp_size); + return dhcp_size; +} diff --git a/package/wwan/app/fibocom-dial/src/libmnl/dhcp/packet.h b/package/wwan/app/fibocom-dial/src/libmnl/dhcp/packet.h new file mode 100755 index 000000000..aade392df --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/libmnl/dhcp/packet.h @@ -0,0 +1,25 @@ +/* + * Copyright 2008, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _WIFI_PACKET_H_ +#define _WIFI_PACKET_H_ + +int open_raw_socket(const char *ifname, uint8_t *hwaddr, int if_index); +int send_packet(int s, int if_index, struct dhcp_msg *msg, int size, + uint32_t saddr, uint32_t daddr, uint32_t sport, uint32_t dport); +int receive_packet(int s, struct dhcp_msg *msg); + +#endif diff --git a/package/wwan/app/fibocom-dial/src/libmnl/ifutils.c b/package/wwan/app/fibocom-dial/src/libmnl/ifutils.c new file mode 100755 index 000000000..51ac9d85f --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/libmnl/ifutils.c @@ -0,0 +1,748 @@ +/* This example is placed in the public domain. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +//#include + +#include "libmnl.h" +#include "ifutils.h" + +#define ERRMSG(v...) printf("%s-%d: error=%s %s\n", __func__, __LINE__, strerror(errno), ##v) +extern void dbg_time(const char *fmt, ...); +int mask_to_prefix_v4(uint32_t mask) +{ + int ret = 0; + while (mask) + { + mask = mask & (mask - 1); + ret++; + } + return ret; +} + +const char *ipaddr_to_string_v4(in_addr_t ipaddr) +{ + static char buf[INET6_ADDRSTRLEN] = {'\0'}; + buf[0] = '\0'; + uint32_t addr = ipaddr; + return inet_ntop(AF_INET, &addr, buf, sizeof(buf)); +} + +const char *ipaddr_to_string_v6(uint8_t *ipaddr) +{ + static char buf[INET6_ADDRSTRLEN] = {'\0'}; + buf[0] = '\0'; + return inet_ntop(AF_INET6, ipaddr, buf, sizeof(buf)); +} + +static void ifc_init_ifr(const char *name, struct ifreq *ifr) +{ + memset(ifr, 0, sizeof(struct ifreq)); + strncpy(ifr->ifr_name, name, IFNAMSIZ); + ifr->ifr_name[IFNAMSIZ - 1] = 0; +} + +int if_get_hwaddr(const char *name, void *ptr) +{ + int r; + struct ifreq ifr; + ifc_init_ifr(name, &ifr); + + int ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if (ifc_ctl_sock < 0) + { + return -1; + } + r = ioctl(ifc_ctl_sock, SIOCGIFHWADDR, &ifr); + if (r < 0) + return -1; + + memcpy(ptr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN); + return 0; +} + +static int if_act_on_link(const char *ifname, int state) +{ + struct mnl_socket *nl; + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + struct ifinfomsg *ifm; + int ret; + unsigned int seq, portid, change = 0, flags = 0; + static int oldstate = -1; + + if (state == oldstate) + return 0; + oldstate = state; + + if (state) + { + change |= IFF_UP; + flags |= IFF_UP; + } + else + { + change |= IFF_UP; + flags &= ~IFF_UP; + } + + nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = RTM_NEWLINK; + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + nlh->nlmsg_seq = seq = time(NULL); + ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifm)); + ifm->ifi_family = AF_UNSPEC; + ifm->ifi_change = change; + ifm->ifi_flags = flags; + + mnl_attr_put_str(nlh, IFLA_IFNAME, ifname); + + nl = mnl_socket_open(NETLINK_ROUTE); + if (nl == NULL) + { + ERRMSG("mnl_socket_open"); + return -1; + } + + if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) + { + ERRMSG(" mnl_socket_bind"); + return -1; + } + portid = mnl_socket_get_portid(nl); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) + { + ERRMSG(" mnl_socket_sendto"); + return -1; + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + if (ret == -1) + { + ERRMSG(" mnl_socket_recvfrom"); + return -1; + } + + ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); + if (ret == -1) + { + ERRMSG(" mnl_cb_run"); + return -1; + } + + mnl_socket_close(nl); + + return 0; +} + +int if_link_up(const char *ifname) +{ + dbg_time("if_link_up %s",ifname); + return if_act_on_link(ifname, 1); +} + +int if_link_down(const char *ifname) +{ + + dbg_time("if_link_down %s",ifname); + return if_act_on_link(ifname, 0); +} + +int if_set_mtu(const char *ifname, uint32_t mtu) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + unsigned int seq, portid; + struct mnl_socket *nl; + struct nlmsghdr *nlh; + struct ifinfomsg *ifm; + int ret; + int iface; + static uint32_t oldmtu = 1500; + + if (mtu == oldmtu) + return 0; + oldmtu = mtu; + + iface = if_nametoindex(ifname); + if (iface == 0) + { + ERRMSG(" if_nametoindex"); + return -1; + } + + nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = RTM_NEWLINK; + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + nlh->nlmsg_seq = seq = time(NULL); + ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(struct ifinfomsg)); + ifm->ifi_family = AF_UNSPEC; + ifm->ifi_index = iface; + ifm->ifi_change = 0xFFFFFFFF; + ifm->ifi_type = 0; + ifm->ifi_flags = IFF_NOARP | IFF_MULTICAST; + + mnl_attr_put_u32(nlh, IFLA_MTU, mtu); + + nl = mnl_socket_open(NETLINK_ROUTE); + if (nl == NULL) + { + ERRMSG(" mnl_socket_open"); + return -1; + } + + if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) + { + ERRMSG(" mnl_socket_bind"); + return -1; + } + portid = mnl_socket_get_portid(nl); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) + { + ERRMSG(" mnl_socket_sendto"); + return -1; + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + if (ret == -1) + { + ERRMSG(" mnl_socket_recvfrom"); + return -1; + } + + ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); + if (ret == -1) + { + ERRMSG(" mnl_cb_run"); + return -1; + } + + mnl_socket_close(nl); + + return 0; +} + +/** + * @brief Set the ip addr object + * + * @param operate + * 0 -> add address on interface + * 1 -> delete address on interface + * @param ifname + * @param ipaddr + * @param prefix + * @return int + */ +static int if_act_on_addr(bool operate, int proto, const char *ifname, addr_t *ipaddr, uint32_t prefix) +{ + struct mnl_socket *nl; + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + struct ifaddrmsg *ifm; + uint32_t seq, portid; + int ret, family = proto; + + int iface; + + iface = if_nametoindex(ifname); + if (iface == 0) + { + ERRMSG(" if_nametoindex"); + return -1; + } + + nlh = mnl_nlmsg_put_header(buf); + if (operate) + nlh->nlmsg_type = RTM_NEWADDR; + else + nlh->nlmsg_type = RTM_DELADDR; + + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE | NLM_F_ACK; + nlh->nlmsg_seq = seq = time(NULL); + + ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(struct ifaddrmsg)); + + ifm->ifa_family = family; + ifm->ifa_prefixlen = prefix; + ifm->ifa_flags = IFA_F_PERMANENT; + + ifm->ifa_scope = RT_SCOPE_UNIVERSE; + ifm->ifa_index = iface; + + /* + * The exact meaning of IFA_LOCAL and IFA_ADDRESS depend + * on the address family being used and the device type. + * For broadcast devices (like the interfaces we use), + * for IPv4 we specify both and they are used interchangeably. + * For IPv6, only IFA_ADDRESS needs to be set. + */ + if (family == AF_INET) + { + mnl_attr_put_u32(nlh, IFA_LOCAL, ipaddr->ip); + mnl_attr_put_u32(nlh, IFA_ADDRESS, ipaddr->ip); + } + else + { + mnl_attr_put(nlh, IFA_ADDRESS, sizeof(struct in6_addr), ipaddr); + } + + nl = mnl_socket_open(NETLINK_ROUTE); + if (nl == NULL) + { + ERRMSG(" mnl_socket_open"); + return -1; + } + + if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) + { + ERRMSG(" mnl_socket_bind"); + return -1; + } + portid = mnl_socket_get_portid(nl); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) + { + ERRMSG(" mnl_socket_sendto"); + return -1; + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + if (ret < 0) + { + ERRMSG(" mnl_socket_recvfrom"); + return -1; + } + + ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); + if (ret < 0) + { + ERRMSG(" mnl_cb_run"); + return -1; + } + + mnl_socket_close(nl); + + return 0; +} + +int if_set_addr_v4(const char *ifname, in_addr_t ipaddr, uint32_t prefix) +{ + addr_t addr; + addr.ip = ipaddr; + return if_act_on_addr(1, AF_INET, ifname, &addr, prefix); +} + +int if_del_addr_v4(const char *ifname, in_addr_t ipaddr, uint32_t prefix) +{ + addr_t addr; + addr.ip = ipaddr; + return if_act_on_addr(0, AF_INET, ifname, &addr, prefix); +} + +int if_set_addr_v6(const char *ifname, uint8_t *ipaddr, uint32_t prefix) +{ + addr_t addr; + memcpy(&addr.ip6, ipaddr, 16); + return if_act_on_addr(1, AF_INET6, ifname, &addr, prefix); +} + +int if_del_addr_v6(const char *ifname, uint8_t *ipaddr, uint32_t prefix) +{ + addr_t addr; + memcpy(&addr.ip6, ipaddr, 16); + return if_act_on_addr(0, AF_INET6, ifname, &addr, prefix); +} + +static int data_attr_cb(const struct nlattr *attr, void *data) +{ + const struct nlattr **tb = data; + int type = mnl_attr_get_type(attr); + + /* skip unsupported attribute in user-space */ + if (mnl_attr_type_valid(attr, IFA_MAX) < 0) + return MNL_CB_OK; + + switch (type) + { + case IFA_ADDRESS: + if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0) + { + ERRMSG(" mnl_attr_validate"); + return MNL_CB_ERROR; + } + break; + } + tb[type] = attr; + return MNL_CB_OK; +} + +static int data_cb(const struct nlmsghdr *nlh, void *data) +{ + struct nlattr *tb[IFA_MAX + 1] = {}; + struct ifaddrmsg *ifa = mnl_nlmsg_get_payload(nlh); + struct addrinfo_t *addrinfo = (struct addrinfo_t *)data; + void *addr = NULL; + + mnl_attr_parse(nlh, sizeof(*ifa), data_attr_cb, tb); + if (tb[IFA_ADDRESS]) + { + char out[INET6_ADDRSTRLEN]; + + addr = mnl_attr_get_payload(tb[IFLA_ADDRESS]); + addr = mnl_attr_get_payload(tb[IFA_ADDRESS]); + if (!inet_ntop(ifa->ifa_family, addr, out, sizeof(out))) + ERRMSG("inet_ntop"); + // printf("%d %d-> %d %s\n", addrinfo->iface, ifa->ifa_index, ifa->ifa_scope, out); + + addrinfo->addrs[addrinfo->num].prefix = ifa->ifa_prefixlen; + if (ifa->ifa_index == addrinfo->iface) + { + if (ifa->ifa_family == AF_INET6) + memcpy(addrinfo->addrs[addrinfo->num].address.ip6.s6_addr, addr, 16); + if (ifa->ifa_family == AF_INET) + memcpy(&(addrinfo->addrs[addrinfo->num].address.ip), addr, 4); + addrinfo->num++; + } + } + + // ifa->ifa_scope + // 0: global + // 200: site + // 253: link + // 254: host + // 255: nowhere + + return MNL_CB_OK; +} + +/** + * @brief + * + * @param ifname + * @param proto + * AF_INET -> for IPv4 + * AF_INET6 -> for IPv6 + * @return int + */ +static int if_get_addr(const char *ifname, int proto, struct addrinfo_t *addrinfo) +{ + char buf[MNL_SOCKET_BUFFER_SIZE]; + unsigned int seq, portid; + struct mnl_socket *nl; + struct nlmsghdr *nlh; + struct rtgenmsg *rt; + int ret; + + addrinfo->iface = if_nametoindex(ifname); + if (addrinfo->iface == 0) + { + ERRMSG(" if_nametoindex"); + return -1; + } + + nlh = mnl_nlmsg_put_header(buf); + nlh->nlmsg_type = RTM_GETADDR; + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + nlh->nlmsg_seq = seq = time(NULL); + rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg)); + if (proto == AF_INET) + rt->rtgen_family = AF_INET; + else if (proto == AF_INET6) + rt->rtgen_family = AF_INET6; + + nl = mnl_socket_open(NETLINK_ROUTE); + if (nl == NULL) + { + ERRMSG(" mnl_socket_open"); + return -1; + } + + if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) + { + ERRMSG(" mnl_socket_bind"); + return -1; + } + portid = mnl_socket_get_portid(nl); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) + { + ERRMSG(" mnl_socket_sendto"); + return -1; + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + while (ret > 0) + { + ret = mnl_cb_run(buf, ret, seq, portid, data_cb, addrinfo); + if (ret <= MNL_CB_STOP) + break; + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + } + if (ret == -1) + { + ERRMSG(" error"); + return -1; + } + mnl_socket_close(nl); + + return 0; +} + +int if_flush_v4_addr(const char *ifname) +{ + struct addrinfo_t addrinfo; + int i = 0; + + memset(&addrinfo, 0, sizeof(struct addrinfo_t)); + if_get_addr(ifname, AF_INET, &addrinfo); + for (; i < addrinfo.num; i++) + { + // printf("remove address: %s\n", ipaddr_to_string_v4(addrinfo.addrs[i].address.ip)); + if_del_addr_v4(ifname, addrinfo.addrs[i].address.ip, addrinfo.addrs[i].prefix); + } + return 0; +} + +int if_flush_v6_addr(const char *ifname) +{ + struct addrinfo_t addrinfo; + int i = 0; + + memset(&addrinfo, 0, sizeof(struct addrinfo_t)); + if_get_addr(ifname, AF_INET6, &addrinfo); + for (; i < addrinfo.num; i++) + { + // printf("remove address: %s\n", ipaddr_to_string_v6(addrinfo.addrs[i].address.ip6.s6_addr)); + if_del_addr_v6(ifname, addrinfo.addrs[i].address.ip6.s6_addr, addrinfo.addrs[i].prefix); + } + return 0; +} + +/** + * @brief Set the route addr object + * Usage: + * iface destination cidr [gateway] + * Example: + * eth0 10.0.1.12 32 10.0.1.11 + * eth0 ffff::10.0.1.12 128 fdff::1 + * @param operate + * add or del + * @param ifname + * @param dstaddr + * @param prefix + * @param gwaddr + * @return int + */ +int if_act_on_route(bool operate, int proto, const char *ifname, addr_t *dstaddr, uint32_t prefix, addr_t *gwaddr) +{ + struct mnl_socket *nl; + char buf[MNL_SOCKET_BUFFER_SIZE]; + struct nlmsghdr *nlh; + struct rtmsg *rtm; + uint32_t seq, portid; + int iface, ret, family = proto; + + iface = if_nametoindex(ifname); + if (iface == 0) + { + ERRMSG(" if_nametoindex"); + return -1; + } + + nlh = mnl_nlmsg_put_header(buf); + if (operate) + nlh->nlmsg_type = RTM_NEWROUTE; + else + nlh->nlmsg_type = RTM_DELROUTE; + + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK; + nlh->nlmsg_seq = seq = time(NULL); + + rtm = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtmsg)); + rtm->rtm_family = family; + rtm->rtm_dst_len = prefix; + rtm->rtm_src_len = 0; + rtm->rtm_tos = 0; + rtm->rtm_protocol = RTPROT_STATIC; + rtm->rtm_table = RT_TABLE_MAIN; + rtm->rtm_type = RTN_UNICAST; + /* is there any gateway? */ + rtm->rtm_scope = gwaddr ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK; + rtm->rtm_flags = 0; + + if (family == AF_INET) + mnl_attr_put_u32(nlh, RTA_DST, dstaddr->ip); + else + mnl_attr_put(nlh, RTA_DST, sizeof(struct in6_addr), dstaddr); + + mnl_attr_put_u32(nlh, RTA_OIF, iface); + if (gwaddr) + { + if (family == AF_INET) + mnl_attr_put_u32(nlh, RTA_GATEWAY, gwaddr->ip); + else + { + mnl_attr_put(nlh, RTA_GATEWAY, sizeof(struct in6_addr), gwaddr); + } + } + + nl = mnl_socket_open(NETLINK_ROUTE); + if (nl == NULL) + { + ERRMSG(" mnl_socket_open"); + return -1; + } + + if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) + { + ERRMSG(" mnl_socket_bind"); + return -1; + } + portid = mnl_socket_get_portid(nl); + + if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) + { + ERRMSG(" mnl_socket_sendto"); + return -1; + } + + ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); + if (ret < 0) + { + ERRMSG(" mnl_socket_recvfrom"); + return -1; + } + + ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); + if (ret < 0) + { + ERRMSG(" mnl_cb_run"); + return -1; + } + + mnl_socket_close(nl); + + return 0; +} + +int if_set_default_route_v4(const char *ifname) +{ + return if_act_on_route(1, AF_INET, ifname, (addr_t *)&in6addr_any, 0, NULL); +} + +int if_del_default_route_v4(const char *ifname) +{ + return if_act_on_route(0, AF_INET, ifname, (addr_t *)&in6addr_any, 0, NULL); +} + +int if_set_default_route_v6(const char *ifname) +{ + return if_act_on_route(1, AF_INET6, ifname, (addr_t *)&in6addr_any, 0, NULL); +} + +int if_del_default_route_v6(const char *ifname) +{ + return if_act_on_route(0, AF_INET6, ifname, (addr_t *)&in6addr_any, 0, NULL); +} + +/** + * @brief Set the default gwaddr object + * set default gw + * @param operate + * @param ifname + * @param gwaddr + * gateway ip + * @return int + */ +int if_set_route_gw_v4(const char *ifname, in_addr_t gwaddr) +{ + addr_t addr; + memset(&addr, 0, sizeof(addr_t)); + addr.ip = gwaddr; + return if_act_on_route(1, AF_INET, ifname, (addr_t *)&in6addr_any, 0, &addr); +} + +int if_del_route_gw_v4(const char *ifname, in_addr_t gwaddr) +{ + addr_t addr; + memset(&addr, 0, sizeof(addr_t)); + addr.ip = gwaddr; + return if_act_on_route(0, AF_INET, ifname, (addr_t *)&in6addr_any, 0, &addr); +} + +int if_set_route_gw_v6(const char *ifname, uint8_t *gwaddr) +{ + addr_t addr; + memset(&addr, 0, sizeof(addr_t)); + memcpy(&addr.ip6, gwaddr, 16); + return if_act_on_route(1, AF_INET6, ifname, (addr_t *)&in6addr_any, 0, &addr); +} + +int if_del_route_gw_v6(const char *ifname, uint8_t *gwaddr) +{ + addr_t addr; + memset(&addr, 0, sizeof(addr_t)); + memcpy(&addr.ip6, gwaddr, 16); + return if_act_on_route(0, AF_INET6, ifname, (addr_t *)&in6addr_any, 0, &addr); +} + +int if_set_dns(const char *dns1, const char *dns2) +{ + int ret = 0; + char buf[128] = {'\0'}; + int fd = open("/etc/resolv.conf", O_CREAT | O_WRONLY | O_TRUNC); + if (fd < 0) + { + ERRMSG(" fail to open /etc/resolv.conf"); + return -1; + } + + if (dns1) + snprintf(buf, sizeof(buf), "nameserver %s\n", dns1); + if (dns2) + snprintf(buf, sizeof(buf), "nameserver %s\n", dns2); + ret = write(fd, buf, strlen(buf)); + if (ret < 0) + { + ERRMSG(" write dns"); + } + close(fd); + return ret > 0 ? 0 : -1; +} + +int if_set_network_v4(const char *ifname, in_addr_t ipaddr, uint32_t prefix, + in_addr_t gwaddr, in_addr_t dns1, in_addr_t dns2) +{ + if_link_up(ifname); + sleep(2); + if_set_addr_v4(ifname, ipaddr, prefix); + if_set_default_route_v4(ifname); + if_set_dns(ipaddr_to_string_v4(dns1), ipaddr_to_string_v4(dns2)); + return 0; +} + +int if_set_network_v6(const char *ifname, uint8_t *ipaddr, uint32_t prefix, + uint8_t *gwaddr, uint8_t *dns1, uint8_t *dns2) +{ + if_link_up(ifname); + sleep(2); + if_set_addr_v6(ifname, ipaddr, prefix); + if_set_default_route_v6(ifname); + if_set_dns(ipaddr_to_string_v6(dns1), ipaddr_to_string_v6(dns2)); + return 0; +} diff --git a/package/wwan/app/fibocom-dial/src/libmnl/ifutils.h b/package/wwan/app/fibocom-dial/src/libmnl/ifutils.h new file mode 100755 index 000000000..4c2b5650d --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/libmnl/ifutils.h @@ -0,0 +1,53 @@ +#ifndef __IFUTILS_H__ +#define __IFUTILS_H__ + +typedef union { + in_addr_t ip; + struct in6_addr ip6; +} addr_t; + +#define MAX_IP_NUM 32 +struct addrinfo_t +{ + int iface; + int num; + struct + { + int prefix; + addr_t address; + } addrs[MAX_IP_NUM]; +}; + +const char *ipaddr_to_string_v4(in_addr_t ipaddr); +const char *ipaddr_to_string_v6(uint8_t *ipaddr); +int mask_to_prefix_v4(in_addr_t mask); + +int if_get_hwaddr(const char *name, void *ptr); + +int if_link_down(const char *ifname); +int if_link_up(const char *ifname); +int if_set_mtu(const char *ifname, uint32_t mtu); + +int if_set_addr_v4(const char *name, in_addr_t address, uint32_t prefixlen); +int if_del_addr_v4(const char *name, in_addr_t address, uint32_t prefixlen); +int if_set_addr_v6(const char *name, uint8_t *address, uint32_t prefixlen); +int if_del_addr_v6(const char *name, uint8_t *address, uint32_t prefixlen); +int if_flush_v4_addr(const char *ifname); +int if_flush_v6_addr(const char *ifname); + +int if_set_route_gw_v4(const char *ifname, in_addr_t gwaddr); +int if_del_route_gw_v4(const char *ifname, in_addr_t gwaddr); +int if_set_default_route_v4(const char *ifname); +int if_del_default_route_v4(const char *ifname); + +int if_set_route_gw_v6(const char *ifname, uint8_t *gwaddr); +int if_del_route_gw_v6(const char *ifname, uint8_t *gwaddr); +int if_set_default_route_v6(const char *ifname); +int if_del_default_route_v6(const char *ifname); + +int if_set_network_v4(const char *ifname, in_addr_t ipaddr, uint32_t prefix, + in_addr_t gwaddr, in_addr_t dns1, in_addr_t dns2); +int if_set_network_v6(const char *ifname, uint8_t *ipaddr, uint32_t prefix, + uint8_t *gwaddr, uint8_t *dns1, uint8_t *dns2); + +#endif //__IFUTILS_H__ \ No newline at end of file diff --git a/package/wwan/app/fibocom-dial/src/libmnl/libmnl.h b/package/wwan/app/fibocom-dial/src/libmnl/libmnl.h new file mode 100755 index 000000000..4bd0b92e8 --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/libmnl/libmnl.h @@ -0,0 +1,202 @@ +#ifndef _LIBMNL_H_ +#define _LIBMNL_H_ + +#include +#include +#include +#include +#include /* for sa_family_t */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Netlink socket API + */ + +#define MNL_SOCKET_AUTOPID 0 +#define MNL_SOCKET_BUFFER_SIZE (sysconf(_SC_PAGESIZE) < 8192L ? sysconf(_SC_PAGESIZE) : 8192L) +#define MNL_SOCKET_DUMP_SIZE 32768 + +struct mnl_socket; + +extern struct mnl_socket *mnl_socket_open(int bus); +extern struct mnl_socket *mnl_socket_open2(int bus, int flags); +extern struct mnl_socket *mnl_socket_fdopen(int fd); +extern int mnl_socket_bind(struct mnl_socket *nl, unsigned int groups, pid_t pid); +extern int mnl_socket_close(struct mnl_socket *nl); +extern int mnl_socket_get_fd(const struct mnl_socket *nl); +extern unsigned int mnl_socket_get_portid(const struct mnl_socket *nl); +extern ssize_t mnl_socket_sendto(const struct mnl_socket *nl, const void *req, size_t siz); +extern ssize_t mnl_socket_recvfrom(const struct mnl_socket *nl, void *buf, size_t siz); +extern int mnl_socket_setsockopt(const struct mnl_socket *nl, int type, void *buf, socklen_t len); +extern int mnl_socket_getsockopt(const struct mnl_socket *nl, int type, void *buf, socklen_t *len); + +/* + * Netlink message API + */ + +#define MNL_ALIGNTO 4 +#define MNL_ALIGN(len) (((len)+MNL_ALIGNTO-1) & ~(MNL_ALIGNTO-1)) +#define MNL_NLMSG_HDRLEN MNL_ALIGN(sizeof(struct nlmsghdr)) + +extern size_t mnl_nlmsg_size(size_t len); +extern size_t mnl_nlmsg_get_payload_len(const struct nlmsghdr *nlh); + +/* Netlink message header builder */ +extern struct nlmsghdr *mnl_nlmsg_put_header(void *buf); +extern void *mnl_nlmsg_put_extra_header(struct nlmsghdr *nlh, size_t size); + +/* Netlink message iterators */ +extern bool mnl_nlmsg_ok(const struct nlmsghdr *nlh, int len); +extern struct nlmsghdr *mnl_nlmsg_next(const struct nlmsghdr *nlh, int *len); + +/* Netlink sequence tracking */ +extern bool mnl_nlmsg_seq_ok(const struct nlmsghdr *nlh, unsigned int seq); + +/* Netlink portID checking */ +extern bool mnl_nlmsg_portid_ok(const struct nlmsghdr *nlh, unsigned int portid); + +/* Netlink message getters */ +extern void *mnl_nlmsg_get_payload(const struct nlmsghdr *nlh); +extern void *mnl_nlmsg_get_payload_offset(const struct nlmsghdr *nlh, size_t offset); +extern void *mnl_nlmsg_get_payload_tail(const struct nlmsghdr *nlh); + +/* Netlink message printer */ +extern void mnl_nlmsg_fprintf(FILE *fd, const void *data, size_t datalen, size_t extra_header_size); + +/* Message batch helpers */ +struct mnl_nlmsg_batch; +extern struct mnl_nlmsg_batch *mnl_nlmsg_batch_start(void *buf, size_t bufsiz); +extern bool mnl_nlmsg_batch_next(struct mnl_nlmsg_batch *b); +extern void mnl_nlmsg_batch_stop(struct mnl_nlmsg_batch *b); +extern size_t mnl_nlmsg_batch_size(struct mnl_nlmsg_batch *b); +extern void mnl_nlmsg_batch_reset(struct mnl_nlmsg_batch *b); +extern void *mnl_nlmsg_batch_head(struct mnl_nlmsg_batch *b); +extern void *mnl_nlmsg_batch_current(struct mnl_nlmsg_batch *b); +extern bool mnl_nlmsg_batch_is_empty(struct mnl_nlmsg_batch *b); + +/* + * Netlink attributes API + */ +#define MNL_ATTR_HDRLEN MNL_ALIGN(sizeof(struct nlattr)) + +/* TLV attribute getters */ +extern uint16_t mnl_attr_get_type(const struct nlattr *attr); +extern uint16_t mnl_attr_get_len(const struct nlattr *attr); +extern uint16_t mnl_attr_get_payload_len(const struct nlattr *attr); +extern void *mnl_attr_get_payload(const struct nlattr *attr); +extern uint8_t mnl_attr_get_u8(const struct nlattr *attr); +extern uint16_t mnl_attr_get_u16(const struct nlattr *attr); +extern uint32_t mnl_attr_get_u32(const struct nlattr *attr); +extern uint64_t mnl_attr_get_u64(const struct nlattr *attr); +extern const char *mnl_attr_get_str(const struct nlattr *attr); + +/* TLV attribute putters */ +extern void mnl_attr_put(struct nlmsghdr *nlh, uint16_t type, size_t len, const void *data); +extern void mnl_attr_put_u8(struct nlmsghdr *nlh, uint16_t type, uint8_t data); +extern void mnl_attr_put_u16(struct nlmsghdr *nlh, uint16_t type, uint16_t data); +extern void mnl_attr_put_u32(struct nlmsghdr *nlh, uint16_t type, uint32_t data); +extern void mnl_attr_put_u64(struct nlmsghdr *nlh, uint16_t type, uint64_t data); +extern void mnl_attr_put_str(struct nlmsghdr *nlh, uint16_t type, const char *data); +extern void mnl_attr_put_strz(struct nlmsghdr *nlh, uint16_t type, const char *data); + +/* TLV attribute putters with buffer boundary checkings */ +extern bool mnl_attr_put_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, size_t len, const void *data); +extern bool mnl_attr_put_u8_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, uint8_t data); +extern bool mnl_attr_put_u16_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, uint16_t data); +extern bool mnl_attr_put_u32_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, uint32_t data); +extern bool mnl_attr_put_u64_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, uint64_t data); +extern bool mnl_attr_put_str_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, const char *data); +extern bool mnl_attr_put_strz_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, const char *data); + +/* TLV attribute nesting */ +extern struct nlattr *mnl_attr_nest_start(struct nlmsghdr *nlh, uint16_t type); +extern struct nlattr *mnl_attr_nest_start_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type); +extern void mnl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *start); +extern void mnl_attr_nest_cancel(struct nlmsghdr *nlh, struct nlattr *start); + +/* TLV validation */ +extern int mnl_attr_type_valid(const struct nlattr *attr, uint16_t maxtype); + +enum mnl_attr_data_type { + MNL_TYPE_UNSPEC, + MNL_TYPE_U8, + MNL_TYPE_U16, + MNL_TYPE_U32, + MNL_TYPE_U64, + MNL_TYPE_STRING, + MNL_TYPE_FLAG, + MNL_TYPE_MSECS, + MNL_TYPE_NESTED, + MNL_TYPE_NESTED_COMPAT, + MNL_TYPE_NUL_STRING, + MNL_TYPE_BINARY, + MNL_TYPE_MAX, +}; + +extern int mnl_attr_validate(const struct nlattr *attr, enum mnl_attr_data_type type); +extern int mnl_attr_validate2(const struct nlattr *attr, enum mnl_attr_data_type type, size_t len); + +/* TLV iterators */ +extern bool mnl_attr_ok(const struct nlattr *attr, int len); +extern struct nlattr *mnl_attr_next(const struct nlattr *attr); + +#define mnl_attr_for_each(attr, nlh, offset) \ + for ((attr) = mnl_nlmsg_get_payload_offset((nlh), (offset)); \ + mnl_attr_ok((attr), (char *)mnl_nlmsg_get_payload_tail(nlh) - (char *)(attr)); \ + (attr) = mnl_attr_next(attr)) + +#define mnl_attr_for_each_nested(attr, nest) \ + for ((attr) = mnl_attr_get_payload(nest); \ + mnl_attr_ok((attr), (char *)mnl_attr_get_payload(nest) + mnl_attr_get_payload_len(nest) - (char *)(attr)); \ + (attr) = mnl_attr_next(attr)) + +#define mnl_attr_for_each_payload(payload, payload_size) \ + for ((attr) = (payload); \ + mnl_attr_ok((attr), (char *)(payload) + payload_size - (char *)(attr)); \ + (attr) = mnl_attr_next(attr)) + +/* TLV callback-based attribute parsers */ +typedef int (*mnl_attr_cb_t)(const struct nlattr *attr, void *data); + +extern int mnl_attr_parse(const struct nlmsghdr *nlh, unsigned int offset, mnl_attr_cb_t cb, void *data); +extern int mnl_attr_parse_nested(const struct nlattr *attr, mnl_attr_cb_t cb, void *data); +extern int mnl_attr_parse_payload(const void *payload, size_t payload_len, mnl_attr_cb_t cb, void *data); + +/* + * callback API + */ +#define MNL_CB_ERROR -1 +#define MNL_CB_STOP 0 +#define MNL_CB_OK 1 + +typedef int (*mnl_cb_t)(const struct nlmsghdr *nlh, void *data); + +extern int mnl_cb_run(const void *buf, size_t numbytes, unsigned int seq, + unsigned int portid, mnl_cb_t cb_data, void *data); + +extern int mnl_cb_run2(const void *buf, size_t numbytes, unsigned int seq, + unsigned int portid, mnl_cb_t cb_data, void *data, + const mnl_cb_t *cb_ctl_array, + unsigned int cb_ctl_array_len); + +/* + * other declarations + */ + +#ifndef SOL_NETLINK +#define SOL_NETLINK 270 +#endif + +#ifndef MNL_ARRAY_SIZE +#define MNL_ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/package/wwan/app/fibocom-dial/src/libmnl/nlmsg.c b/package/wwan/app/fibocom-dial/src/libmnl/nlmsg.c new file mode 100755 index 000000000..d960cf338 --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/libmnl/nlmsg.c @@ -0,0 +1,556 @@ +/* + * (C) 2008-2010 by Pablo Neira Ayuso + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include + +#include "libmnl.h" + +/** + * \defgroup nlmsg Netlink message helpers + * + * Netlink message: + * \verbatim + |<----------------- 4 bytes ------------------->| + |<----- 2 bytes ------>|<------- 2 bytes ------>| + |-----------------------------------------------| + | Message length (including header) | + |-----------------------------------------------| + | Message type | Message flags | + |-----------------------------------------------| + | Message sequence number | + |-----------------------------------------------| + | Netlink PortID | + |-----------------------------------------------| + | | + . Payload . + |_______________________________________________| +\endverbatim + * + * There is usually an extra header after the the Netlink header (at the + * beginning of the payload). This extra header is specific of the Netlink + * subsystem. After this extra header, it comes the sequence of attributes + * that are expressed in Type-Length-Value (TLV) format. + * + * @{ + */ + +/** + * mnl_nlmsg_size - calculate the size of Netlink message (without alignment) + * \param len length of the Netlink payload + * + * This function returns the size of a netlink message (header plus payload) + * without alignment. + */ +size_t mnl_nlmsg_size(size_t len) +{ + return len + MNL_NLMSG_HDRLEN; +} + +/** + * mnl_nlmsg_get_payload_len - get the length of the Netlink payload + * \param nlh pointer to the header of the Netlink message + * + * This function returns the Length of the netlink payload, ie. the length + * of the full message minus the size of the Netlink header. + */ +size_t mnl_nlmsg_get_payload_len(const struct nlmsghdr *nlh) +{ + return nlh->nlmsg_len - MNL_NLMSG_HDRLEN; +} + +/** + * mnl_nlmsg_put_header - reserve and prepare room for Netlink header + * \param buf memory already allocated to store the Netlink header + * + * This function sets to zero the room that is required to put the Netlink + * header in the memory buffer passed as parameter. This function also + * initializes the nlmsg_len field to the size of the Netlink header. This + * function returns a pointer to the Netlink header structure. + */ +struct nlmsghdr *mnl_nlmsg_put_header(void *buf) +{ + int len = MNL_ALIGN(sizeof(struct nlmsghdr)); + struct nlmsghdr *nlh = buf; + + memset(buf, 0, len); + nlh->nlmsg_len = len; + return nlh; +} + +/** + * mnl_nlmsg_put_extra_header - reserve and prepare room for an extra header + * \param nlh pointer to Netlink header + * \param size size of the extra header that we want to put + * + * This function sets to zero the room that is required to put the extra + * header after the initial Netlink header. This function also increases + * the nlmsg_len field. You have to invoke mnl_nlmsg_put_header() before + * you call this function. This function returns a pointer to the extra + * header. + */ +void *mnl_nlmsg_put_extra_header(struct nlmsghdr *nlh, + size_t size) +{ + char *ptr = (char *)nlh + nlh->nlmsg_len; + size_t len = MNL_ALIGN(size); + nlh->nlmsg_len += len; + memset(ptr, 0, len); + return ptr; +} + +/** + * mnl_nlmsg_get_payload - get a pointer to the payload of the netlink message + * \param nlh pointer to a netlink header + * + * This function returns a pointer to the payload of the netlink message. + */ +void *mnl_nlmsg_get_payload(const struct nlmsghdr *nlh) +{ + return (void *)nlh + MNL_NLMSG_HDRLEN; +} + +/** + * mnl_nlmsg_get_payload_offset - get a pointer to the payload of the message + * \param nlh pointer to a netlink header + * \param offset offset to the payload of the attributes TLV set + * + * This function returns a pointer to the payload of the netlink message plus + * a given offset. + */ +void *mnl_nlmsg_get_payload_offset(const struct nlmsghdr *nlh, + size_t offset) +{ + return (void *)nlh + MNL_NLMSG_HDRLEN + MNL_ALIGN(offset); +} + +/** + * mnl_nlmsg_ok - check a there is room for netlink message + * \param nlh netlink message that we want to check + * \param len remaining bytes in a buffer that contains the netlink message + * + * This function is used to check that a buffer that contains a netlink + * message has enough room for the netlink message that it stores, ie. this + * function can be used to verify that a netlink message is not malformed nor + * truncated. + * + * This function does not set errno in case of error since it is intended + * for iterations. Thus, it returns true on success and false on error. + * + * The len parameter may become negative in malformed messages during message + * iteration, that is why we use a signed integer. + */ +bool mnl_nlmsg_ok(const struct nlmsghdr *nlh, int len) +{ + return len >= (int)sizeof(struct nlmsghdr) && + nlh->nlmsg_len >= sizeof(struct nlmsghdr) && + (int)nlh->nlmsg_len <= len; +} + +/** + * mnl_nlmsg_next - get the next netlink message in a multipart message + * \param nlh current netlink message that we are handling + * \param len length of the remaining bytes in the buffer (passed by reference). + * + * This function returns a pointer to the next netlink message that is part + * of a multi-part netlink message. Netlink can batch several messages into + * one buffer so that the receiver has to iterate over the whole set of + * Netlink messages. + * + * You have to use mnl_nlmsg_ok() to check if the next Netlink message is + * valid. + */ +struct nlmsghdr *mnl_nlmsg_next(const struct nlmsghdr *nlh, + int *len) +{ + *len -= MNL_ALIGN(nlh->nlmsg_len); + return (struct nlmsghdr *)((void *)nlh + MNL_ALIGN(nlh->nlmsg_len)); +} + +/** + * mnl_nlmsg_get_payload_tail - get the ending of the netlink message + * \param nlh pointer to netlink message + * + * This function returns a pointer to the netlink message tail. This is useful + * to build a message since we continue adding attributes at the end of the + * message. + */ +void *mnl_nlmsg_get_payload_tail(const struct nlmsghdr *nlh) +{ + return (void *)nlh + MNL_ALIGN(nlh->nlmsg_len); +} + +/** + * mnl_nlmsg_seq_ok - perform sequence tracking + * \param nlh current netlink message that we are handling + * \param seq last sequence number used to send a message + * + * This functions returns true if the sequence tracking is fulfilled, otherwise + * false is returned. We skip the tracking for netlink messages whose sequence + * number is zero since it is usually reserved for event-based kernel + * notifications. On the other hand, if seq is set but the message sequence + * number is not set (i.e. this is an event message coming from kernel-space), + * then we also skip the tracking. This approach is good if we use the same + * socket to send commands to kernel-space (that we want to track) and to + * listen to events (that we do not track). + */ +bool mnl_nlmsg_seq_ok(const struct nlmsghdr *nlh, + unsigned int seq) +{ + return nlh->nlmsg_seq && seq ? nlh->nlmsg_seq == seq : true; +} + +/** + * mnl_nlmsg_portid_ok - perform portID origin check + * \param nlh current netlink message that we are handling + * \param portid netlink portid that we want to check + * + * This functions returns true if the origin is fulfilled, otherwise + * false is returned. We skip the tracking for netlink message whose portID + * is zero since it is reserved for event-based kernel notifications. On the + * other hand, if portid is set but the message PortID is not (i.e. this + * is an event message coming from kernel-space), then we also skip the + * tracking. This approach is good if we use the same socket to send commands + * to kernel-space (that we want to track) and to listen to events (that we + * do not track). + */ +bool mnl_nlmsg_portid_ok(const struct nlmsghdr *nlh, + unsigned int portid) +{ + return nlh->nlmsg_pid && portid ? nlh->nlmsg_pid == portid : true; +} + +static void mnl_nlmsg_fprintf_header(FILE *fd, const struct nlmsghdr *nlh) +{ + fprintf(fd, "----------------\t------------------\n"); + fprintf(fd, "| %.010u |\t| message length |\n", nlh->nlmsg_len); + fprintf(fd, "| %.05u | %c%c%c%c |\t| type | flags |\n", + nlh->nlmsg_type, + nlh->nlmsg_flags & NLM_F_REQUEST ? 'R' : '-', + nlh->nlmsg_flags & NLM_F_MULTI ? 'M' : '-', + nlh->nlmsg_flags & NLM_F_ACK ? 'A' : '-', + nlh->nlmsg_flags & NLM_F_ECHO ? 'E' : '-'); + fprintf(fd, "| %.010u |\t| sequence number|\n", nlh->nlmsg_seq); + fprintf(fd, "| %.010u |\t| port ID |\n", nlh->nlmsg_pid); + fprintf(fd, "----------------\t------------------\n"); +} + +static void mnl_nlmsg_fprintf_payload(FILE *fd, const struct nlmsghdr *nlh, + size_t extra_header_size) +{ + int rem = 0; + unsigned int i; + + for (i=sizeof(struct nlmsghdr); inlmsg_len; i+=4) { + char *b = (char *) nlh; + struct nlattr *attr = (struct nlattr *) (b+i); + + /* netlink control message. */ + if (nlh->nlmsg_type < NLMSG_MIN_TYPE) { + fprintf(fd, "| %.2x %.2x %.2x %.2x |\t", + 0xff & b[i], 0xff & b[i+1], + 0xff & b[i+2], 0xff & b[i+3]); + fprintf(fd, "| |\n"); + /* special handling for the extra header. */ + } else if (extra_header_size > 0) { + extra_header_size -= 4; + fprintf(fd, "| %.2x %.2x %.2x %.2x |\t", + 0xff & b[i], 0xff & b[i+1], + 0xff & b[i+2], 0xff & b[i+3]); + fprintf(fd, "| extra header |\n"); + /* this seems like an attribute header. */ + } else if (rem == 0 && (attr->nla_type & NLA_TYPE_MASK) != 0) { + fprintf(fd, "|%c[%d;%dm" + "%.5u" + "%c[%dm" + "|" + "%c[%d;%dm" + "%c%c" + "%c[%dm" + "|" + "%c[%d;%dm" + "%.5u" + "%c[%dm|\t", + 27, 1, 31, + attr->nla_len, + 27, 0, + 27, 1, 32, + attr->nla_type & NLA_F_NESTED ? 'N' : '-', + attr->nla_type & + NLA_F_NET_BYTEORDER ? 'B' : '-', + 27, 0, + 27, 1, 34, + attr->nla_type & NLA_TYPE_MASK, + 27, 0); + fprintf(fd, "|len |flags| type|\n"); + + if (!(attr->nla_type & NLA_F_NESTED)) { + rem = NLA_ALIGN(attr->nla_len) - + sizeof(struct nlattr); + } + /* this is the attribute payload. */ + } else if (rem > 0) { + rem -= 4; + fprintf(fd, "| %.2x %.2x %.2x %.2x |\t", + 0xff & b[i], 0xff & b[i+1], + 0xff & b[i+2], 0xff & b[i+3]); + fprintf(fd, "| data |"); + fprintf(fd, "\t %c %c %c %c\n", + isprint(b[i]) ? b[i] : ' ', + isprint(b[i+1]) ? b[i+1] : ' ', + isprint(b[i+2]) ? b[i+2] : ' ', + isprint(b[i+3]) ? b[i+3] : ' '); + } + } + fprintf(fd, "----------------\t------------------\n"); +} + +/** + * mnl_nlmsg_fprintf - print netlink message to file + * \param fd pointer to file type + * \param data pointer to the buffer that contains messages to be printed + * \param datalen length of data stored in the buffer + * \param extra_header_size size of the extra header (if any) + * + * This function prints the netlink header to a file handle. + * It may be useful for debugging purposes. One example of the output + * is the following: + * + *\verbatim +---------------- ------------------ +| 0000000040 | | message length | +| 00016 | R-A- | | type | flags | +| 1289148991 | | sequence number| +| 0000000000 | | port ID | +---------------- ------------------ +| 00 00 00 00 | | extra header | +| 00 00 00 00 | | extra header | +| 01 00 00 00 | | extra header | +| 01 00 00 00 | | extra header | +|00008|--|00003| |len |flags| type| +| 65 74 68 30 | | data | e t h 0 +---------------- ------------------ +\endverbatim + * + * This example above shows the netlink message that is send to kernel-space + * to set up the link interface eth0. The netlink and attribute header data + * are displayed in base 10 whereas the extra header and the attribute payload + * are expressed in base 16. The possible flags in the netlink header are: + * + * - R, that indicates that NLM_F_REQUEST is set. + * - M, that indicates that NLM_F_MULTI is set. + * - A, that indicates that NLM_F_ACK is set. + * - E, that indicates that NLM_F_ECHO is set. + * + * The lack of one flag is displayed with '-'. On the other hand, the possible + * attribute flags available are: + * + * - N, that indicates that NLA_F_NESTED is set. + * - B, that indicates that NLA_F_NET_BYTEORDER is set. + */ +void mnl_nlmsg_fprintf(FILE *fd, const void *data, size_t datalen, + size_t extra_header_size) +{ + const struct nlmsghdr *nlh = data; + int len = datalen; + + while (mnl_nlmsg_ok(nlh, len)) { + mnl_nlmsg_fprintf_header(fd, nlh); + mnl_nlmsg_fprintf_payload(fd, nlh, extra_header_size); + nlh = mnl_nlmsg_next(nlh, &len); + } +} + +/** + * @} + */ + +/** + * \defgroup batch Netlink message batch helpers + * + * This library provides helpers to batch several messages into one single + * datagram. These helpers do not perform strict memory boundary checkings. + * + * The following figure represents a Netlink message batch: + * + * |<-------------- MNL_SOCKET_BUFFER_SIZE ------------->| + * |<-------------------- batch ------------------>| | + * |-----------|-----------|-----------|-----------|-----------| + * |<- nlmsg ->|<- nlmsg ->|<- nlmsg ->|<- nlmsg ->|<- nlmsg ->| + * |-----------|-----------|-----------|-----------|-----------| + * ^ ^ + * | | + * message N message N+1 + * + * To start the batch, you have to call mnl_nlmsg_batch_start() and you can + * use mnl_nlmsg_batch_stop() to release it. + * + * You have to invoke mnl_nlmsg_batch_next() to get room for a new message + * in the batch. If this function returns NULL, it means that the last + * message that was added (message N+1 in the figure above) does not fit the + * batch. Thus, you have to send the batch (which includes until message N) + * and, then, you have to call mnl_nlmsg_batch_reset() to re-initialize + * the batch (this moves message N+1 to the head of the buffer). For that + * reason, the buffer that you have to use to store the batch must be double + * of MNL_SOCKET_BUFFER_SIZE to ensure that the last message (message N+1) + * that did not fit into the batch is written inside valid memory boundaries. + * + * @{ + */ + +struct mnl_nlmsg_batch { + /* the buffer that is used to store the batch. */ + void *buf; + size_t limit; + size_t buflen; + /* the current netlink message in the batch. */ + void *cur; + bool overflow; +}; + +/** + * mnl_nlmsg_batch_start - initialize a batch + * \param buf pointer to the buffer that will store this batch + * \param limit maximum size of the batch (should be MNL_SOCKET_BUFFER_SIZE). + * + * The buffer that you pass must be double of MNL_SOCKET_BUFFER_SIZE. The + * limit must be half of the buffer size, otherwise expect funny memory + * corruptions 8-). + * + * You can allocate the buffer that you use to store the batch in the stack or + * the heap, no restrictions in this regard. This function returns NULL on + * error. + */ +struct mnl_nlmsg_batch *mnl_nlmsg_batch_start(void *buf, + size_t limit) +{ + struct mnl_nlmsg_batch *b; + + b = malloc(sizeof(struct mnl_nlmsg_batch)); + if (b == NULL) + return NULL; + + b->buf = buf; + b->limit = limit; + b->buflen = 0; + b->cur = buf; + b->overflow = false; + + return b; +} + +/** + * mnl_nlmsg_batch_stop - release a batch + * \param b pointer to batch + * + * This function releases the batch allocated by mnl_nlmsg_batch_start(). + */ +void mnl_nlmsg_batch_stop(struct mnl_nlmsg_batch *b) +{ + free(b); +} + +/** + * mnl_nlmsg_batch_next - get room for the next message in the batch + * \param b pointer to batch + * + * This function returns false if the last message did not fit into the + * batch. Otherwise, it prepares the batch to provide room for the new + * Netlink message in the batch and returns true. + * + * You have to put at least one message in the batch before calling this + * function, otherwise your application is likely to crash. + */ +bool mnl_nlmsg_batch_next(struct mnl_nlmsg_batch *b) +{ + struct nlmsghdr *nlh = b->cur; + + if (b->buflen + nlh->nlmsg_len > b->limit) { + b->overflow = true; + return false; + } + b->cur = b->buf + b->buflen + nlh->nlmsg_len; + b->buflen += nlh->nlmsg_len; + return true; +} + +/** + * mnl_nlmsg_batch_reset - reset the batch + * \param b pointer to batch + * + * This function allows to reset a batch, so you can reuse it to create a + * new one. This function moves the last message which does not fit the + * batch to the head of the buffer, if any. + */ +void mnl_nlmsg_batch_reset(struct mnl_nlmsg_batch *b) +{ + if (b->overflow) { + struct nlmsghdr *nlh = b->cur; + memcpy(b->buf, b->cur, nlh->nlmsg_len); + b->buflen = nlh->nlmsg_len; + b->cur = b->buf + b->buflen; + b->overflow = false; + } else { + b->buflen = 0; + b->cur = b->buf; + } +} + +/** + * mnl_nlmsg_batch_size - get current size of the batch + * \param b pointer to batch + * + * This function returns the current size of the batch. + */ +size_t mnl_nlmsg_batch_size(struct mnl_nlmsg_batch *b) +{ + return b->buflen; +} + +/** + * mnl_nlmsg_batch_head - get head of this batch + * \param b pointer to batch + * + * This function returns a pointer to the head of the batch, which is the + * beginning of the buffer that is used. + */ +void *mnl_nlmsg_batch_head(struct mnl_nlmsg_batch *b) +{ + return b->buf; +} + +/** + * mnl_nlmsg_batch_current - returns current position in the batch + * \param b pointer to batch + * + * This function returns a pointer to the current position in the buffer + * that is used to store the batch. + */ +void *mnl_nlmsg_batch_current(struct mnl_nlmsg_batch *b) +{ + return b->cur; +} + +/** + * mnl_nlmsg_batch_is_empty - check if there is any message in the batch + * \param b pointer to batch + * + * This function returns true if the batch is empty. + */ +bool mnl_nlmsg_batch_is_empty(struct mnl_nlmsg_batch *b) +{ + return b->buflen == 0; +} + +/** + * @} + */ diff --git a/package/wwan/app/fibocom-dial/src/libmnl/socket.c b/package/wwan/app/fibocom-dial/src/libmnl/socket.c new file mode 100755 index 000000000..dd5ab664c --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/libmnl/socket.c @@ -0,0 +1,351 @@ +/* + * (C) 2008-2010 by Pablo Neira Ayuso + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include + +#include "libmnl.h" + +/** + * \mainpage + * + * libmnl is a minimalistic user-space library oriented to Netlink developers. + * There are a lot of common tasks in parsing, validating, constructing of + * both the Netlink header and TLVs that are repetitive and easy to get wrong. + * This library aims to provide simple helpers that allows you to avoid + * re-inventing the wheel in common Netlink tasks. + * + * \verbatim +"Simplify, simplify" -- Henry David Thoureau. Walden (1854) +\endverbatim + * + * The acronym libmnl stands for LIBrary Minimalistic NetLink. + * + * libmnl homepage is: + * http://www.netfilter.org/projects/libmnl/ + * + * \section features Main Features + * - Small: the shared library requires around 30KB for an x86-based computer. + * - Simple: this library avoids complex abstractions that tend to hide Netlink + * details. It avoids elaborated object-oriented infrastructure and complex + * callback-based workflow. + * - Easy to use: the library simplifies the work for Netlink-wise developers. + * It provides functions to make socket handling, message building, + * validating, parsing and sequence tracking, easier. + * - Easy to re-use: you can use this library to build your own abstraction + * layer upon this library, if you want to provide another library that + * hides Netlink details to your users. + * - Decoupling: the interdependency of the main bricks that compose this + * library is reduced, i.e. the library provides many helpers, but the + * programmer is not forced to use them. + * + * \section licensing Licensing terms + * This library is released under the LGPLv2.1 or any later (at your option). + * + * \section Dependencies + * You have to install the Linux kernel headers that you want to use to develop + * your application. Moreover, this library requires that you have some basics + * on Netlink. + * + * \section scm Git Tree + * The current development version of libmnl can be accessed at: + * http://git.netfilter.org/cgi-bin/gitweb.cgi?p=libmnl.git;a=summary + * + * \section using Using libmnl + * You can access several example files under examples/ in the libmnl source + * code tree. + */ + +struct mnl_socket { + int fd; + struct sockaddr_nl addr; +}; + +/** + * \defgroup socket Netlink socket helpers + * @{ + */ + +/** + * mnl_socket_get_fd - obtain file descriptor from netlink socket + * \param nl netlink socket obtained via mnl_socket_open() + * + * This function returns the file descriptor of a given netlink socket. + */ +int mnl_socket_get_fd(const struct mnl_socket *nl) +{ + return nl->fd; +} + +/** + * mnl_socket_get_portid - obtain Netlink PortID from netlink socket + * \param nl netlink socket obtained via mnl_socket_open() + * + * This function returns the Netlink PortID of a given netlink socket. + * It's a common mistake to assume that this PortID equals the process ID + * which is not always true. This is the case if you open more than one + * socket that is binded to the same Netlink subsystem from the same process. + */ +unsigned int mnl_socket_get_portid(const struct mnl_socket *nl) +{ + return nl->addr.nl_pid; +} + +static struct mnl_socket *__mnl_socket_open(int bus, int flags) +{ + struct mnl_socket *nl; + + nl = calloc(1, sizeof(struct mnl_socket)); + if (nl == NULL) + return NULL; + + nl->fd = socket(AF_NETLINK, SOCK_RAW | flags, bus); + if (nl->fd == -1) { + free(nl); + return NULL; + } + + return nl; +} + +/** + * mnl_socket_open - open a netlink socket + * \param bus the netlink socket bus ID (see NETLINK_* constants) + * + * On error, it returns NULL and errno is appropriately set. Otherwise, it + * returns a valid pointer to the mnl_socket structure. + */ +struct mnl_socket *mnl_socket_open(int bus) +{ + return __mnl_socket_open(bus, 0); +} + +/** + * mnl_socket_open2 - open a netlink socket with appropriate flags + * \param bus the netlink socket bus ID (see NETLINK_* constants) + * \param flags the netlink socket flags (see SOCK_* constants in socket(2)) + * + * This is similar to mnl_socket_open(), but allows to set flags like + * SOCK_CLOEXEC at socket creation time (useful for multi-threaded programs + * performing exec calls). + * + * On error, it returns NULL and errno is appropriately set. Otherwise, it + * returns a valid pointer to the mnl_socket structure. + */ +struct mnl_socket *mnl_socket_open2(int bus, int flags) +{ + return __mnl_socket_open(bus, flags); +} + +/** + * mnl_socket_fdopen - associates a mnl_socket object with pre-existing socket. + * \param fd pre-existing socket descriptor. + * + * On error, it returns NULL and errno is appropriately set. Otherwise, it + * returns a valid pointer to the mnl_socket structure. It also sets the portID + * if the socket fd is already bound and it is AF_NETLINK. + * + * Note that mnl_socket_get_portid() returns 0 if this function is used with + * non-netlink socket. + */ +struct mnl_socket *mnl_socket_fdopen(int fd) +{ + int ret; + struct mnl_socket *nl; + struct sockaddr_nl addr; + socklen_t addr_len = sizeof(struct sockaddr_nl); + + ret = getsockname(fd, (struct sockaddr *) &addr, &addr_len); + if (ret == -1) + return NULL; + + nl = calloc(1, sizeof(struct mnl_socket)); + if (nl == NULL) + return NULL; + + nl->fd = fd; + if (addr.nl_family == AF_NETLINK) + nl->addr = addr; + + return nl; +} + +/** + * mnl_socket_bind - bind netlink socket + * \param nl netlink socket obtained via mnl_socket_open() + * \param groups the group of message you're interested in + * \param pid the port ID you want to use (use zero for automatic selection) + * + * On error, this function returns -1 and errno is appropriately set. On + * success, 0 is returned. You can use MNL_SOCKET_AUTOPID which is 0 for + * automatic port ID selection. + */ +int mnl_socket_bind(struct mnl_socket *nl, unsigned int groups, + pid_t pid) +{ + int ret; + socklen_t addr_len; + + nl->addr.nl_family = AF_NETLINK; + nl->addr.nl_groups = groups; + nl->addr.nl_pid = pid; + + ret = bind(nl->fd, (struct sockaddr *) &nl->addr, sizeof (nl->addr)); + if (ret < 0) + return ret; + + addr_len = sizeof(nl->addr); + ret = getsockname(nl->fd, (struct sockaddr *) &nl->addr, &addr_len); + if (ret < 0) + return ret; + + if (addr_len != sizeof(nl->addr)) { + errno = EINVAL; + return -1; + } + if (nl->addr.nl_family != AF_NETLINK) { + errno = EINVAL; + return -1; + } + return 0; +} + +/** + * mnl_socket_sendto - send a netlink message of a certain size + * \param nl netlink socket obtained via mnl_socket_open() + * \param buf buffer containing the netlink message to be sent + * \param len number of bytes in the buffer that you want to send + * + * On error, it returns -1 and errno is appropriately set. Otherwise, it + * returns the number of bytes sent. + */ +ssize_t mnl_socket_sendto(const struct mnl_socket *nl, + const void *buf, size_t len) +{ + static const struct sockaddr_nl snl = { + .nl_family = AF_NETLINK + }; + return sendto(nl->fd, buf, len, 0, + (struct sockaddr *) &snl, sizeof(snl)); +} + +/** + * mnl_socket_recvfrom - receive a netlink message + * \param nl netlink socket obtained via mnl_socket_open() + * \param buf buffer that you want to use to store the netlink message + * \param bufsiz size of the buffer passed to store the netlink message + * + * On error, it returns -1 and errno is appropriately set. If errno is set + * to ENOSPC, it means that the buffer that you have passed to store the + * netlink message is too small, so you have received a truncated message. + * To avoid this, you have to allocate a buffer of MNL_SOCKET_BUFFER_SIZE + * (which is 8KB, see linux/netlink.h for more information). Using this + * buffer size ensures that your buffer is big enough to store the netlink + * message without truncating it. + */ +ssize_t mnl_socket_recvfrom(const struct mnl_socket *nl, + void *buf, size_t bufsiz) +{ + ssize_t ret; + struct sockaddr_nl addr; + struct iovec iov = { + .iov_base = buf, + .iov_len = bufsiz, + }; + struct msghdr msg = { + .msg_name = &addr, + .msg_namelen = sizeof(struct sockaddr_nl), + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = NULL, + .msg_controllen = 0, + .msg_flags = 0, + }; + ret = recvmsg(nl->fd, &msg, 0); + if (ret == -1) + return ret; + + if (msg.msg_flags & MSG_TRUNC) { + errno = ENOSPC; + return -1; + } + if (msg.msg_namelen != sizeof(struct sockaddr_nl)) { + errno = EINVAL; + return -1; + } + return ret; +} + +/** + * mnl_socket_close - close a given netlink socket + * \param nl netlink socket obtained via mnl_socket_open() + * + * On error, this function returns -1 and errno is appropriately set. + * On success, it returns 0. + */ +int mnl_socket_close(struct mnl_socket *nl) +{ + int ret = close(nl->fd); + free(nl); + return ret; +} + +/** + * mnl_socket_setsockopt - set Netlink socket option + * \param nl netlink socket obtained via mnl_socket_open() + * \param type type of Netlink socket options + * \param buf the buffer that contains the data about this option + * \param len the size of the buffer passed + * + * This function allows you to set some Netlink socket option. As of writing + * this (see linux/netlink.h), the existing options are: + * + * - \#define NETLINK_ADD_MEMBERSHIP 1 + * - \#define NETLINK_DROP_MEMBERSHIP 2 + * - \#define NETLINK_PKTINFO 3 + * - \#define NETLINK_BROADCAST_ERROR 4 + * - \#define NETLINK_NO_ENOBUFS 5 + * + * In the early days, Netlink only supported 32 groups expressed in a + * 32-bits mask. However, since 2.6.14, Netlink may have up to 2^32 multicast + * groups but you have to use setsockopt() with NETLINK_ADD_MEMBERSHIP to + * join a given multicast group. This function internally calls setsockopt() + * to join a given netlink multicast group. You can still use mnl_bind() + * and the 32-bit mask to join a set of Netlink multicast groups. + * + * On error, this function returns -1 and errno is appropriately set. + */ +int mnl_socket_setsockopt(const struct mnl_socket *nl, int type, + void *buf, socklen_t len) +{ + return setsockopt(nl->fd, SOL_NETLINK, type, buf, len); +} + +/** + * mnl_socket_getsockopt - get a Netlink socket option + * \param nl netlink socket obtained via mnl_socket_open() + * \param type type of Netlink socket options + * \param buf pointer to the buffer to store the value of this option + * \param len size of the information written in the buffer + * + * On error, this function returns -1 and errno is appropriately set. + */ +int mnl_socket_getsockopt(const struct mnl_socket *nl, int type, + void *buf, socklen_t *len) +{ + return getsockopt(nl->fd, SOL_NETLINK, type, buf, len); +} + +/** + * @} + */ diff --git a/package/wwan/app/fibocom-dial/src/main.c b/package/wwan/app/fibocom-dial/src/main.c new file mode 100755 index 000000000..dd6429350 --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/main.c @@ -0,0 +1,1770 @@ +#include +#include +#include +#include + +//2021-02-25 willa.liu@fibocom.com changed begin for support eipd SN-20210129001 +#include +#include +//2021-02-25 willa.liu@fibocom.com changed end for support eipd SN-20210129001 + +//2020-12-23 willa.liu@fibocom.com changed begin for support mantis 0065286 +#include +#include +//2020-12-23 willa.liu@fibocom.com changed end for support mantis 0065286 + +#include "QMIThread.h" +#include "util.h" +//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817 +#include "query_pcie_mode.h" +//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817 + +#define MAJOR 2 +#define MINOR 0 +#define REVISION 10 +/* + * Generally, we do not modify version info, so several modifications will share + * the same version code. SUBVERSION is used for customized modification to + * distinguise this version from previous one. SUBVERSION adds up before you + * send the code to customers and it should be set to 0 if VERSION_STRING info + * is changed. + */ +#define SUBVERSION 0 +#define STRINGIFY_HELPER(v) #v +#define STRINGIFY(v) STRINGIFY_HELPER(v) +#define VERSION_STRING() \ + STRINGIFY(MAJOR) "." STRINGIFY(MINOR) "." STRINGIFY(REVISION) +#define MAX_PATH 256 + +//2020-12-23 willa.liu@fibocom.com changed begin for support mantis 0065286 +struct sockaddr_un { + sa_family_t sun_family; + char sun_path[100]; +}; +//2020-12-23 willa.liu@fibocom.com changed end for support mantis 0065286 + +int query_pcie_mode = 0; +int debug_qmi = 0; +int main_loop = 0; +int qmidevice_control_fd[2]; +static int signal_control_fd[2]; +pthread_t gQmiThreadID; +USHORT g_MobileCountryCode = 0; +USHORT g_MobileNetworkCode = 0; + +//2020-12-23 willa.liu@fibocom.com changed begin for support mantis 0065286 +sem_t sem; +int socket_server_fd = 0; +int cli_accept_fd = 0; +char fibo_dial_filepath[100] = {0}; +//2020-12-23 willa.liu@fibocom.com changed end for support mantis 0065286 + +extern const struct qmi_device_ops qmiwwan_qmidev_ops; +extern const struct qmi_device_ops gobi_qmidev_ops; + +//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817 +//extern int *speed_arr; +//extern int *name_arr; +//extern int get_private_gateway_debug; +//2021-03-24 willa.liu@fibocom.com changed end for support mantis 0071817 + +static int s_link = -1; + +static int is_pcie_dial() +{ + return (access("/dev/mhi_QMI0", F_OK) == 0); +} + +//2021-02-25 willa.liu@fibocom.com changed begin for support eipd SN-20210129001 +int split_gateway(char *str ,char* split, int index, char *outgateway) +{ + char chBuffer[1024]; + char *pchStrTmpIn = NULL; + char *pchTmp = NULL; + int i = 1; + strncpy(chBuffer, str, sizeof(chBuffer)-1); + pchTmp = chBuffer; + //printf("pchTmp is [%s]\n", pchTmp); + while(NULL != (pchTmp = strtok_r( pchTmp, split, &pchStrTmpIn))) + { + //printf("line %d::::::::::::[%s]\n", i, pchTmp); + if(i == index) + { + memcpy(outgateway, pchTmp, strlen(pchTmp)); + break; + } + //if(strstr(pchTmp, "+CGCONTRDP") != -1) + i++; + pchTmp = NULL; + } + return strlen(outgateway); +} + +int get_private_gateway(char *outgateway) +{ + int i; + int fd; + int ret; + char buffer[1024] = {0}; + int rate; + char *sendbuffer; + char prigateways[1024*2] = {0}; + char prigateway[256] = {0}; + int totallen = 0; + fd_set readfds; + struct timeval timeout; + struct termios tiosfd, tio; + + int timeoutVal = 5; + + char *dev = "/dev/ttyUSB1"; //The port under Linux is operated by opening the device file + rate = 115200; + sendbuffer = "AT+CGCONTRDP=1"; + + fd = open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK); + if(fd < 0) + goto ERR; + fcntl(fd, F_SETFL, O_RDWR); + + xget1(fd, &tio, &tiosfd); + + for(i = 0; i < sizeof(speed_arr)/sizeof(int); i++) + { + if(rate == name_arr[i])//Judge if the pass is equal to the pass + { + break; + } + } + + if(i >= sizeof(speed_arr)/sizeof(int)) + { + printf("bound rate set failed\n"); + goto ERR; + } + + cfsetspeed(&tio, speed_arr[i]); + if(xset1(fd, &tio, dev)) + goto ERR; + + tcflush(fd, TCIOFLUSH); + + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + + sprintf(buffer, "%s\r", sendbuffer); + ret = write (fd, buffer, strlen(buffer)); + if(ret < 0) + { + printf("write failed\n"); + goto ERR; + } + printf("dev: %s\nrate:%d\nsendbuffer:%s\n", dev, rate, sendbuffer); + sleep(1); + if(get_private_gateway_debug)printf("write %d\n", ret); + while(1) + { + timeout.tv_sec = timeoutVal; + timeout.tv_usec = 0; + + ret = select(fd+1, &readfds, (fd_set *)0, (fd_set *)0, &timeout); + if(ret > 0) + { + ret = read(fd, buffer+totallen, sizeof(buffer)-totallen-1); + if(ret < 0) + { + printf("read failed\n"); + goto ERR; + } + + if(ret == 0) + { + goto ERR; + } + + totallen += ret; + buffer[totallen] = '\0'; + if(get_private_gateway_debug)printf("read %d(%s)\n", ret, &buffer[totallen-ret]); + //printf("buffer is %s\n", buffer); + + if(totallen == sizeof(buffer)-1) + break; + + if(strstr(buffer, "\nOK")) + { + split_gateway(buffer, "\r", 3, prigateways); + //printf("test1 %s\n", prigateways); + split_gateway(prigateways, ",", 5, prigateway); + //printf("test2 %s\n", prigateway); + break; + } + else + { + goto ERR; + } + + } + else + { + printf("select timeout\n"); + goto ERR; + } + + } + + tcsetattr(fd, TCSAFLUSH, &tiosfd); + if(strstr(buffer, "\nERROR") || strstr(buffer, "\n+CME ERROR:") || strstr(buffer, "\n+CMS ERROR:")) + goto ERR; + + close(fd); + + memcpy(outgateway, prigateway+1, strlen(prigateway)-2); + printf("private gateway is %s\n", outgateway); + return 0; +ERR: + if(fd > 0) + close(fd); + return -1; +} +//2021-02-25 willa.liu@fibocom.com changed end for support eipd SN-20210129001 + +// UINT ifc_get_addr(const char *ifname); +static void usbnet_link_change(int link, PROFILE_T *profile) +{ + // static int s_link = 0; + dbg_time("%s :link:%d ", __func__, link); + + if (s_link == link) + return; + + s_link = link; + + if (link) { + if (profile->ipv4_flag) + requestGetIPAddress(profile, IpFamilyV4); + if (profile->ipv6_flag) + requestGetIPAddress(profile, IpFamilyV6); + if (qmidev_is_pciemhi(profile->qmichannel)) + udhcpc_start_pcie(profile); + else + udhcpc_start(profile); + } else { + if (qmidev_is_pciemhi(profile->qmichannel)) + udhcpc_stop_pcie(profile); + else + udhcpc_stop(profile); + } +} + +static int check_address(PROFILE_T *now_profile,int ipfamily) +{ + PROFILE_T new_profile_v; + PROFILE_T *new_profile = &new_profile_v; + static int time_out_count = 0; + int ret = 0; + #define QMITHREADSENDQMITIMEOUT 110 + + memcpy(new_profile, now_profile, sizeof(PROFILE_T)); + if(ipfamily == IpFamilyV4) + { + ret = requestGetIPAddress(new_profile, 0x04); + if (ret == 0) + { + time_out_count = 0; + if (new_profile->ipv4.Address != now_profile->ipv4.Address || debug_qmi) + { + unsigned char *l = (unsigned char *)&now_profile->ipv4.Address; + unsigned char *r = (unsigned char *)&new_profile->ipv4.Address; + dbg_time("localIP: %d.%d.%d.%d VS remoteIP: %d.%d.%d.%d", l[3], + l[2], l[1], l[0], r[3], r[2], r[1], r[0]); + } + return (new_profile->ipv4.Address == now_profile->ipv4.Address); + } + else if (ret == QMITHREADSENDQMITIMEOUT) + { + time_out_count++; + dbg_time("%s %d time_out_count %d\n", __func__, __LINE__, time_out_count); + if (time_out_count >= 3) + { + return 0; + } + else + { + return 1; + } + } + } + if(ipfamily == IpFamilyV6) + { + return 1; + } + + return 0; +} + +static void main_send_event_to_qmidevice(int triger_event) +{ + write(qmidevice_control_fd[0], &triger_event, sizeof(triger_event)); +} + +static void send_signo_to_main(int signo) +{ + write(signal_control_fd[0], &signo, sizeof(signo)); + dbg_time("write signo: %d to signal_control_fd",signo); +} + +void qmidevice_send_event_to_main(int triger_event) +{ + write(qmidevice_control_fd[1], &triger_event, sizeof(triger_event)); + dbg_time("write triger_event: %d to qmidevice_control_fd",triger_event); +} + +static int ls_dir(const char *dir, + int (*match)(const char *dir, const char *file, void *argv[]), + void *argv[]) +{ + DIR *pDir; + struct dirent *ent = NULL; + int match_times = 0; + + pDir = opendir(dir); + if (pDir == NULL) { + dbg_time("Cannot open directory: %s, errno: %d (%s)", dir, errno, + strerror(errno)); + return 0; + } + + while ((ent = readdir(pDir)) != NULL) { + match_times += match(dir, ent->d_name, argv); + } + closedir(pDir); + + return match_times; +} + +static int is_same_linkfile(const char *dir, const char *file, void *argv[]) +{ + const char *qmichannel = (const char *)argv[1]; + char linkname[MAX_PATH]; + char filename[MAX_PATH]; + int linksize; + + snprintf(linkname, MAX_PATH, "%s/%s", dir, file); + linksize = readlink(linkname, filename, MAX_PATH); + if (linksize <= 0) + return 0; + + filename[linksize] = 0; + if (strcmp(filename, qmichannel)) + return 0; + + dbg_time("%s -> %s", linkname, filename); + return 1; +} + +static int is_brother_process(const char *dir, const char *file, void *argv[]) +{ + // const char *myself = (const char *)argv[0]; + char linkname[MAX_PATH]; + char filename[MAX_PATH]; + int linksize; + int i = 0, kill_timeout = 15; + pid_t pid; + + // dbg_time("%s", file); + while (file[i]) { + if (!isdigit(file[i])) + break; + i++; + } + + if (file[i]) { + // dbg_time("%s not digit", file); + return 0; + } + + snprintf(linkname, MAX_PATH, "%s/%s/exe", dir, file); + linksize = readlink(linkname, filename, MAX_PATH); + if (linksize <= 0) + return 0; + + filename[linksize] = 0; + + pid = atoi(file); + if (pid >= getpid()) + return 0; + + snprintf(linkname, MAX_PATH, "%s/%s/fd", dir, file); + if (!ls_dir(linkname, is_same_linkfile, argv)) + return 0; + + dbg_time("%s/%s/exe -> %s", dir, file, filename); + while (kill_timeout-- && !kill(pid, 0)) { + kill(pid, SIGTERM); + sleep(1); + } + if (!kill(pid, 0)) { + dbg_time("force kill %s/%s/exe -> %s", dir, file, filename); + kill(pid, SIGKILL); + sleep(1); + } + + return 1; +} + +static int kill_brothers(const char *qmichannel) +{ + char myself[MAX_PATH]; + int filenamesize; + void *argv[2] = {myself, (void *)qmichannel}; + + filenamesize = readlink("/proc/self/exe", myself, MAX_PATH); + if (filenamesize <= 0) + return 0; + myself[filenamesize] = 0; + + if (ls_dir("/proc", is_brother_process, argv)) + sleep(1); + + return 0; +} + +static void fibo_sigaction(int signo) +{ + if (SIGCHLD == signo) + waitpid(-1, NULL, WNOHANG); + else if (SIGALRM == signo) + send_signo_to_main(SIGUSR1); + else { + if (SIGTERM == signo || SIGHUP == signo || SIGINT == signo) + main_loop = 0; + send_signo_to_main(signo); + main_send_event_to_qmidevice(signo); // main may be wating qmi response + } +} + +static int usage(const char *progname) +{ + dbg_time("Usage: %s [options]", progname); + dbg_time( + "-s [apn [user password auth]] Set " + "apn/user/password/auth get from your network provider"); + dbg_time( + "-p pincode Verify sim card pin if " + "sim card is locked"); + dbg_time( + "-f logfilename Save log message of this " + "program to file"); + dbg_time( + "-i interface Specify network " + "interface(default auto-detect)"); + dbg_time("-4 IPv4 protocol"); + dbg_time("-6 IPv6 protocol"); + +//2021-02-25 willa.liu@fibocom.com changed begin for support eipd SN-20210129001 + dbg_time("-g IPv6 private gateway"); +//2021-02-25 willa.liu@fibocom.com changed begin for support eipd SN-20210129001 + +//2020-12-29 willa.liu@fibocom.com changed begin for support mantis 0066901 + //dbg_time( + //"-P profile index Specify profile index " + //"when start network data connection(default 1)."); +//2020-12-29 willa.liu@fibocom.com changed end for support mantis 0066901 + + dbg_time( + "-m muxID Specify muxid when set " + "multi-pdn data connection."); + dbg_time( + "-n channelID Specify channelID when " + "set multi-pdn data connection(default 1)."); + dbg_time( + "-N Number of channel Specify total channels " + "when set multi-pdn data connection(default 1)."); + +//2020-12-23 willa.liu@fibocom.com changed begin for support mantis 0065286 + dbg_time( + "-k number kill specified process "); +//2020-12-23 willa.liu@fibocom.com changed end for support mantis 0065286 + + dbg_time("[Examples]"); + dbg_time("Example 1: %s ", progname); + dbg_time("Example 2: %s -s 3gnet ", progname); + dbg_time("Example 3: %s -s 3gnet carl 1234 0 -p 1234 -f gobinet_log.txt", + progname); + return 0; +} + +static int charsplit(const char *src, char *desc, int n, const char *splitStr) +{ + char *p; + char *p1; + int len; + + len = strlen(splitStr); + p = strstr(src, splitStr); + if (p == NULL) + return -1; + p1 = strstr(p, "\n"); + if (p1 == NULL) + return -1; + memset(desc, 0, n); + memcpy(desc, p + len, p1 - p - len); + + return 0; +} + +static int get_dev_major_minor(char *path, int *major, int *minor) +{ + int fd = -1; + char desc[128] = {0}; + char devmajor[64], devminor[64]; + int n = 0; + if (access(path, R_OK | W_OK)) { + return 1; + } + if ((fd = open(path, O_RDWR)) < 0) { + return 1; + } + n = read(fd, desc, sizeof(desc)); + if (n == sizeof(desc)) { + dbg_time("may be overflow"); + } + close(fd); + if (charsplit(desc, devmajor, 64, "MAJOR=") == -1 || + charsplit(desc, devminor, 64, "MINOR=") == -1) { + return 2; + } + *major = atoi(devmajor); + *minor = atoi(devminor); + return 0; +} +#ifdef GHT_FEATURE_PCIE_AUTO +//begin modified by zhangkaibo add PCIe auto detect feature on x55/x24 platform. 20200605 +static int qmipciedevice_detect(char **pp_qmichannel, char **pp_usbnet_adapter) +{ + struct dirent *ent = NULL; + DIR *pDir; + char dir[255] = "/sys/bus/pci/devices"; + + struct { + char subdir[255 * 2]; + char subdir2[255 * 3 + 16]; + char qmifile[255 * 2]; + } * pl; + pl = (typeof(pl))malloc(sizeof(*pl)); + memset(pl, 0x00, sizeof(*pl)); + + pDir = opendir(dir); + if (pDir) { + while ((ent = readdir(pDir)) != NULL) { + + struct dirent *subent = NULL; + DIR *psubDir; + char idVendor[4 + 1] = {0}; + char idDevice[4 + 1] = {0}; + char tempNetpath[256] = {0}; + int fd = 0; + char netcard[32] = "\0"; + + memset(pl, 0x00, sizeof(*pl)); + snprintf(pl->subdir, sizeof(pl->subdir), "%s/%s/vendor", dir, + ent->d_name); + fd = open(pl->subdir, O_RDONLY); + if (fd > 0) { + read(fd, idVendor, 6); + close(fd); + } + + snprintf(pl->subdir, sizeof(pl->subdir), "%s/%s/device", dir, + ent->d_name); + fd = open(pl->subdir, O_RDONLY); + if (fd > 0) { + read(fd, idDevice, 6); + close(fd); + } + + if (!strncasecmp(idVendor, "0x17cb", 6)) + ; + else + continue; + + dbg_time("Find %s/%s vendor=%s device=%s", dir, ent->d_name, + idVendor,idDevice); + //find pcie netdevicename + snprintf(tempNetpath,256,"%s%s_IP_HW0", idDevice+2 , ent->d_name+2); + snprintf(pl->subdir, sizeof(pl->subdir), "%s/%s/%s/net", dir, + ent->d_name,tempNetpath); + psubDir = opendir(pl->subdir); + if (psubDir == NULL) { + dbg_time("Cannot open directory: %s, errno: %d (%s)", + pl->subdir, errno, strerror(errno)); + continue; + } + + while ((subent = readdir(psubDir)) != NULL) { + if (subent->d_name[0] == '.') + continue; + dbg_time("Find pcienet_adapter = %s", subent->d_name); + strcpy(netcard, subent->d_name); + break; + } + + closedir(psubDir); + + if (netcard[0]) { + } else { + continue; + } + + *pp_usbnet_adapter = strdup(netcard); + break; + } + closedir(pDir); + } + //find pcie qmi control name + if ((pDir = opendir("/dev")) == NULL) { + dbg_time("Cannot open directory: %s, errno:%d (%s)", "/dev", errno, + strerror(errno)); + return -ENODEV; + } + + while ((ent = readdir(pDir)) != NULL) { + if ( strncmp(ent->d_name, "mhi_QMI", strlen("mhi_QMI")) == 0 ) { + *pp_qmichannel = (char *)malloc(32); + sprintf(*pp_qmichannel, "/dev/%s", ent->d_name); + dbg_time("Find qmichannel = %s", *pp_qmichannel); + break; + } + } + closedir(pDir); + free(pl); + + return (*pp_qmichannel && *pp_usbnet_adapter); +} +//end modified by zhangkaibo add PCIe auto detect feature on x55/x24 platform. 20200605 +#endif +static int qmidevice_detect(char **pp_qmichannel, char **pp_usbnet_adapter,PROFILE_T *profile) +{ + struct dirent *ent = NULL; + DIR *pDir; + char dir[255] = "/sys/bus/usb/devices"; + int major = 0, minor = 0; + int indexid = 4; + struct { + char subdir[255 * 3]; + char subdir2[255 * 4 + 16]; + char qmifile[255 * 2]; + } * pl; +#ifdef GHT_FEATURE_PCIE_AUTO +//begin modified by zhangkaibo add PCIe auto detect feature on x55/x24 platform. 20200605 + if (qmipciedevice_detect(pp_qmichannel, pp_usbnet_adapter)) + { + return (*pp_qmichannel && *pp_usbnet_adapter); + } +//end modified by zhangkaibo add PCIe auto detect feature on x55/x24 platform. 20200605 +#endif + pl = (typeof(pl))malloc(sizeof(*pl)); + memset(pl, 0x00, sizeof(*pl)); + + pDir = opendir(dir); + if (pDir) { + while ((ent = readdir(pDir)) != NULL) { + struct dirent *subent = NULL; + DIR *psubDir; + char idVendor[4 + 1] = {0}; + char idProduct[4 + 1] = {0}; + int fd = 0; + char netcard[32] = "\0"; + + memset(pl, 0x00, sizeof(*pl)); + + snprintf(pl->subdir, sizeof(pl->subdir), "%s/%s/idVendor", dir, + ent->d_name); + fd = open(pl->subdir, O_RDONLY); + if (fd > 0) { + read(fd, idVendor, 4); + close(fd); + } + + snprintf(pl->subdir, sizeof(pl->subdir), "%s/%s/idProduct", dir, + ent->d_name); + fd = open(pl->subdir, O_RDONLY); + if (fd > 0) { + read(fd, idProduct, 4); + close(fd); + } + + if (!strncasecmp(idVendor, "05c6", 4) || + !strncasecmp(idVendor, "2cb7", 4)) + ; + else + continue; + + dbg_time("Find %s/%s idVendor=%s idProduct=%s", dir, ent->d_name, + idVendor, idProduct); +//2021-02-08 zhangkaibo@fibocom.com changed start for mantis 0070613 + if(!strncasecmp(idProduct, "0109", 4)) + { + indexid = 2; + profile->interfacenum = 2; + } +//2021-09-09 willa.liu@fibocom.com changed start for mantis 0086219 + else if(!strncasecmp(idProduct, "0113", 4)) + { + indexid = 0; + profile->interfacenum = 0; + } +//2021-09-09 willa.liu@fibocom.com changed end for mantis 0086219 + else + { + profile->interfacenum = 4; + } + snprintf(pl->subdir, sizeof(pl->subdir), "%s/%s:1.%d/net", dir, + ent->d_name,indexid); + psubDir = opendir(pl->subdir); + if (psubDir == NULL) { + dbg_time("Cannot open directory: %s, errno: %d (%s)", + pl->subdir, errno, strerror(errno)); + continue; + } + + while ((subent = readdir(psubDir)) != NULL) { + if (subent->d_name[0] == '.') + continue; + dbg_time("Find %s/%s", pl->subdir, subent->d_name); + dbg_time("Find usbnet_adapter = %s", subent->d_name); + strcpy(netcard, subent->d_name); + break; + } + + closedir(psubDir); + + if (netcard[0]) { + } else { + continue; + } + + if (*pp_usbnet_adapter && strcmp(*pp_usbnet_adapter, netcard)) + continue; + + snprintf(pl->subdir, sizeof(pl->subdir), "%s/%s:1.%d/GobiQMI", dir, + ent->d_name,indexid); + if (access(pl->subdir, R_OK)) { + snprintf(pl->subdir, sizeof(pl->subdir), "%s/%s:1.%d/usbmisc", + dir, ent->d_name,indexid); + if (access(pl->subdir, R_OK)) { + snprintf(pl->subdir, sizeof(pl->subdir), "%s/%s:1.%d/usb", + dir, ent->d_name,indexid); + if (access(pl->subdir, R_OK)) { + dbg_time("no GobiQMI/usbmic/usb found in %s/%s:1.%d", + dir, ent->d_name,indexid); + continue; + } + } + } + +//2021-02-08 zhangkaibo@fibocom.com changed end for mantis 0070613 + + psubDir = opendir(pl->subdir); + if (pDir == NULL) { + dbg_time("Cannot open directory: %s, errno: %d (%s)", dir, + errno, strerror(errno)); + continue; + } + + while ((subent = readdir(psubDir)) != NULL) { + if (subent->d_name[0] == '.') + continue; + dbg_time("Find %s/%s", pl->subdir, subent->d_name); + dbg_time("Find qmichannel = /dev/%s", subent->d_name); + snprintf(pl->qmifile, sizeof(pl->qmifile), "/dev/%s", + subent->d_name); + + // get major minor + snprintf(pl->subdir2, sizeof(pl->subdir2), "%s/%s/uevent", + pl->subdir, subent->d_name); + if (!get_dev_major_minor(pl->subdir2, &major, &minor)) { + // dbg_time("%s major = %d, minor = %d\n",pl->qmifile, + // major, minor); + } else { + dbg_time("get %s major and minor failed\n", pl->qmifile); + } + // get major minor + + if ((fd = open(pl->qmifile, R_OK)) < 0) { + dbg_time("%s open failed", pl->qmifile); + dbg_time("please mknod %s c %d %d", pl->qmifile, major, + minor); + } else { + close(fd); + } + break; + } + + closedir(psubDir); + + if (netcard[0] && pl->qmifile[0]) { + *pp_qmichannel = strdup(pl->qmifile); + *pp_usbnet_adapter = strdup(netcard); + closedir(pDir); + return 1; + } + } + + closedir(pDir); + } + + if ((pDir = opendir("/dev")) == NULL) { + dbg_time("Cannot open directory: %s, errno:%d (%s)", "/dev", errno, + strerror(errno)); + return -ENODEV; + } + + while ((ent = readdir(pDir)) != NULL) { + if ((strncmp(ent->d_name, "cdc-wdm", strlen("cdc-wdm")) == 0) || + (strncmp(ent->d_name, "qcqmi", strlen("qcqmi")) == 0)) { + char net_path[255*2]; + + *pp_qmichannel = (char *)malloc(32); + sprintf(*pp_qmichannel, "/dev/%s", ent->d_name); + dbg_time("Find qmichannel = %s", *pp_qmichannel); + + if (strncmp(ent->d_name, "cdc-wdm", strlen("cdc-wdm")) == 0) + sprintf(net_path, "/sys/class/net/wwan%s", + &ent->d_name[strlen("cdc-wdm")]); + else { + sprintf(net_path, "/sys/class/net/usb%s", + &ent->d_name[strlen("qcqmi")]); + + if (access(net_path, R_OK) && errno == ENOENT) + sprintf(net_path, "/sys/class/net/eth%s", + &ent->d_name[strlen("qcqmi")]); + } + + if (access(net_path, R_OK) == 0) { + if (*pp_usbnet_adapter && + strcmp(*pp_usbnet_adapter, + (net_path + strlen("/sys/class/net/")))) { + free(*pp_qmichannel); + *pp_qmichannel = NULL; + continue; + } + *pp_usbnet_adapter = + strdup(net_path + strlen("/sys/class/net/")); + dbg_time("Find usbnet_adapter = %s", *pp_usbnet_adapter); + break; + } else { + dbg_time("Failed to access %s, errno:%d (%s)", net_path, errno, + strerror(errno)); + free(*pp_qmichannel); + *pp_qmichannel = NULL; + } + } + } + closedir(pDir); + free(pl); + + return (*pp_qmichannel && *pp_usbnet_adapter); +} +//begin modified by zhangkaibo limit input parameters. mantis 0048965 20200605 +int IsInt(char* str) +{ + int len; + len = strlen(str); + int i=0; + for(; i < len ; i++) + { + if(!(isdigit(str[i]))) + return 0; + } + return 1; +} +//end modified by zhangkaibo limit input parameters. mantis 0048965 20200605 + +//2020-12-23 willa.liu@fibocom.com changed begin for support mantis 0065286 +int rdwr_init(int clienfd, char * msg) +{ + char buf[512]; + int rv = 0; + memset(buf, 0, 512); + while(1) + { + if ((rv = read(clienfd, buf, 512)) < 0) + { + dbg_time("Read by socket[%d] error:%s", clienfd, strerror(errno)); + goto STOP; + } + else if (0 == rv) + { + goto STOP; + } + else if (rv > 0) + { + dbg_time("Read %d bytes data from client, there are :[%s]", rv, buf); + } + if ((rv =write(clienfd, msg, strlen(msg))) < 0) + { + dbg_time("write to cilent by socket[%d] error:%s",clienfd, strerror(errno)); + goto STOP; + } + } +STOP: + dbg_time("The socket[%d] will exit!", clienfd); + return 0; +} + +void *thread_socket_server(void *args) +{ + int on = 1; + int rv = 0; + struct sockaddr_un serv_addr; + struct sockaddr_un cli_addr; + socklen_t len = sizeof(serv_addr); + sprintf(fibo_dial_filepath,"/tmp/fibocom_dial_%d",*(int*)args); + char* msg = "receive quit request\n"; + if ((socket_server_fd = socket(AF_UNIX,SOCK_STREAM,0))< 0) + { + dbg_time("Socket error:%s\a\n", strerror(errno)); + return ; + } + dbg_time("socket[%d] successfuly!", socket_server_fd); + if (!access(fibo_dial_filepath, F_OK)) + { + unlink(fibo_dial_filepath); + } + setsockopt(socket_server_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + memset(&serv_addr, 0, sizeof(serv_addr)); + serv_addr.sun_family = AF_UNIX; + strncpy(serv_addr.sun_path, fibo_dial_filepath, sizeof(serv_addr.sun_path) - 1); + if ((rv = bind(socket_server_fd, (struct sockaddr *)&serv_addr, len)) < 0) + { + dbg_time("Bind error %s", strerror(errno)); + goto EXIT; + } + if ((rv = listen(socket_server_fd, 13)) < 0) + { + dbg_time("Listen error:%s", strerror(errno)); + goto EXIT; + } + dbg_time("Waiting client to connect....."); + sem_post(&sem); + while(1) + { + if ((cli_accept_fd = accept(socket_server_fd, (struct sockaddr *)&cli_addr, &len))< 0) + { + dbg_time("accept error:%s", strerror(errno)); + goto EXIT; + } + dbg_time("client to connected"); + rv = rdwr_init(cli_accept_fd, msg); + goto EXIT; + } +EXIT: + unlink(fibo_dial_filepath); + close(socket_server_fd ); + close(cli_accept_fd ); + send_signo_to_main(SIGTERM); + return ((void *)0); + +} + +//2020-12-29 willa.liu@fibocom.com changed begin for support mantis 0066901 +int startSocketserver(int pdpindex) +{ + pthread_t ntid; + //sem_init(&sem, 0, 2); + sem_init(&sem, 0, 0); + if (pthread_create(&ntid, 0, thread_socket_server, + (void *)(&pdpindex)) != 0) { + dbg_time("%s Failed to create QMIThread: %d (%s)", __func__, errno, + strerror(errno)); + } + sem_wait(&sem); + sem_destroy(&sem); + return 0; +} +//2020-12-29 willa.liu@fibocom.com changed begin for support mantis 0066901 + +int startSocketclient(int pdpindex) +{ + int socket_client_fd; + int rv = -1; + struct sockaddr_un servaddr; + char fibo_dial_filepath[100] = {0}; + sprintf(fibo_dial_filepath,"/tmp/fibocom_dial_%d",pdpindex); + dbg_time("enter startSocketclient %s.",fibo_dial_filepath); + char* message = "fibocom-dial quit request"; + char buf[1024]; + + if(access(fibo_dial_filepath, F_OK) != 0) + { + return -1; + } + socket_client_fd = socket(AF_UNIX,SOCK_STREAM,0); + if(socket_client_fd < 0) + { + dbg_time("Cearte socket failure :%s\a",strerror(errno)); + return -1; + } + dbg_time("Create socket [%d] sucessfully.",socket_client_fd); + memset(&servaddr,0,sizeof(servaddr)); + servaddr.sun_family = AF_UNIX; + strncpy(servaddr.sun_path, fibo_dial_filepath, sizeof(servaddr.sun_path) - 1); + rv = connect(socket_client_fd,(struct sockaddr *)&servaddr,sizeof(servaddr)); + if(rv <0) + { + dbg_time("connect to server [%s] failure :%s\a",fibo_dial_filepath,strerror(errno)); + return -2; + } + dbg_time("connect to server [%s] successfully!",fibo_dial_filepath); + rv = write(socket_client_fd,message,strlen(message)); + if(rv <0) + { + dbg_time("Write to server failure by socket[%d] failure: %s",socket_client_fd,strerror(errno)); + return -3; + } + else + { + dbg_time("Write [%s] to server by socket[%d] successfuly!", message, socket_client_fd); + } + memset(buf,0,sizeof(buf)); + rv = read(socket_client_fd,buf,1024); + if(rv < 0) + { + dbg_time("Read to server socket[%d] failure: %s",socket_client_fd,strerror(errno)); + return -4; + } + else if(rv == 0) + { + dbg_time("socket [%d] get disconnected",socket_client_fd); + return -4; + } + else if(rv >0) + { + dbg_time("Read [%d] bytes data from Server: [%s]",rv,buf); + } + close(socket_client_fd); + unlink(fibo_dial_filepath); + + return 0; +} +//2020-12-23 willa.liu@fibocom.com changed begin for support mantis 0065286 + +int main(int argc, char *argv[]) +{ + int triger_event = 0; + int opt = 1; + int signo; +//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817 + int sim_number = 0; +//begin modified by zhangkaibo limit input parameters. mantis 0048965 20200605 + char argvtemp[256] = {0}; +//end modified by zhangkaibo limit input parameters. mantis 0048965 20200605 + +//2020-12-23 willa.liu@fibocom.com changed begin for support mantis 0065286 + int killnumber = -1; +//2020-12-23 willa.liu@fibocom.com changed end for support mantis 0065286 + +#ifdef CONFIG_SIM + SIM_Select SIMNumber; +//2021-03-24 willa.liu@fibocom.com changed end for support mantis 0071817 + SIM_Status SIMStatus; +#endif + UCHAR PSAttachedState; + UCHAR IPv4ConnectionStatus = 0xff; // unknow state + UCHAR IPV6ConnectionStatus = 0xff; // unknow state + int qmierr = 0; + char *save_usbnet_adapter = NULL; + PROFILE_T profile; +#ifdef CONFIG_RESET_RADIO + struct timeval resetRadioTime = {0}; + struct timeval FailDailRadioTime = {0}; + struct timeval nowTime; + gettimeofday(&resetRadioTime, (struct timezone *)NULL); +#endif + + dbg_time("Fibocom-dial_Linux_Tool_V%s", VERSION_STRING()); + memset(&profile, 0x00, sizeof(profile)); + profile.pdp = CONFIG_DEFAULT_PDP; + profile.pdpindex = CONFIG_DEFAULT_PDPINDEX; + profile.pdpnum = 1; + + if (!strcmp(argv[argc - 1], "&")) + argc--; + + opt = 1; + while (opt < argc) { + if (argv[opt][0] != '-') + return usage(argv[0]); + + switch (argv[opt++][1]) { +#define has_more_argv() ((opt < argc) && (argv[opt][0] != '-')) + case 's': + profile.apn = profile.user = profile.password = ""; + if (has_more_argv()) + profile.apn = argv[opt++]; + if (has_more_argv()) + profile.user = argv[opt++]; + if (has_more_argv()) { + profile.password = argv[opt++]; + if (profile.password && profile.password[0]) + profile.auth = 2; // default chap, customers may miss auth + } + if (has_more_argv()) +//begin modified by zhangkaibo limit input parameters. mantis 0048965 20200605 + { + memset(argvtemp,0,256); + strcpy(argvtemp,argv[opt++]); + if(strlen(argvtemp) > 1 || !IsInt(argvtemp)) + { + dbg_time("Invalid parament for \"-s\""); + return -1; + } + profile.auth = argvtemp[0] - '0'; +//begin modified by zhangkaibo limit input parameters. mantis 0077949 20200513 + if(profile.auth < 0 || profile.auth > 3) + { + dbg_time("auth must be 0~3"); +//end modified by zhangkaibo limit input parameters. mantis 0077949 20200513 + return -1; + } + } +//end modified by zhangkaibo limit input parameters. mantis 0048965 20200605 + break; + + case 'm': + if (has_more_argv()) + { + if (is_pcie_dial()) + profile.muxid = argv[opt++][0] - '0'; + else + { + memset(argvtemp,0,256); + strcpy(argvtemp,argv[opt++]); + if(strlen(argvtemp) > 1 || !IsInt(argvtemp)) + { + dbg_time("Invalid parament for \"-P\""); + return -1; + } + profile.pdpindex = argvtemp[0] - '0'; + if(profile.pdpindex < 1 || profile.pdpindex > 10) + { + dbg_time("pdpindex must be 1~10"); + return -1; + } + } + } + break; + + case 'p': + if (has_more_argv()) + profile.pincode = argv[opt++]; + break; +#if 0 + case 'P': + if (has_more_argv()) +//begin modified by zhangkaibo limit input parameters. mantis 0048965 20200605 + { + memset(argvtemp,0,256); + strcpy(argvtemp,argv[opt++]); + if(strlen(argvtemp) > 1 || !IsInt(argvtemp)) + { + dbg_time("Invalid parament for \"-P\""); + return -1; + } + profile.pdpindex = argvtemp[0] - '0'; + if(profile.pdpindex < 1 || profile.pdpindex > 10) + { + dbg_time("pdpindex must be 1~10"); + return -1; + } + } +//end modified by zhangkaibo limit input parameters. mantis 0048965 20200605 + break; +#endif + case 'n': + if (has_more_argv()) +//begin modified by zhangkaibo limit input parameters. mantis 0048965 20200605 + { + memset(argvtemp,0,256); + strcpy(argvtemp,argv[opt++]); + if(strlen(argvtemp) > 1 || !IsInt(argvtemp)) + { + dbg_time("Invalid parament for \"-n\""); + return -1; + } + profile.pdp = argvtemp[0] - '0'; + if(profile.pdp < 1 || profile.pdp > 8) + { + dbg_time("pdpindex must be 1~8"); + return -1; + } + + if (is_pcie_dial()) + profile.pdpindex = profile.pdp; + } + break; +//end modified by zhangkaibo limit input parameters. mantis 0048965 20200605 + case 'N': + if (has_more_argv()) +//begin modified by zhangkaibo limit input parameters. mantis 0048965 20200605 + { + memset(argvtemp,0,256); + strcpy(argvtemp,argv[opt++]); + if(strlen(argvtemp) > 1 || !IsInt(argvtemp)) + { + dbg_time("Invalid parament for \"-N\""); + return -1; + } + profile.pdpnum = argvtemp[0] - '0'; + if(profile.pdpnum < 0 || profile.pdpnum > 8) + { + dbg_time("pdpnum must be 0~8"); + return -1; + } + } +//end modified by zhangkaibo limit input parameters. mantis 0048965 20200605 + break; + + case 'f': + if (has_more_argv()) { + const char *filename = argv[opt++]; + logfilefp = fopen(filename, "a+"); + if (!logfilefp) { + dbg_time("Fail to open %s, errno: %d(%s)", filename, errno, + strerror(errno)); + } + } + break; + + case 'i': + if (has_more_argv()) + profile.usbnet_adapter = save_usbnet_adapter = argv[opt++]; + break; + + case 'v': + debug_qmi = 1; + break; + + case 'l': + if (has_more_argv()) { + profile.replication_factor = atoi(argv[opt++]); + if (profile.replication_factor > 0) + profile.loopback_state = 1; + } + else + main_loop = 1; + + break; + + case '4': + profile.ipv4_flag = 1; + break; + + case '6': + profile.ipv6_flag = 1; + break; + +//2021-02-25 willa.liu@fibocom.com changed begin for support eipd SN-20210129001 + case 'g': + profile.ipv6_prigateway_flag = 1; + break; +//2021-02-25 willa.liu@fibocom.com changed end for support eipd SN-20210129001 + + case 'd': + if (has_more_argv()) { + profile.qmichannel = argv[opt++]; + if (qmidev_is_pciemhi(profile.qmichannel)) + profile.usbnet_adapter = "pcie_mhi0"; + } + break; + + case 'U': + query_pcie_mode = 1; + break; + +//2020-12-23 willa.liu@fibocom.com changed begin for support mantis 0065286 + case 'k': + if (has_more_argv()) + { + memset(argvtemp,0,256); + strcpy(argvtemp,argv[opt++]); + if(strlen(argvtemp) > 1 || !IsInt(argvtemp)) + { + dbg_time("Invalid parament for \"-n\""); + return -1; + } + killnumber = argvtemp[0] - '0'; +//2021-02-01 willa.liu@fibocom.com changed begin for support mantis 0069837 + //if(killnumber < 1 || killnumber > 5) + if(killnumber < 1 || killnumber > 8) + { + dbg_time("pdpindex must be 1~8"); + return -1; + } +//2021-02-01 willa.liu@fibocom.com changed end for support mantis 0069837 + } + break; +//2020-12-23 willa.liu@fibocom.com changed end for support mantis 0065286 + + default: + return usage(argv[0]); + break; + } + } + + if (profile.ipv4_flag != 1 && + profile.ipv6_flag != 1) { // default enable IPv4 + profile.ipv4_flag = 1; + } + + dbg_time("%s profile[%d] = %s/%s/%s/%d, pincode = %s", argv[0], profile.pdp, + profile.apn, profile.user, profile.password, profile.auth, + profile.pincode); + signal(SIGUSR1, fibo_sigaction); + signal(SIGUSR2, fibo_sigaction); + signal(SIGINT, fibo_sigaction); + signal(SIGTERM, fibo_sigaction); + signal(SIGHUP, fibo_sigaction); + signal(SIGCHLD, fibo_sigaction); + signal(SIGALRM, fibo_sigaction); + + //2020-12-23 willa.liu@fibocom.com changed begin for support mantis 0065286 + if(killnumber == -1) + { + startSocketserver(profile.pdp); + } + else{ + startSocketclient(killnumber); + return 0; + } + //2020-12-23 willa.liu@fibocom.com changed end for support mantis 0065286 + + if (socketpair(AF_LOCAL, SOCK_STREAM, 0, signal_control_fd) < 0) { + dbg_time("%s Faild to create main_control_fd: %d (%s)", __func__, errno, + strerror(errno)); + return -1; + } + + if (socketpair(AF_LOCAL, SOCK_STREAM, 0, qmidevice_control_fd) < 0) { + dbg_time("%s Failed to create thread control socket pair: %d (%s)", + __func__, errno, strerror(errno)); + return 0; + } + +// sudo apt-get install udhcpc +// sudo apt-get remove ModemManager +__main_loop: + while (!profile.qmichannel) { +//2021-02-08 zhangkaibo@fibocom.com changed start for mantis 0070613 + if (qmidevice_detect(&profile.qmichannel, &profile.usbnet_adapter,&profile)) +//2021-02-08 zhangkaibo@fibocom.com changed end for mantis 0070613 + { + if (query_pcie_mode) + get_pcie_mode(); + break; + } + if (main_loop) { + int wait_for_device = 3000; + dbg_time("Wait for fibo modules connect"); + while (wait_for_device && main_loop) { + wait_for_device -= 100; + usleep(100 * 1000); + } + continue; + } + dbg_time( + "Cannot find qmichannel(%s) usbnet_adapter(%s) for fibo modules", + profile.qmichannel, profile.usbnet_adapter); + return -ENODEV; + } + + if (access(profile.qmichannel, R_OK | W_OK)) { + dbg_time("Fail to access %s, errno: %d (%s)", profile.qmichannel, errno, + strerror(errno)); + return errno; + } + dbg_time( + "qmichannel(%s) usbnet_adapter(%s) ", + profile.qmichannel, profile.usbnet_adapter); + + if (qmidev_is_gobinet(profile.qmichannel)) { + profile.qmi_ops = &gobi_qmidev_ops; + dbg_time("usb rmnet mode"); + } else { + profile.qmi_ops = &qmiwwan_qmidev_ops; + dbg_time("pcie mode"); + } + qmidev_send = profile.qmi_ops->send; + fibo_qmap_mode_detect(&profile); + if (profile.pdpnum > 1 && profile.pdpnum != profile.qmap_mode && !qmidev_is_pciemhi(profile.qmichannel)) { + if (profile.qmap_mode > 1) { + dbg_time("qmap_mode=%d,profile.pdpnum %d",profile.qmap_mode,profile.pdpnum); + kill_brothers(profile.qmichannel); + } + fibo_qmap_mode_set(&profile); + } + fibo_qmap_mode_detect(&profile); +//begin modified by zhangkaibo limit input parameters. mantis 0048965 20200605 + if(profile.qmap_mode < profile.pdp && profile.qmap_mode > 0 && !qmidev_is_pciemhi(profile.qmichannel)) + { + dbg_time("invalid pdpindex"); + return -1; + } +//end modified by zhangkaibo limit input parameters. mantis 0048965 20200605 + if (profile.qmap_mode == 0 || profile.qmap_mode == 1) + { + dbg_time("qmap_mode=%d",profile.qmap_mode); + kill_brothers(profile.qmichannel); + } + if (pthread_create(&gQmiThreadID, 0, profile.qmi_ops->read, + (void *)&profile) != 0) { + dbg_time("%s Failed to create QMIThread: %d (%s)", __func__, errno, + strerror(errno)); + return 0; + } + + if ((read(qmidevice_control_fd[0], &triger_event, sizeof(triger_event)) != + sizeof(triger_event)) || + (triger_event != RIL_INDICATE_DEVICE_CONNECTED)) { + dbg_time("%s Failed to init QMIThread: %d (%s)", __func__, errno, + strerror(errno)); + return 0; + } + + if (profile.qmi_ops->init && profile.qmi_ops->init(&profile)) { + dbg_time("%s Failed to qmi init: %d (%s)", __func__, errno, + strerror(errno)); + return 0; + } + +#ifdef CONFIG_VERSION + requestBaseBandVersion(NULL); +#endif + requestSetEthMode(&profile); + +#ifdef CONFIG_SIM +//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817 + sim_number = requestGetSIMCardNumber(&profile); + if(sim_number == 1){ + requestSimBindSubscription_NAS_WMS(); + requestSimBindSubscription_WDS_DMS_QOS(); + } + //qmierr = requestGetSIMStatus(&SIMStatus); + qmierr = requestGetSIMStatus(&SIMStatus, sim_number); + while (qmierr == QMI_ERR_OP_DEVICE_UNSUPPORTED) { + sleep(1); + //qmierr = requestGetSIMStatus(&SIMStatus); + qmierr = requestGetSIMStatus(&SIMStatus, sim_number); +//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817 + } + if ((SIMStatus == SIM_PIN) && profile.pincode) { + requestEnterSimPin(profile.pincode); + } +#ifdef CONFIG_IMSI_ICCID + if (SIMStatus == SIM_READY) { + requestGetICCID(); + requestGetIMSI(); + } +#endif +#endif +#ifdef CONFIG_APN + if (profile.apn || profile.user || profile.password) { + requestSetProfile(&profile); + } + requestGetProfile(&profile); +#endif + requestRegistrationState2(&PSAttachedState); + /* + if (!requestQueryDataCall(&IPv4ConnectionStatus, IpFamilyV4) && + (QWDS_PKT_DATA_CONNECTED == IPv4ConnectionStatus)) usbnet_link_change(1, + &profile); else usbnet_link_change(0, &profile); + */ + send_signo_to_main(SIGUSR2); + + while (1) { + struct pollfd pollfds[] = {{signal_control_fd[1], POLLIN, 0}, + {qmidevice_control_fd[0], POLLIN, 0}}; + int ne, ret, nevents = sizeof(pollfds) / sizeof(pollfds[0]); + + do { + ret = poll(pollfds, nevents, 15 * 1000); + } while ((ret < 0) && (errno == EINTR)); + + if (ret == 0) { + send_signo_to_main(SIGUSR2); + continue; + } + + if (ret <= 0) { + dbg_time("%s poll=%d, errno: %d (%s)", __func__, ret, errno, + strerror(errno)); + goto __main_quit; + } + + for (ne = 0; ne < nevents; ne++) { + int fd = pollfds[ne].fd; + short revents = pollfds[ne].revents; + dbg_time("epoll fd = %d, events = 0x%04x", fd, revents); + if (revents & (POLLERR | POLLHUP | POLLNVAL)) { + dbg_time("%s poll err/hup", __func__); + dbg_time("epoll fd = %d, events = 0x%04x", fd, revents); + main_send_event_to_qmidevice(RIL_REQUEST_QUIT); + if (revents & POLLHUP) + goto __main_quit; + } + + if ((revents & POLLIN) == 0) + continue; + + if (fd == signal_control_fd[1]) { + if (read(fd, &signo, sizeof(signo)) == sizeof(signo)) { + alarm(0); + dbg_time("get signo: %d ",signo); + switch (signo) { + case SIGUSR1: + { + if(profile.ipv4_flag) + { + if (QWDS_PKT_DATA_CONNECTED != IPv4ConnectionStatus) { + usbnet_link_change(0, &profile); + requestRegistrationState2(&PSAttachedState); + +//2021-02-05 willa.liu@fibocom.com changed begin for support mantis 0070460 + //if (PSAttachedState == 1 || profile.loopback_state == 0) { + if (PSAttachedState == 1 || profile.loopback_state == 1) { + qmierr = + requestSetupDataCall(&profile, IpFamilyV4); + + if ((qmierr > 0) && profile.user && + profile.user[0] && profile.password && + profile.password[0]) { + int old_auto = profile.auth; + + // may be fail because wrong auth mode, try + // pap->chap, or chap->pap + profile.auth = (profile.auth == 1) ? 2 : 1; + qmierr = requestSetupDataCall(&profile, + IpFamilyV4); + + if (qmierr) + profile.auth = + old_auto; // still fail, restore + // old auth moe + } + if (!qmierr) { + requestGetIPAddress(&profile, IpFamilyV4); + } + if (!qmierr){ + IPv4ConnectionStatus = QWDS_PKT_DATA_CONNECTED; + FailDailRadioTime.tv_sec = 0; + } + else if(FailDailRadioTime.tv_sec == 0) { + gettimeofday(&FailDailRadioTime, (struct timezone *)NULL); + } + } + } + } + if(profile.ipv6_flag) + { + if (QWDS_PKT_DATA_CONNECTED != IPV6ConnectionStatus) { + if(!profile.ipv4_flag) + { + usbnet_link_change(0, &profile); + requestRegistrationState2(&PSAttachedState); + } + else + { + profile.dual_flag = 1; + //PSAttachedState = 1; // for dual stack + requestRegistrationState2(&PSAttachedState); + } +//2021-02-05 willa.liu@fibocom.com changed end for support mantis 0070460 + + if (PSAttachedState == 1) { + qmierr = + requestSetupDataCall(&profile, IpFamilyV6); + if ((g_MobileCountryCode == 460) && (g_MobileNetworkCode == 1 || g_MobileNetworkCode == 6)) { + if (qmierr > 0 && profile.dual_flag == 1) { + profile.dual_flag = 0; + profile.ipv6_flag = 0; + dbg_time("%s Dual stack dial IPv6 failed, quit", __func__); + break; + } + } + if ((qmierr > 0) && profile.user && + profile.user[0] && profile.password && + profile.password[0]) { + int old_auto = profile.auth; + + // may be fail because wrong auth mode, try + // pap->chap, or chap->pap + profile.auth = (profile.auth == 1) ? 2 : 1; + qmierr = requestSetupDataCall(&profile, + IpFamilyV6); + + if (qmierr) + profile.auth = + old_auto; // still fail, restore + // old auth moe + } + if (!qmierr) { + requestGetIPAddress(&profile, IpFamilyV6); + } + + if (!qmierr){ + IPV6ConnectionStatus = QWDS_PKT_DATA_CONNECTED; + FailDailRadioTime.tv_sec = 0; + } + else if(FailDailRadioTime.tv_sec == 0) { + gettimeofday(&FailDailRadioTime, (struct timezone *)NULL); + } + } + } + } +#ifdef CONFIG_RESET_RADIO + if( ((profile.ipv4_flag)&&(IPv4ConnectionStatus != QWDS_PKT_DATA_CONNECTED))|| + ((profile.ipv6_flag)&&(IPV6ConnectionStatus != QWDS_PKT_DATA_CONNECTED))) + { + gettimeofday(&nowTime, (struct timezone *)NULL); + if( ((abs(nowTime.tv_sec - FailDailRadioTime.tv_sec) > CONFIG_RESET_RADIO)) + &&(FailDailRadioTime.tv_sec > resetRadioTime.tv_sec)){ + resetRadioTime = nowTime; + // requestSetOperatingMode(0x06); //same as + // AT+CFUN=0 + requestSetOperatingMode( + 0x01); // same as AT+CFUN=4 + requestSetOperatingMode( + 0x00); // same as AT+CFUN=1 + } + } +#endif + alarm(5); // try to setup data call 5 seconds later + } + break; + + case SIGUSR2: + { + + if (profile.ipv4_flag) + { + requestQueryDataCall(&IPv4ConnectionStatus, IpFamilyV4); + //local ip is different with remote ip + if (QWDS_PKT_DATA_CONNECTED == IPv4ConnectionStatus && check_address(&profile,IpFamilyV4) == 0) { + requestDeactivateDefaultPDP(&profile, IpFamilyV4); + IPv4ConnectionStatus = QWDS_PKT_DATA_DISCONNECTED; + } + } + else + IPv4ConnectionStatus = QWDS_PKT_DATA_DISCONNECTED; + if (profile.ipv6_flag) + requestQueryDataCall(&IPV6ConnectionStatus, IpFamilyV6); + else + IPV6ConnectionStatus = QWDS_PKT_DATA_DISCONNECTED; + if(IPv4ConnectionStatus == QWDS_PKT_DATA_DISCONNECTED && IPV6ConnectionStatus == QWDS_PKT_DATA_DISCONNECTED) + { + usbnet_link_change(0, &profile); + } + if((profile.ipv6_flag && profile.ipv6_flag ) && ((IPv4ConnectionStatus == QWDS_PKT_DATA_CONNECTED && IPV6ConnectionStatus == QWDS_PKT_DATA_CONNECTED)) ) + { + usbnet_link_change(1, &profile); + } + else + if(IPv4ConnectionStatus == QWDS_PKT_DATA_CONNECTED || IPV6ConnectionStatus == QWDS_PKT_DATA_CONNECTED) + { + usbnet_link_change(1, &profile); + } + if((profile.ipv4_flag && IPv4ConnectionStatus == QWDS_PKT_DATA_DISCONNECTED ) || + (profile.ipv6_flag && IPV6ConnectionStatus == QWDS_PKT_DATA_DISCONNECTED )) + { + send_signo_to_main(SIGUSR1); + } + } + break; + + case SIGTERM: + case SIGHUP: + case SIGINT: + if(profile.ipv4_flag && IPv4ConnectionStatus == QWDS_PKT_DATA_CONNECTED) + requestDeactivateDefaultPDP(&profile, IpFamilyV4); + if(profile.ipv6_flag && IPV6ConnectionStatus == QWDS_PKT_DATA_CONNECTED) + requestDeactivateDefaultPDP(&profile, IpFamilyV6); + + usbnet_link_change(0, &profile); + if (profile.qmi_ops->deinit) + profile.qmi_ops->deinit(); + main_send_event_to_qmidevice(RIL_REQUEST_QUIT); + goto __main_quit; + break; + + default: + break; + } + } + } + + if (fd == qmidevice_control_fd[0]) { + if (read(fd, &triger_event, sizeof(triger_event)) == + sizeof(triger_event)) { + switch (triger_event) { + case RIL_INDICATE_DEVICE_DISCONNECTED: + usbnet_link_change(0, &profile); + if (main_loop) { + if (pthread_join(gQmiThreadID, NULL)) { + dbg_time( + "%s Error joining to listener thread (%s)", + __func__, strerror(errno)); + } + profile.qmichannel = NULL; + profile.usbnet_adapter = save_usbnet_adapter; + goto __main_loop; + } + goto __main_quit; + break; + + case RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED: + requestRegistrationState2(&PSAttachedState); + if (PSAttachedState == 1) + { +//begin modify for mantis 0050112 by kaibo.zhangkaibo@fibocom.com + if((profile.ipv4_flag && IPv4ConnectionStatus == QWDS_PKT_DATA_DISCONNECTED) + ||(profile.ipv6_flag && IPV6ConnectionStatus == QWDS_PKT_DATA_DISCONNECTED)) +//end modify for mantis 0050112 by kaibo.zhangkaibo@fibocom.com + send_signo_to_main(SIGUSR1); + } + break; + + case RIL_UNSOL_DATA_CALL_LIST_CHANGED: + if (IPv4ConnectionStatus == QWDS_PKT_DATA_CONNECTED || IPV6ConnectionStatus == QWDS_PKT_DATA_CONNECTED) + send_signo_to_main(SIGUSR2); + break; + + default: + break; + } + } + } + } + } + +__main_quit: + usbnet_link_change(0, &profile); + if (pthread_join(gQmiThreadID, NULL)) { + dbg_time("%s Error joining to listener thread (%s)", __func__, + strerror(errno)); + } + close(signal_control_fd[0]); + close(signal_control_fd[1]); + close(qmidevice_control_fd[0]); + close(qmidevice_control_fd[1]); + dbg_time("%s exit", __func__); + if (logfilefp) + fclose(logfilefp); + +//2020-12-23 willa.liu@fibocom.com changed begin for support mantis 0065286 + unlink(fibo_dial_filepath); + close(socket_server_fd ); + close(cli_accept_fd ); +//2020-12-23 willa.liu@fibocom.com changed end for support mantis 0065286 + + return 0; +} diff --git a/package/wwan/app/fibocom-dial/src/multi-pdn-manager.c b/package/wwan/app/fibocom-dial/src/multi-pdn-manager.c new file mode 100755 index 000000000..20d05e732 --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/multi-pdn-manager.c @@ -0,0 +1,1019 @@ +#include +#include +#include +#include +#include +#include +#include +#include +//begin modified by zhangkaibo get qmap_num process flow. mantis 0048920,0048917 20200605 +#include +//end modified by zhangkaibo get qmap_num process flow. mantis 0048920,0048917 20200605 +#include "util.h" +#include "query_pcie_mode.h" +#define MAJOR 1 +#define MINOR 0 +#define REVISION 4 +/* + * Generally, we do not modify version info, so several modifications will share + * the same version code. SUBVERSION is used for customized modification to + * distinguise this version from previous one. SUBVERSION adds up before you + * send the code to customers and it should be set to 0 if VERSION_STRING info + * is changed. + */ +#define SUBVERSION 0 +#define STRINGIFY_HELPER(v) #v +#define STRINGIFY(v) STRINGIFY_HELPER(v) +#define VERSION_STRING() \ + STRINGIFY(MAJOR) "." STRINGIFY(MINOR) "." STRINGIFY(REVISION) +#define MAX_PATH 256 + +#define _PARAM_GLOBALS_ +#include +#include +#include +#include +#include +#include +#include +#include +#include +//begin modified by zhangkaibo get qmap_num process flow. mantis 0048920,0048917 20200605 +#include +//end modified by zhangkaibo get qmap_num process flow. mantis 0048920,0048917 20200605 +#define SECTION_MAX_LEN 256 +#define STRVALUE_MAX_LEN 256 +#define LINE_CONTENT_MAX_LEN 256 +#define READ_STR_ERR -1 +#define READ_STR_OK 0 +//begin modified by zhangkaibo get qmap_num process flow. mantis 0048920,0048917 20200605 + +//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817 +//#include "query_pcie_mode.h" +//2021-03-24 willa.liu@fibocom.com changed end for support mantis 0071817 + +static int is_pcie_dial() +{ + return (access("/dev/mhi_QMI0", F_OK) == 0); +} + +static int is_gobinet_dial() +{ + return (access("/dev/qcqmi0", F_OK) == 0); +} + +static int is_qmiwwan_dial() +{ + return (access("/dev/cdc-wdm0", F_OK) == 0); +} + +static size_t fibo_fread(const char *filename, void *buf, size_t size) +{ + FILE *fp = fopen(filename, "r"); + size_t n = 0; + + memset(buf, 0x00, size); + + if (fp) { + n = fread(buf, 1, size, fp); + if (n <= 0 || n == size) { + dbg_time( + "warnning: fail to fread(%s), fread=%zd, buf_size=%zd, " + "errno: %d (%s)", + __func__, filename, n, size, errno, strerror(errno)); + } + fclose(fp); + } + + return n > 0 ? n : 0; +} + +int get_qmap_num() +{ + int n; + int qmap_num=-1; + char buf[128]; + struct { + char filename[255 * 2]; + char linkname[255 * 2]; + } * pl; + + if (is_pcie_dial()) + return 8; + + pl = (typeof(pl))malloc(sizeof(*pl)); + + if(is_gobinet_dial()) + { + snprintf(pl->linkname, sizeof(pl->linkname), + "/sys/class/net/usb0/device/driver"); + n = readlink(pl->linkname, pl->filename, sizeof(pl->filename)); + pl->filename[n] = '\0'; + while (pl->filename[n] != '/') n--; + + snprintf(pl->filename, sizeof(pl->filename), "/sys/class/net/usb0/qmap_num"); + //2021-02-22 kaibo.zhangkaibo@fibocom.com changed begin for support mantis 0071171 + if (access(pl->filename, F_OK) == 0) { + dbg_time("access %s", pl->filename); + if (errno != ENOENT) { + dbg_time("fail to access %s, errno: %d (%s)", pl->filename, errno, + strerror(errno)); + goto _out; + } + } + else + { + snprintf(pl->filename, sizeof(pl->filename), "/sys/class/net/usb0/qmap_mode"); + if (access(pl->filename, F_OK) == 0) { + dbg_time("access %s", pl->filename); + if (errno != ENOENT) { + dbg_time("fail to access %s, errno: %d (%s)", pl->filename, errno, + strerror(errno)); + goto _out; + } + } + } + } + if(is_qmiwwan_dial()) + { + snprintf(pl->linkname, sizeof(pl->linkname), + "/sys/class/net/wwan0/device/driver"); + n = readlink(pl->linkname, pl->filename, sizeof(pl->filename)); + pl->filename[n] = '\0'; + while (pl->filename[n] != '/') n--; + + snprintf(pl->filename, sizeof(pl->filename), "/sys/class/net/wwan0/qmap_mode"); + if (access(pl->filename, F_OK) == 0) { + dbg_time("access %s", pl->filename); + if (errno != ENOENT) { + dbg_time("fail to access %s, errno: %d (%s)", pl->filename, errno, + strerror(errno)); + goto _out; + } + } + } + + dbg_time("access %s", pl->filename); + + if (!access(pl->filename, R_OK)) { + n = fibo_fread(pl->filename, buf, sizeof(buf)); + if (n > 0) { + qmap_num = atoi(buf); + } + } +_out: + free(pl); + + return qmap_num; +} +//end modified by zhangkaibo get qmap_num process flow. mantis 0048920,0048917 20200605 +//begin modified by zhangkaibo limit input parameters. mantis 0048965 20200605 +int IsInt(char* str) +{ + int len; + len = strlen(str-1); + len = len>=1?len:1; + int i=0; + for(; i < len ; i++) + { + if(!(isdigit(str[i]))) + return 0; + } + return 1; +} + +//end modified by zhangkaibo limit input parameters. mantis 0048965 20200605 +// read value from .ini +void IniReadValue(char *section, char *key, char *val, const char *file) +{ + FILE *fp; + int i = 0; + int lineContentLen = 0; + int position = 0; + char lineContent[LINE_CONTENT_MAX_LEN]; + bool bFoundSection = false; + bool bFoundKey = false; + fp = fopen(file, "r"); + if (fp == NULL) { + printf("%s: Opent file %s failed.\n", __FILE__, file); + return; + } + while (feof(fp) == 0) { + memset(lineContent, 0, LINE_CONTENT_MAX_LEN); + fgets(lineContent, LINE_CONTENT_MAX_LEN, fp); + if ((lineContent[0] == ';') || (lineContent[0] == '\0') || + (lineContent[0] == '\r') || (lineContent[0] == '\n')) { + continue; + } + + // check section + if (strncmp(lineContent, section, strlen(section)) == 0) { + bFoundSection = true; + // printf("Found section = %s\n", lineContent); + while (feof(fp) == 0) { + memset(lineContent, 0, LINE_CONTENT_MAX_LEN); + fgets(lineContent, LINE_CONTENT_MAX_LEN, fp); + // check key + if (strncmp(lineContent, key, strlen(key)) == 0) { + bFoundKey = true; + lineContentLen = strlen(lineContent); + // find value + for (i = strlen(key); i < lineContentLen; i++) { + if (lineContent[i] == '=') { + position = i + 1; + break; + } + } + if (i >= lineContentLen) + break; + strncpy(val, lineContent + position, + strlen(lineContent + position)); + lineContentLen = strlen(val); + for (i = 0; i < lineContentLen; i++) { + if ((val[i] == '\0') || (val[i] == '\r') || + (val[i] == '\n')) { + val[i] = '\0'; + // break; + } + } + } else if (lineContent[0] == '[') { + break; + } + } + break; + } + } + if (!bFoundSection) { + printf("No section = %s\n", section); + } else if (!bFoundKey) { + printf("No key = %s\n", key); + } + + fclose(fp); +} + +int readStringValue(const char *section, char *key, char *val, const char *file) +{ + char sect[SECTION_MAX_LEN]; + // printf("section = %s, key = %s, file = %s\n", section, key, file); + if (section == NULL || key == NULL || val == NULL || file == NULL) { + printf("%s: input parameter(s) is NULL!\n", __func__); + return READ_STR_ERR; + } + + memset(sect, 0, SECTION_MAX_LEN); + sprintf(sect, "[%s]", section); + // printf("reading value...\n"); + IniReadValue(sect, key, val, file); + + return READ_STR_OK; +} + +char fileContents[80][LINE_CONTENT_MAX_LEN]; +int fileIndex = 0; + +void IniWriteValue(const char *section, char *key, char *val, const char *file) +{ + int err = 0; + char lineContent[LINE_CONTENT_MAX_LEN]; + char strWrite[LINE_CONTENT_MAX_LEN]; + bool bFoundSection = false; + bool bFoundKey = false; + int fileIndextemp = 0; + memset(lineContent, '\0', LINE_CONTENT_MAX_LEN); + memset(strWrite, '\0', LINE_CONTENT_MAX_LEN); + sprintf(strWrite, "%s=%s\n", key, val); + + while (fileIndextemp <= fileIndex) { + memset(lineContent, 0, LINE_CONTENT_MAX_LEN); + memcpy(lineContent, fileContents[fileIndextemp++], + LINE_CONTENT_MAX_LEN); + if ((lineContent[0] == ';') || (lineContent[0] == '\0') || + (lineContent[0] == '\r') || (lineContent[0] == '\n')) { + continue; + } + // check section + if (strncmp(lineContent, section, strlen(section)) == 0) { + bFoundSection = true; + while (fileIndextemp <= fileIndex) { + memset(lineContent, 0, LINE_CONTENT_MAX_LEN); + memcpy(lineContent, fileContents[fileIndextemp], + LINE_CONTENT_MAX_LEN); + // check key + if (strncmp(lineContent, key, strlen(key)) == 0) { + bFoundKey = true; + // printf("%s: %s=%s\n", __func__, key, val); + memset(fileContents[fileIndextemp], 0, + LINE_CONTENT_MAX_LEN); + memcpy(fileContents[fileIndextemp], strWrite, + strlen(strWrite)); + // printf("%s\n",strWrite); + if (err < 0) { + printf("%s err.\n", __func__); + } + break; + } else if (lineContent[0] == '[') { + fileIndextemp++; + break; + } + fileIndextemp++; + } + break; + } + } + if (!bFoundSection) { + printf("No section = %s\n", section); + } else if (!bFoundKey) { + printf("No key = %s\n", key); + } +} + +int writeStringVlaue(const char *section, char *key, char *val, + const char *file) +{ + char sect[SECTION_MAX_LEN]; + + // printf("section = %s, key = %s, value=%s , file = %s\n", section, key, + // val, file); + if (section == NULL || key == NULL || val == NULL || file == NULL) { + printf("%s: input parameter(s) is NULL!\n", __func__); + return READ_STR_ERR; + } + memset(sect, '\0', SECTION_MAX_LEN); + sprintf(sect, "[%s]", section); + IniWriteValue(sect, key, val, file); + return READ_STR_OK; +} + +int writeIntValue(const char *section, char *key, int val, const char *file) +{ + char strValue[STRVALUE_MAX_LEN]; + memset(strValue, '\0', STRVALUE_MAX_LEN); + sprintf(strValue, "%d", val); + + return writeStringVlaue(section, key, strValue, file); +} + +int readIntValue(const char *section, char *key, const char *file) +{ + char strValue[STRVALUE_MAX_LEN]; + memset(strValue, '\0', STRVALUE_MAX_LEN); + if (readStringValue(section, key, strValue, file) != READ_STR_OK) { + printf("%s: error", __func__); + return 0; + } + return (atoi(strValue)); +} + +int mygetch() +{ + struct termios oldt, newt; + int ch; + tcgetattr(STDIN_FILENO, &oldt); + newt = oldt; + newt.c_lflag &= ~(ICANON | ECHO); + tcsetattr(STDIN_FILENO, TCSANOW, &newt); + ch = getchar(); + tcsetattr(STDIN_FILENO, TCSANOW, &oldt); + return ch; +} + +#define CONFIG_FILE "multi-pdn.ini" +#define DIAL_PROCESS "fibocom-dial" +#define MAX_QMAP_NUM 8 + +struct profile { + char apn[MAX_PATH]; + char user[MAX_PATH]; + char password[MAX_PATH]; + int auth; + int ipfamily; +//begin modified by zhangkaibo add sim pin operate. mantis 0049142 20200612 + char pin[MAX_PATH]; +//end modified by zhangkaibo add sim pin operate. mantis 0049142 20200612 +}; + +int shmid; +void *shm; +int qmap_num = -1; + +bool connectState[MAX_QMAP_NUM]; +int lock_file = -1; + +void initShareMemory() +{ + shmid = shmget((key_t)9527, sizeof(int) * 8, 0666 | IPC_CREAT); + if (shmid == -1) { + fprintf(stderr, "shmget failed\n"); + exit(EXIT_FAILURE); + } + shm = shmat(shmid, 0, 0); + if (shm == (void *)-1) { + fprintf(stderr, "shmat failed\n"); + exit(EXIT_FAILURE); + } +} + +void destoryShareMemory() +{ + if (shmdt(shm) == -1) { + fprintf(stderr, "shmdt failed\n"); + exit(EXIT_FAILURE); + } + + if (shmctl(shmid, IPC_RMID, 0) == -1) { + fprintf(stderr, "shmctl(IPC_RMID) failed\n"); + exit(EXIT_FAILURE); + } +} + +void SIGINT_handle(int sig_num) + +{ + printf("reveice signal %d \n", sig_num); + { + int *connectPids = (int *)shm; + int cIndex; + for(cIndex = 1 ; cIndex <= qmap_num ; cIndex++) + { + dbg_time("kill pid %d", connectPids[cIndex - 1]); + kill(connectPids[cIndex - 1], SIGINT); + connectState[cIndex - 1] = false; + } + } + destoryShareMemory(); + close(lock_file); // 不要忘记释放文件指针 + exit(0); +} + +int loadConfigFromIni(struct profile *profileList, bool *connectState) +{ + int profileIndex; +//begin modified by zhangkaibo get qmap_num process flow. mantis 0048920,0048917 20200605 + //qmap_num = readIntValue("Setting", "qmap_num", CONFIG_FILE); + qmap_num = get_qmap_num(); + if (qmap_num == 0 || qmap_num == -1 ) + return -1; +//end modified by zhangkaibo get qmap_num process flow. mantis 0048920,0048917 20200605 + for (profileIndex = 0; profileIndex < 8; profileIndex++) { + char profilename[MAX_PATH]; + sprintf(profilename, "profile%d", profileIndex + 1); + memset(profileList[profileIndex].apn, 0, MAX_PATH); + readStringValue(profilename, "apn", profileList[profileIndex].apn, + CONFIG_FILE); + memset(profileList[profileIndex].user, 0, MAX_PATH); + readStringValue(profilename, "user", profileList[profileIndex].user, + CONFIG_FILE); + memset(profileList[profileIndex].password, 0, MAX_PATH); + readStringValue(profilename, "password", + profileList[profileIndex].password, CONFIG_FILE); + profileList[profileIndex].auth = + readIntValue(profilename, "auth", CONFIG_FILE); + profileList[profileIndex].ipfamily = + readIntValue(profilename, "ipfamily", CONFIG_FILE); +//begin modified by zhangkaibo add sim pin operate. mantis 0049142 20200612 + memset(profileList[profileIndex].pin, 0, MAX_PATH); + readStringValue(profilename, "pin", profileList[profileIndex].pin, + CONFIG_FILE); +//end modified by zhangkaibo add sim pin operate. mantis 0049142 20200612 + } + FILE *fp; + fileIndex = 0; + char lineContent[LINE_CONTENT_MAX_LEN]; + fp = fopen(CONFIG_FILE, "r+"); + if (fp == NULL) { + printf("%s: Opent file %s failed.\n", __FILE__, CONFIG_FILE); + return -2; + } + // read all + while (feof(fp) == 0) { + memset(lineContent, 0, LINE_CONTENT_MAX_LEN); + fgets(lineContent, LINE_CONTENT_MAX_LEN, fp); + memcpy(fileContents[fileIndex], lineContent, strlen(lineContent)); + // printf("%s",fileContents[fileIndex]); + fileIndex++; + } + fclose(fp); + return 0; +} + +void saveConfigToIni() +{ + FILE *fp; + fp = fopen(CONFIG_FILE, "w"); + int fileIndextemp = 0; + fseek(fp, 0, SEEK_SET); + while (fileIndextemp <= fileIndex) { + fwrite(fileContents[fileIndextemp], strlen(fileContents[fileIndextemp]), + 1, fp); + // printf("%s",fileContents[fileIndextemp]); + fileIndextemp++; + } + fclose(fp); +} + +void modifyProfile(struct profile *profileList) +{ + int profileIndex; +//begin modified by zhangkaibo limit input parameters. mantis 0048965 20200605 + struct profile tempprofile; +//end modified by zhangkaibo limit input parameters. mantis 0048965 20200605 + char *f; + // show current fprfile setting + for (profileIndex = 0; profileIndex < 8; profileIndex++) { + dbg_time( + "Fibocom manager \nprofile%d apn:\"%s\" username:\"%s\" password: " + "\"%s\" auth: \"%d\" ip family: \"%d\"", + profileIndex + 1, profileList[profileIndex].apn, + profileList[profileIndex].user, profileList[profileIndex].password, + profileList[profileIndex].auth, profileList[profileIndex].ipfamily); + } + // select instance to be set + int connectProfile; + printf("set profile index:"); + f = malloc(sizeof(f)); + fgets(f,sizeof(f),stdin); + connectProfile = atoi(f); +//begin modified by zhangkaibo limit input parameters. mantis 0048965 20200605 + if(!IsInt(f)){ + dbg_time("invalid input"); + return; + } +//end modified by zhangkaibo limit input parameters. mantis 0048965 20200605 + if (connectProfile < 0 || connectProfile > 8) { + dbg_time("error profile id"); + return; + } + free(f); + /* + * Begin: 2020-11-16, Lizhengyang for multi-pdn-manager, + * Solve the problem of setting length + * of apn/username/password, mantis 0062495. + */ + printf("profile apn:"); + f = malloc(MAX_PATH); + if (f == NULL) + { + printf("profile apn f malloc null\n"); + return; + } + fgets(f, MAX_PATH, stdin); + f[strlen(f) - 1] = '\0'; + strcpy(tempprofile.apn, f); + free(f); + + printf("profile username:"); + f = malloc(MAX_PATH); + if (f == NULL) + { + printf("profile username f malloc null\n"); + return; + } + fgets(f, MAX_PATH, stdin); + f[strlen(f) - 1] = '\0'; + strcpy(tempprofile.user, f); + free(f); + + printf("profile password:"); + f = malloc(MAX_PATH); + if (f == NULL) + { + printf("profile password f malloc null\n"); + return; + } + fgets(f, MAX_PATH, stdin); + f[strlen(f) - 1] = '\0'; + strcpy(tempprofile.password, f); + free(f); + /* + * End: 2020-11-16, Lizhengyang for multi-pdn-manager, + * Solve the problem of setting length + * of apn/username/password, mantis 0062495. + */ + printf("profile auth[0-3]:"); + f = malloc(sizeof(f)); + fgets(f,sizeof(f),stdin); +//begin modified by zhangkaibo limit input parameters. mantis 0048965 20200605 + tempprofile.auth = atoi(f); + if(!IsInt(f)){ + dbg_time("invalid input"); + return; + } + if(tempprofile.auth < 0 || tempprofile.auth > 3){ + dbg_time("invalid auth type"); + return; + } +//end modified by zhangkaibo limit input parameters. mantis 0048965 20200605 + free(f); + + printf("profile ipfamily[1-3]:"); + f = malloc(sizeof(f)); + fgets(f,sizeof(f),stdin); +//begin modified by zhangkaibo limit input parameters. mantis 0048965 20200605 + tempprofile.ipfamily = atoi(f); + if(!IsInt(f)){ + dbg_time("invalid input"); + return; + } + free(f); + if(tempprofile.ipfamily < 1 || tempprofile.ipfamily > 3){ + dbg_time("invalid auth type"); + return; + } +//begin modified by zhangkaibo add sim pin operate. mantis 0049142 20200612 + printf("pin:"); + f = malloc(sizeof(f)); + fgets(f,sizeof(f),stdin); + f[strlen(f)-1]='\0'; + strcpy(tempprofile.pin, f); + free(f); +//end modified by zhangkaibo add sim pin operate. mantis 0049142 20200612 + memset(profileList[connectProfile-1].apn, 0, MAX_PATH); + memset(profileList[connectProfile-1].user, 0, MAX_PATH); + memset(profileList[connectProfile-1].password, 0, MAX_PATH); + + strcpy(profileList[connectProfile-1].apn , tempprofile.apn); + strcpy(profileList[connectProfile-1].user , tempprofile.user); + strcpy(profileList[connectProfile-1].password , tempprofile.password); + profileList[connectProfile-1].auth = tempprofile.auth; + profileList[connectProfile-1].ipfamily = tempprofile.ipfamily; +//end modified by zhangkaibo limit input parameters. mantis 0048965 20200605 +//begin modified by zhangkaibo add sim pin operate. mantis 0049142 20200612 + //strcpy(profileList[connectProfile].pin , tempprofile.pin); + strcpy(profileList[connectProfile-1].pin , tempprofile.pin); +//end modified by zhangkaibo add sim pin operate. mantis 0049142 20200612 + // save in + for (profileIndex = 0; profileIndex < qmap_num; profileIndex++) { + dbg_time( + "Fibocom manager \nprofile%d apn:\"%s\" username:\"%s\" pawssword: " + "\"%s\" auth: \"%d\" ip family: \"%d\"", + profileIndex + 1, profileList[profileIndex].apn, + profileList[profileIndex].user, profileList[profileIndex].password, + profileList[profileIndex].auth, profileList[profileIndex].ipfamily); + char profilename[MAX_PATH]; + sprintf(profilename, "profile%d", profileIndex + 1); + writeStringVlaue(profilename, "apn", profileList[profileIndex].apn, + CONFIG_FILE); + writeStringVlaue(profilename, "user", profileList[profileIndex].user, + CONFIG_FILE); + writeStringVlaue(profilename, "password", + profileList[profileIndex].password, CONFIG_FILE); + writeIntValue(profilename, "auth", profileList[profileIndex].auth, + CONFIG_FILE); + writeIntValue(profilename, "ipfamily", + profileList[profileIndex].ipfamily, CONFIG_FILE); +//begin modified by zhangkaibo add sim pin operate. mantis 0049142 20200612 + writeStringVlaue(profilename, "pin", + profileList[profileIndex].pin, CONFIG_FILE); +//end modified by zhangkaibo add sim pin operate. mantis 0049142 20200612 + } +} + +void startConnectCM(struct profile *profileList, bool *connectState) +{ + int connectIndex; + int connectProfile; + char *f; + printf("connect visual net interface use:"); + f = malloc(sizeof(f)); + fgets(f,sizeof(f),stdin); + connectIndex = atoi(f); + free(f); + if (connectIndex < 1 || connectIndex > qmap_num) { + dbg_time("error visual net interface "); + return; + } + printf("connect profile use:"); + f = malloc(sizeof(f)); + fgets(f,sizeof(f),stdin); + connectProfile = atoi(f); + free(f); + if (connectProfile < 1 || connectProfile > 8) { + dbg_time("error profile id"); + return; + } +//begin modified by zhangkaibo modify mantis0048806. 20200605 + if (connectState[connectIndex - 1] == true) { + dbg_time( + "visual net interface %d now is connected", + connectIndex); + return; + } +//end modified by zhangkaibo modify mantis0048806. 20200605 + dbg_time("Start connect network use instance %d profile %d", connectIndex, + connectProfile); + char cmd[1024]; + //./fibicom-dial -n -s -s apn user password auth -4 -6 + + sprintf(cmd, "-n %d -m %d -s %s %s %s %d", connectIndex, connectProfile, + profileList[connectProfile - 1].apn, + profileList[connectProfile - 1].user, + profileList[connectProfile - 1].password, + profileList[connectProfile - 1].auth); + char *argvCmd[30]; + int index = 0; + // DIAL_PROCESS,","-N","4,""-n","2","-m","1","-s","ctnet","","","","-4","-6","-f","temp.txt",NULL; + argvCmd[index] = malloc(256); + sprintf(argvCmd[index++], "%s", DIAL_PROCESS); + argvCmd[index] = malloc(5); + sprintf(argvCmd[index++], "-N"); + argvCmd[index] = malloc(256); + sprintf(argvCmd[index++], "%d", qmap_num); + argvCmd[index] = malloc(5); + sprintf(argvCmd[index++], "-n"); + argvCmd[index] = malloc(256); + sprintf(argvCmd[index++], "%d", connectIndex); + argvCmd[index] = malloc(5); + sprintf(argvCmd[index++], "-m"); + argvCmd[index] = malloc(256); + sprintf(argvCmd[index++], "%d", connectProfile); + argvCmd[index] = malloc(5); + sprintf(argvCmd[index++], "-s"); + argvCmd[index] = malloc(256); + sprintf(argvCmd[index++], "%s", profileList[connectProfile - 1].apn); + if (strlen(profileList[connectProfile - 1].user) > 0) { + argvCmd[index] = malloc(256); + sprintf(argvCmd[index++], "%s", profileList[connectProfile - 1].user); + argvCmd[index] = malloc(256); + sprintf(argvCmd[index++], "%s", + profileList[connectProfile - 1].password); + argvCmd[index] = malloc(256); + sprintf(argvCmd[index++], "%d", profileList[connectProfile - 1].auth); + } + + if (profileList[connectProfile - 1].ipfamily == 2) { + argvCmd[index] = malloc(5); +//begin modified by zhangkaibo fix ipv6 dial process flow. mantis 0048789 20200605 + sprintf(argvCmd[index++], "-6"); +//end modified by zhangkaibo fix ipv6 dial process flow. mantis 0048789 20200605 + } else if (profileList[connectProfile - 1].ipfamily == 3) { + argvCmd[index] = malloc(5); + sprintf(argvCmd[index++], "-4"); + argvCmd[index] = malloc(5); + sprintf(argvCmd[index++], "-6"); + } else { + argvCmd[index] = malloc(5); + sprintf(argvCmd[index++], "-4"); + } +//begin modified by zhangkaibo add sim pin operate. mantis 0049142 20200612 + if (strlen(profileList[connectProfile - 1].pin) > 0) { + argvCmd[index] = malloc(5); + sprintf(argvCmd[index++], "-p"); + argvCmd[index] = malloc(256); + sprintf(argvCmd[index++], "%s", profileList[connectProfile - 1].pin); + } + + argvCmd[index] = malloc(5); +//end modified by zhangkaibo add sim pin operate. mantis 0049142 20200612 + sprintf(argvCmd[index++], "-f"); + argvCmd[index] = malloc(256); + sprintf(argvCmd[index++], "instance%d.txt", connectIndex); + argvCmd[index] = NULL; + char temp[MAX_PATH]; + sprintf(temp, "rm -f instance%d.txt", connectIndex); + system(temp); + if (0 == fork()) { + int *connectPids = (int *)shm; + connectPids[connectIndex - 1] = getpid(); + dbg_time("exec pid %d", connectPids[connectIndex - 1]); + char tempcmd[MAX_PATH]; + sprintf(tempcmd, "./%s", DIAL_PROCESS); + execvp(tempcmd, argvCmd); + // system(cmd); +//begin modified by zhangkaibo add sim pin operate. mantis 0049142 20200612 + } +//2021-02-01 willa.liu@fibocom.com changed begin for support mantis 0069837 + //for(int ii=0; ii < index;ii++) + int ii; + for(ii = 0;ii < index;ii++) +//2021-02-01 willa.liu@fibocom.com changed end for support mantis 0069837 + { + printf("%s ",argvCmd[ii]); + free(argvCmd[ii]); + } + printf("\r\n"); + connectState[connectIndex - 1] = true; +} + +int main(int argc, char *argv[]) +{ + struct profile profileList[MAX_QMAP_NUM]; + char *f; + int profileIndex; + int opsCode = -1; + int ret=0; + + /* Exit if the process is already running */ + lock_file = open("/tmp/single_proc.lock", O_CREAT|O_RDWR, 0666); + ret = flock(lock_file, LOCK_EX|LOCK_NB); + if (ret) + { + if (EWOULDBLOCK == errno) + { + dbg_time("The Fibocom multi-pdn-manager is already running! So killall multi-pdn-manager!"); + system("killall -9 fibocom-dial"); + system("killall -9 multi-pdn-manager"); + } + } + else + { + char buffer[64]; + sprintf(buffer, "pid:%d\n", getpid()); + write(lock_file, buffer, strlen(buffer)); + system("killall -9 fibocom-dial"); + dbg_time("Start Fibocom multi-pdn-manager!\n"); + } + + system("clear"); + + get_pcie_mode(); + + signal(SIGCHLD, SIG_IGN); + + // read from config + ret = loadConfigFromIni(profileList, connectState); + if(ret == -1) + { + dbg_time("Fibocom multi-pdn-manager %s", VERSION_STRING()); + dbg_time("Fibocom manager current qmap_num is %d,not support multi-pdn", qmap_num); + dbg_time("please use \"echo 4 > /sys/class/net/usb0/qmap_num\",set driver to multi mode"); + return -1; + } + if(ret == -2) + return -2; + initShareMemory(); + signal(SIGINT, SIGINT_handle); + if (is_pcie_dial()) + { + dbg_time("start qmi proxy server"); + //system("./fibo_qmimsg_server -d /dev/mhi_QMI0 &"); + } + while (1) + { + // show tips + dbg_time("Fibocom multi-pdn-manager %s", VERSION_STRING()); + dbg_time("Fibocom manager current qmap_num is %d", qmap_num); + for (profileIndex = 0; profileIndex < qmap_num; profileIndex++) + { + dbg_time("Fibocom manager sub-instance%d %s", profileIndex + 1, + connectState[profileIndex] ? "Connected" : "Disconnected"); + } + printf("Please select an action[0-9]\n"); + printf("1.show profile setting\n"); + printf("2.set profile setting\n"); + printf("3.connect to network\n"); + printf("4.disconnect to network\n"); + printf("5.show connect log\n"); + printf("6.reload profile setting\n"); + printf("7.save profile setting\n"); + printf("8.show max instance number\n"); + printf("9.set max instance number\n"); + printf("0.exit\n"); + + // get operate + printf("input [0-9]: "); + f = malloc(sizeof(f)); + //begin modified by zhangkaibo limit input parameters. mantis 0048965 20200605 + fgets(f,sizeof(f),stdin); + if(!IsInt(f)) + { + dbg_time("invalid input"); + printf("Press any key to continus"); + getchar(); + system("clear"); + continue; + } + //end modified by zhangkaibo limit input parameters. mantis 0048965 20200605 + opsCode = atoi(f); + free(f); + + // select operate + switch (opsCode) + { + case 1: + //begin modified by zhangkaibo add sim pin operate. mantis 0049142 20200612 + for (profileIndex = 0; profileIndex < qmap_num; profileIndex++) + { + dbg_time( + "Fibocom manager \nprofile%d apn:\"%s\" username:\"%s\" " + "password: \"%s\" auth: \"%d\" ip family: \"%d\" pin:\"%s\"", + profileIndex + 1, profileList[profileIndex].apn, + profileList[profileIndex].user, + profileList[profileIndex].password, + profileList[profileIndex].auth, + profileList[profileIndex].ipfamily, + profileList[profileIndex].pin); + } + //end modified by zhangkaibo add sim pin operate. mantis 0049142 20200612 + break; + case 2: + { + modifyProfile(profileList); + } + break; + case 3: + { + startConnectCM(profileList, connectState); + break; + } + case 4: + { + int connectIndex; + printf("disconnect visual net interface :"); + f = malloc(sizeof(f)); + fgets(f,sizeof(f),stdin); + connectIndex = atoi(f); + free(f); + int *connectPids = (int *)shm; + if (connectIndex < 1 || connectIndex > qmap_num) + { + dbg_time("error visual net interface id"); + break; + } + if (connectState[connectIndex - 1] == false) + { + dbg_time("visual net interface %d now is disconnected", connectIndex); + break; + } + dbg_time("kill pid %d", connectPids[connectIndex - 1]); + kill(connectPids[connectIndex - 1], SIGINT); + connectState[connectIndex - 1] = false; + } + break; + case 5: + { + int connectIndex; + printf("show visual net interface :"); + f = malloc(sizeof(f)); + fgets(f,sizeof(f),stdin); + connectIndex = atoi(f); + free(f); + if (connectIndex < 1 || connectIndex > qmap_num) + { + dbg_time("error visual net interface id"); + break; + } + char temp[MAX_PATH]; + sprintf(temp, "cat instance%d.txt", connectIndex); + system(temp); + } + break; + case 6: + { + loadConfigFromIni(profileList, connectState); + } + break; + case 7: + { + saveConfigToIni(profileList); + } + break; + case 8: + printf("qmap_num : %d", qmap_num); + break; + case 9: + { + int temp_qmap; + printf("set qmap_num :"); + f = malloc(sizeof(f)); + fgets(f,sizeof(f),stdin); + temp_qmap = atoi(f); + free(f); + if (temp_qmap < 1 || temp_qmap > 8) + { + dbg_time("error qmap_num id"); + break; + } + qmap_num = temp_qmap; + } + break; + case 0: + printf("exit? [Y/N] :"); + f = malloc(sizeof(f)); + fgets(f,sizeof(f),stdin); + if (f[0] == 'y' || f[0] == 'Y') + goto __main_exit; + break; + default: + dbg_time("invalid input"); + }; + printf("Press any key to continus"); + getchar(); + system("clear"); + } +__main_exit: + { + int *connectPids = (int *)shm; + int cIndex; + for(cIndex = 1 ; cIndex <= qmap_num ; cIndex++) + { + dbg_time("kill pid %d", connectPids[cIndex - 1]); + kill(connectPids[cIndex - 1], SIGINT); + connectState[cIndex - 1] = false; + } + //system("ps -ef|grep fibo|grep -v grep|cut -c 9-15|xargs kill"); + } + destoryShareMemory(); + close(lock_file); // 不要忘记释放文件指针 + return 0; +} diff --git a/package/wwan/app/fibocom-dial/src/multi-pdn.ini b/package/wwan/app/fibocom-dial/src/multi-pdn.ini new file mode 100755 index 000000000..2d53b3ee8 --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/multi-pdn.ini @@ -0,0 +1,67 @@ +[Setting] +qmap_num=4 + +[profile1] +apn=1234567890 +user=qwertyuio +password=asdfghjkl +auth=2 +ipfamily=1 +pin= + +[profile2] +apn=ctnet +user= +password= +auth=0 +ipfamily=1 +pin= + +[profile3] +apn=ctnet +user= +password= +auth=0 +ipfamily=1 +pin= + +[profile4] +apn=ctnet +user= +password= +auth=0 +ipfamily=1 +pin= + +[profile5] +apn=ctnet +user= +password= +auth= +ipfamily=1 +pin= + +[profile6] +apn=ctnet +user= +password= +auth= +ipfamily=1 +pin= + +[profile7] +apn=ctnet +user= +password= +auth= +ipfamily=1 +pin= + +[profile8] +apn=ctnet +user= +password= +auth= +ipfamily=1 +pin= + diff --git a/package/wwan/app/fibocom-dial/src/qmap_bridge_mode.c b/package/wwan/app/fibocom-dial/src/qmap_bridge_mode.c new file mode 100755 index 000000000..99f2ecaef --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/qmap_bridge_mode.c @@ -0,0 +1,438 @@ +#include "QMIThread.h" +//2021-03-15 zhangkaibo@fibocom.com changed begin for oa 20210311037 +#include +//2021-03-15 zhangkaibo@fibocom.com changed end for oa 20210311037 + +static size_t fibo_fread(const char *filename, void *buf, size_t size) +{ + FILE *fp = fopen(filename, "r"); + size_t n = 0; + + memset(buf, 0x00, size); + + if (fp) { + n = fread(buf, 1, size, fp); + if (n <= 0 || n == size) { + dbg_time( + "warnning: fail to fread(%s), fread=%zd, buf_size=%zd, " + "errno: %d (%s)", + __func__, filename, n, size, errno, strerror(errno)); + } + fclose(fp); + } + + return n > 0 ? n : 0; +} + +static size_t fibo_fwrite(const char *filename, const void *buf, size_t size) +{ + FILE *fp = fopen(filename, "w"); + size_t n = 0; + + if (fp) { + n = fwrite(buf, 1, size, fp); + if (n != size) { + dbg_time( + "warnning: fail to fwrite(%s), fwrite=%zd, buf_size=%zd, " + "errno: %d (%s)", + __func__, filename, n, size, errno, strerror(errno)); + } + fclose(fp); + } + + return n > 0 ? n : 0; +} + +static int fibo_iface_is_in_bridge(const char *iface) +{ + char filename[256]; + + snprintf(filename, sizeof(filename), "/sys/class/net/%s/brport", iface); + return (access(filename, F_OK) == 0 || errno != ENOENT); +} + +int fibo_bridge_mode_detect(PROFILE_T *profile) +{ + const char *ifname = profile->qmapnet_adapter ? profile->qmapnet_adapter + : profile->usbnet_adapter; + const char *driver; + char bridge_mode[128]; + char bridge_ipv4[128]; + char ipv4[128]; + char buf[64]; + size_t n; + int in_bridge; + + driver = profile->driver_name; + snprintf(bridge_mode, sizeof(bridge_mode), "/sys/class/net/%s/bridge_mode", + ifname); + snprintf(bridge_ipv4, sizeof(bridge_ipv4), "/sys/class/net/%s/bridge_ipv4", + ifname); + + if (access(bridge_mode, F_OK) && errno == ENOENT) { + snprintf(bridge_mode, sizeof(bridge_mode), + "/sys/module/%s/parameters/bridge_mode", driver); + snprintf(bridge_ipv4, sizeof(bridge_ipv4), + "/sys/module/%s/parameters/bridge_ipv4", driver); + + if (access(bridge_mode, F_OK) && errno == ENOENT) { + bridge_mode[0] = '\0'; + } + } + + in_bridge = fibo_iface_is_in_bridge(ifname); + if (in_bridge) { + dbg_time("notice: iface %s had add to bridge\n", ifname); + } + + if (in_bridge && bridge_mode[0] == '\0') { + dbg_time("warnning: can not find bride_mode file for %s\n", ifname); + return 1; + } + + n = fibo_fread(bridge_mode, buf, sizeof(buf)); + + if (in_bridge) { + if (n <= 0 || buf[0] == '0') { + dbg_time("warnning: should set 1 to bride_mode file for %s\n", + ifname); + return 1; + } + } else { + if (n <= 0 || buf[0] == '0') { + return 0; + } + } + + memset(ipv4, 0, sizeof(ipv4)); + + if (strstr(bridge_ipv4, "/sys/class/net/") || profile->qmap_mode == 0 || + profile->qmap_mode == 1) { + snprintf(ipv4, sizeof(ipv4), "0x%x", profile->ipv4.Address); + dbg_time("echo '%s' > %s", ipv4, bridge_ipv4); + fibo_fwrite(bridge_ipv4, ipv4, strlen(ipv4)); + } else { + snprintf(ipv4, sizeof(ipv4), "0x%x:%d", profile->ipv4.Address, + profile->muxid); + dbg_time("echo '%s' > %s", ipv4, bridge_ipv4); + fibo_fwrite(bridge_ipv4, ipv4, strlen(ipv4)); + } + + return 1; +} +//2021-03-15 zhangkaibo@fibocom.com changed begin for oa 20210311037 +void fibo_get_driver_info(PROFILE_T *profile, RMNET_INFO *rmnet_info) { + int ifc_ctl_sock; + struct ifreq ifr; + int rc; + int request = 0x89F3; + unsigned char data[512]; + + memset(rmnet_info, 0x00, sizeof(*rmnet_info)); + + ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM, 0); + if (ifc_ctl_sock <= 0) { + dbg_time("socket() failed: %s\n", strerror(errno)); + return; + } + + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_name, profile->usbnet_adapter, IFNAMSIZ); + ifr.ifr_name[IFNAMSIZ - 1] = 0; + ifr.ifr_ifru.ifru_data = (void *)data; + rc = ioctl(ifc_ctl_sock, request, &ifr); + if (rc < 0) { + dbg_time("ioctl(0x%x, qmap_settings) failed: %s, rc=%d", request, strerror(errno), rc); + } + else { + memcpy(rmnet_info, data, sizeof(*rmnet_info)); + } + + close(ifc_ctl_sock); +} +//2021-03-15 zhangkaibo@fibocom.com changed end for oa 20210311037 +int fibo_qmap_mode_detect(PROFILE_T *profile) +{ + int n; + char buf[128]; + char qmap_netcard[128]; + struct { + char filename[255 * 2]; + char linkname[255 * 2]; + } * pl; + + pl = (typeof(pl))malloc(sizeof(*pl)); + + snprintf(pl->linkname, sizeof(pl->linkname), + "/sys/class/net/%s/device/driver", profile->usbnet_adapter); + n = readlink(pl->linkname, pl->filename, sizeof(pl->filename)); + pl->filename[n] = '\0'; + while (pl->filename[n] != '/') n--; + profile->driver_name = strdup(&pl->filename[n + 1]); + +//2021-03-15 zhangkaibo@fibocom.com changed begin for oa 20210311037 + fibo_get_driver_info(profile, &profile->rmnet_info); + if (profile->rmnet_info.size) { + profile->qmap_mode = profile->rmnet_info.qmap_mode; + if (profile->qmap_mode) { + int offset_id = profile->pdp - 1; + + if (profile->qmap_mode == 1) + offset_id = 0; + profile->muxid = profile->rmnet_info.mux_id[offset_id]; + profile->qmapnet_adapter = strdup( profile->rmnet_info.ifname[offset_id]); + profile->qmap_size = profile->rmnet_info.rx_urb_size; + profile->qmap_version = profile->rmnet_info.qmap_version; + } + + goto _out; + } +//2021-03-15 zhangkaibo@fibocom.com changed end for oa 20210311037 + + if (qmidev_is_pciemhi(profile->qmichannel)) { + profile->qmap_mode = 1; + + if (profile->muxid == 0 || profile->muxid == 0x81) + { + profile->muxid = 0x81; + } + else + { + if (profile->muxid < 0x80) + profile->muxid += 0x81; + profile->qmap_mode = 2; + } + + profile->qmapnet_adapter = strdup(profile->usbnet_adapter); + goto _final_process; + } + + snprintf(pl->filename, sizeof(pl->filename), "/sys/class/net/%s/qmap_num", + profile->usbnet_adapter); + +//2021-01-27 willa.liu@fibocom.com changed begin for support mantis 0068849 + if (access(pl->filename, F_OK) == 0) { + dbg_time("access %s", pl->filename); + if (errno != ENOENT) { + dbg_time("fail to access %s, errno: %d (%s)", pl->filename, errno, + strerror(errno)); + goto _out; + } +//2021-02-01 willa.liu@fibocom.com changed begin for support mantis 0069837 +/* + snprintf(pl->filename, sizeof(pl->filename), + "/sys/module/%s/parameters/qmap_num", profile->driver_name); + if (access(pl->filename, R_OK)) { + if (errno != ENOENT) { + dbg_time("fail to access %s, errno: %d (%s)", pl->filename, + errno, strerror(errno)); + goto _out; + } + + snprintf( + pl->filename, sizeof(pl->filename), + "/sys/class/net/%s/device/driver/module/parameters/qmap_num", + profile->usbnet_adapter); + if (access(pl->filename, R_OK)) { + if (errno != ENOENT) { + dbg_time("fail to access %s, errno: %d (%s)", pl->filename, + errno, strerror(errno)); + goto _out; + } + } + } +*/ +//2021-02-01 willa.liu@fibocom.com changed end for support mantis 0069837 + } + else + { + snprintf(pl->filename, sizeof(pl->filename), "/sys/class/net/%s/qmap_mode", + profile->usbnet_adapter); + + if (access(pl->filename, F_OK) == 0) { + dbg_time("access %s", pl->filename); + if (errno != ENOENT) { + dbg_time("fail to access %s, errno: %d (%s)", pl->filename, errno, + strerror(errno)); + goto _out; + } + } + } + + if(!access(pl->filename, R_OK)) + { + n = fibo_fread(pl->filename, buf, sizeof(buf)); + if(n > 0) + { + profile->qmap_mode = atoi(buf); + if(profile->qmap_mode >= 1 && qmidev_is_pciemhi(profile->qmichannel)) + { + profile->muxid = + profile->pdp + 0x80; + sprintf(qmap_netcard, "%s.%d", profile->usbnet_adapter,profile->pdp); + profile->qmapnet_adapter = strdup(qmap_netcard); + } + if(qmidev_is_gobinet(profile->qmichannel) || qmidev_is_qmiwwan(profile->qmichannel)) + { + if(profile->qmap_mode > 1) + { + profile->muxid = + profile->pdp + 0x80; + sprintf(qmap_netcard, "%s.%d", profile->usbnet_adapter,profile->pdp); + profile->qmapnet_adapter = strdup(qmap_netcard); + } + if(profile->qmap_mode == 1) + { + profile->muxid = 0x81; + profile->qmapnet_adapter = strdup(profile->usbnet_adapter); + } + } + } + + + if (0) { + profile->qmap_mode = atoi(buf); + + if (profile->qmap_mode > 1 && qmidev_is_gobinet(profile->qmichannel)) { + profile->muxid = + profile->pdp + 0x80; // muxis is 0x8X for PDN-X + sprintf(qmap_netcard, "%s.%d", profile->usbnet_adapter,profile->pdp); + profile->qmapnet_adapter = strdup(qmap_netcard); + } + if (profile->qmap_mode >= 1 && !qmidev_is_gobinet(profile->qmichannel)) { + profile->muxid = + profile->pdp + 0x80; // muxis is 0x8X for PDN-X + sprintf(qmap_netcard, "%s.%d", profile->usbnet_adapter,profile->pdp); + profile->qmapnet_adapter = strdup(qmap_netcard); + } + if (profile->qmap_mode == 1 && qmidev_is_gobinet(profile->qmichannel)) { + profile->muxid = 0x81; + profile->qmapnet_adapter = strdup(profile->usbnet_adapter); +//2021-01-27 willa.liu@fibocom.com changed end for support mantis 0068849 + + } + } + } else if (qmidev_is_qmiwwan(profile->qmichannel)) { + snprintf(pl->filename, sizeof(pl->filename), "/sys/class/net/qmimux%d", + profile->pdp - 1); + if (access(pl->filename, R_OK)) { + if (errno != ENOENT) { + dbg_time("fail to access %s, errno: %d (%s)", pl->filename, + errno, strerror(errno)); + } + goto _out; + } + + // upstream Kernel Style QMAP qmi_wwan.c + snprintf(pl->filename, sizeof(pl->filename), + "/sys/class/net/%s/qmi/add_mux", profile->usbnet_adapter); + n = fibo_fread(pl->filename, buf, sizeof(buf)); + if (n >= 5) { + profile->qmap_mode = n / 5; // 0x81\n0x82\n0x83\n + if (profile->qmap_mode > 1) { + // PDN-X map to qmimux-X + profile->muxid = (buf[5 * (profile->pdp - 1) + 2] - '0') * 16 + + (buf[5 * (profile->pdp - 1) + 3] - '0'); + sprintf(qmap_netcard, "qmimux%d", profile->pdp - 1); + profile->qmapnet_adapter = strdup(qmap_netcard); + } else if (profile->qmap_mode == 1) { + profile->muxid = + (buf[5 * 0 + 2] - '0') * 16 + (buf[5 * 0 + 3] - '0'); + sprintf(qmap_netcard, "qmimux%d", 0); + profile->qmapnet_adapter = strdup(qmap_netcard); + } + } + } + +_out: + if (profile->qmap_mode) { + profile->qmap_size = 16 * 1024; + snprintf(pl->filename, sizeof(pl->filename), + "/sys/class/net/%s/qmap_size", profile->usbnet_adapter); + if (!access(pl->filename, R_OK)) { + size_t n; + char buf[32]; + n = fibo_fread(pl->filename, buf, sizeof(buf)); + if (n > 0) { + profile->qmap_size = atoi(buf); + } + } + } + +_final_process: + if (profile->qmap_mode) + dbg_time("qmap_mode = %d, muxid = 0x%02x, qmap_netcard = %s", + profile->qmap_mode, profile->muxid, profile->qmapnet_adapter); + + free(pl); + + return 0; +} + +int fibo_qmap_mode_set(PROFILE_T *profile) +{ + int n; + char buf[128]; + struct { + char filename[255 * 2]; + char linkname[255 * 2]; + } * pl; + + if (qmidev_is_pciemhi(profile->qmichannel)) + { + dbg_time("pcie mode exit fibo_qmap_mode_set "); + return 0; + } + + pl = (typeof(pl))malloc(sizeof(*pl)); + + snprintf(pl->linkname, sizeof(pl->linkname), + "/sys/class/net/%s/device/driver", profile->usbnet_adapter); + n = readlink(pl->linkname, pl->filename, sizeof(pl->filename)); + pl->filename[n] = '\0'; + while (pl->filename[n] != '/') n--; + profile->driver_name = strdup(&pl->filename[n + 1]); + + snprintf(pl->filename, sizeof(pl->filename), "/sys/class/net/%s/qmap_num", + profile->usbnet_adapter); + if (access(pl->filename, R_OK)) { + if (errno != ENOENT) { + dbg_time("fail to access %s, errno: %d (%s)", pl->filename, errno, + strerror(errno)); + goto _out; + } + + snprintf(pl->filename, sizeof(pl->filename), + "/sys/module/%s/parameters/qmap_mnum", profile->driver_name); + if (access(pl->filename, R_OK)) { + if (errno != ENOENT) { + dbg_time("fail to access %s, errno: %d (%s)", pl->filename, + errno, strerror(errno)); + goto _out; + } + + snprintf( + pl->filename, sizeof(pl->filename), + "/sys/class/net/%s/device/driver/module/parameters/qmap_num", + profile->usbnet_adapter); + if (access(pl->filename, R_OK)) { + if (errno != ENOENT) { + dbg_time("fail to access %s, errno: %d (%s)", pl->filename, + errno, strerror(errno)); + goto _out; + } + } + } + } + + if (!access(pl->filename, R_OK)) { + snprintf(buf, sizeof(buf), "%d", profile->pdpnum); + n = fibo_fwrite(pl->filename, buf, strlen(buf)); + } + +_out: + + free(pl); + + return 0; +} diff --git a/package/wwan/app/fibocom-dial/src/query_pcie_mode.c b/package/wwan/app/fibocom-dial/src/query_pcie_mode.c new file mode 100755 index 000000000..ff8a9da1e --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/query_pcie_mode.c @@ -0,0 +1,160 @@ +//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817 +#include "QMIThread.h" +#include "query_pcie_mode.h" +int speed_arr[] = { B115200, B19200, B9600, B4800, B2400, B1200, B300,// + B38400, B19200, B9600, B4800, B2400, B1200, B300, + }; +int name_arr[] = {115200, 19200, 9600, 4800, 2400, 1200, 300, + 38400, 19200, 9600, 4800, 2400, 1200, 300, + }; + +int get_pcie_mode_debug = 0; + +//2021-02-24 willa.liu@fibocom.com changed begin for support eipd SN-20210129001 +int get_private_gateway_debug = 1; +//2021-02-24 willa.liu@fibocom.com changed end for support eipd SN-20210129001 + +//static int xset1(int fd, struct termios *tio, const char *device) +int xset1(int fd, struct termios *tio, const char *device) +{ + int ret = tcsetattr(fd, TCSAFLUSH, tio); + + if (ret) { + printf("can't tcsetattr for %s", device); + } + return ret; +} + +// set raw tty mode +//static void xget1(int fd, struct termios *t, struct termios *oldt) +void xget1(int fd, struct termios *t, struct termios *oldt) +{ + tcgetattr(fd, oldt); + *t = *oldt; + cfmakeraw(t); +// t->c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN); +// t->c_iflag &= ~(BRKINT|IXON|ICRNL); +// t->c_oflag &= ~(ONLCR); +// t->c_cc[VMIN] = 1; +// t->c_cc[VTIME] = 0; +} + +//static int get_pcie_mode() +int get_pcie_mode() +//2021-03-24 willa.liu@fibocom.com changed end for support mantis 0071817 +{ + int i; + int fd; + int ret; + char buffer[409600] = {0}; + int rate; + char* sendbuffer; + int totallen = 0; + fd_set readfds; + struct timeval timeout; + struct termios tio0, tiosfd, tio; + + int timeoutVal = 5; + + char *dev = "/dev/ttyUSB1"; //The port under Linux is operated by opening the device file + rate = 115200; + sendbuffer = "at+gtpcie=3"; + printf ( "dev: %s\nrate:%d\nsendbuffer:%s\n", dev,rate,sendbuffer); + + fd = open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (fd < 0) + goto ERR; + fcntl(fd, F_SETFL, O_RDWR); + + // put device to "raw mode" + xget1(fd, &tio, &tiosfd); + // set device speed + for ( i = 0;i < sizeof ( speed_arr ) / sizeof ( int );i++ ) + { + if ( rate == name_arr[i] ) //Judge if the pass is equal to the pass + { + break; + } + } + + if(i >= sizeof ( speed_arr ) / sizeof ( int )) + { + printf("bound rate set failed\n"); + goto ERR; + } + + cfsetspeed(&tio, speed_arr[i]); + if (xset1(fd, &tio, dev)) + goto ERR; + + tcflush ( fd, TCIOFLUSH ); + + sprintf(buffer, "%s\r", sendbuffer); + ret = write ( fd, buffer, strlen(buffer) ); + if(ret < 0) + { + printf ( "write failed\n" ); + goto ERR; + } + if(get_pcie_mode_debug)printf("write %d\n", ret); + + FD_ZERO ( &readfds ); + FD_SET ( fd, &readfds ); + + while(1) + { + timeout.tv_sec = timeoutVal; + timeout.tv_usec = 0; + + ret = select ( fd+1, &readfds, ( fd_set * ) 0, ( fd_set * ) 0, &timeout ); + if(ret > 0) + { + ret = read ( fd, buffer+totallen, sizeof(buffer)-totallen-1 ); + if(ret < 0) + { + printf ( "read failed\n" ); + goto ERR; + } + + if(ret == 0) + { + goto ERR; + } + + totallen += ret; + buffer[totallen] = '\0'; + if(get_pcie_mode_debug)printf("read %d(%s)\n", ret, &buffer[totallen-ret]); + if(totallen == sizeof(buffer)-1) + break; + + if(strstr(buffer,"\nOK") || strstr(buffer,"\nERROR") + || strstr(buffer,"\n+CME ERROR:") || strstr(buffer,"\n+CMS ERROR:")) + { + if(get_pcie_mode_debug)printf("match OK/ERROR"); + if(get_pcie_mode_debug)printf("%s", buffer); + break; + } + + } + else + { + printf ( "select timeout\n" ); + goto ERR; + } + + } + + tcsetattr(fd, TCSAFLUSH, &tiosfd); + //printf("buffer:\n %s\n", buffer); + printf("%s\n", buffer); + if(strstr(buffer,"\nERROR") || strstr(buffer,"\n+CME ERROR:") || strstr(buffer,"\n+CMS ERROR:")) + goto ERR; + + close ( fd ); + return 0; + ERR: + if(fd > 0) + close(fd); + return -1; +} + diff --git a/package/wwan/app/fibocom-dial/src/query_pcie_mode.h b/package/wwan/app/fibocom-dial/src/query_pcie_mode.h new file mode 100755 index 000000000..5f089864f --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/query_pcie_mode.h @@ -0,0 +1,17 @@ +#ifndef __QUERY_PCIE_MODE__ +#define __QUERY_PCIE_MODE__ + +extern int speed_arr[14]; +extern int name_arr[14]; + +extern int get_pcie_mode_debug; + +extern int get_private_gateway_debug; + +extern int xset1(int fd, struct termios *tio, const char *device); + +// set raw tty mode +extern void xget1(int fd, struct termios *t, struct termios *oldt); +extern int get_pcie_mode(); + +#endif diff --git a/package/wwan/app/fibocom-dial/src/udhcpc.c b/package/wwan/app/fibocom-dial/src/udhcpc.c new file mode 100755 index 000000000..e9c6df514 --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/udhcpc.c @@ -0,0 +1,289 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "QMIThread.h" +#include "util.h" + +static int dibbler_client_alive = 0; + +static int fibo_system(const char *shell_cmd) +{ + int ret = 0; + dbg_time("%s", shell_cmd); + ret = system(shell_cmd); + if (ret) { + // dbg_time("Fail to system(\"%s\") = %d, errno: %d (%s)", shell_cmd, + // ret, errno, strerror(errno)); + } + return ret; +} + +static void fibo_set_mtu(const char *ifname, int ifru_mtu) +{ + int inet_sock; + struct ifreq ifr; + + inet_sock = socket(AF_INET, SOCK_DGRAM, 0); + + if (inet_sock > 0) { + strcpy(ifr.ifr_name, ifname); + + if (!ioctl(inet_sock, SIOCGIFMTU, &ifr)) { + if (ifr.ifr_ifru.ifru_mtu != ifru_mtu) { + dbg_time("change mtu %d -> %d", ifr.ifr_ifru.ifru_mtu, + ifru_mtu); + ifr.ifr_ifru.ifru_mtu = ifru_mtu; + ioctl(inet_sock, SIOCSIFMTU, &ifr); + } + } + + close(inet_sock); + } +} + +static void *udhcpc_thread_function(void *arg) +{ + FILE *udhcpc_fp; + char *udhcpc_cmd = (char *)arg; + + if (udhcpc_cmd == NULL) + return NULL; + + dbg_time("%s", udhcpc_cmd); + udhcpc_fp = popen(udhcpc_cmd, "r"); + free(udhcpc_cmd); + if (udhcpc_fp) { + char buf[0xff]; + + buf[sizeof(buf) - 1] = '\0'; + while ((fgets(buf, sizeof(buf) - 1, udhcpc_fp)) != NULL) { + if ((strlen(buf) > 1) && (buf[strlen(buf) - 1] == '\n')) + buf[strlen(buf) - 1] = '\0'; + dbg_time("%s", buf); + } + + pclose(udhcpc_fp); + } + + return NULL; +} + +void fibo_set_driver_link_state(PROFILE_T *profile, int link_state) +{ + char link_file[128]; + int fd; + int new_state = 0; + dbg_time("enter %s ", __func__); + + snprintf(link_file, sizeof(link_file), "/sys/class/net/%s/link_state", + profile->usbnet_adapter); + fd = open(link_file, O_RDWR | O_NONBLOCK | O_NOCTTY); + if (fd == -1) { + if (errno != ENOENT) + dbg_time("Fail to access %s, errno: %d (%s)", link_file, errno, + strerror(errno)); + return; + } + + if (profile->qmap_mode <= 1) + new_state = !!link_state; + else { + // 0x80 means link off this pdp + new_state = (link_state ? 0x00 : 0x80) + profile->pdp; + } + + snprintf(link_file, sizeof(link_file), "%d\n", new_state); + write(fd, link_file, sizeof(link_file)); + + if (link_state == 0 && profile->qmap_mode > 1) { + size_t rc; + + lseek(fd, 0, SEEK_SET); + rc = read(fd, link_file, sizeof(link_file)); + if (rc > 1 && (!strcasecmp(link_file, "0\n") || + !strcasecmp(link_file, "0x0\n"))) { + // snprintf(link_file, sizeof(link_file), "busybox ifconfig %s down", + // profile->usbnet_adapter); + // fibo_system(link_file); + } + } + + close(fd); +} + +int fibo_raw_ip_mode_check(const char *ifname) +{ + int fd; + char raw_ip[128]; + char shell_cmd[128]; + char mode[2] = "X"; + int mode_change = 0; + + snprintf(raw_ip, sizeof(raw_ip), "/sys/class/net/%s/qmi/raw_ip", ifname); + if (access(raw_ip, F_OK)) + return 0; + + fd = open(raw_ip, O_RDWR | O_NONBLOCK | O_NOCTTY); + if (fd < 0) { + dbg_time("%s %d fail to open(%s), errno:%d (%s)", __FILE__, __LINE__, + raw_ip, errno, strerror(errno)); + return 0; + } + + read(fd, mode, 2); + if (mode[0] == '0' || mode[0] == 'N') { + snprintf(shell_cmd, sizeof(shell_cmd), "busybox ifconfig %s down", ifname); + fibo_system(shell_cmd); + dbg_time("echo Y > /sys/class/net/%s/qmi/raw_ip", ifname); + mode[0] = 'Y'; + write(fd, mode, 2); + mode_change = 1; + snprintf(shell_cmd, sizeof(shell_cmd), "busybox ifconfig %s up", ifname); + fibo_system(shell_cmd); + } + + close(fd); + return mode_change; +} + +void udhcpc_start(PROFILE_T *profile) +{ + char *ifname = profile->usbnet_adapter; + char shell_cmd[128]; + + fibo_set_driver_link_state(profile, 1); + if (profile->qmapnet_adapter) { + ifname = profile->qmapnet_adapter; + } + dbg_time("1 %s", profile->qmichannel); + if (qmidev_is_qmiwwan(profile->qmichannel)) { + dbg_time("2 %s", ifname); + fibo_raw_ip_mode_check(ifname); + } + + if (profile->rawIP && profile->ipv4.Address && profile->ipv4.Mtu) { + fibo_set_mtu(ifname, (profile->ipv4.Mtu)); + } + + fibo_system("echo 1 > /sys/module/fibo_mhi/parameters/macaddr_check"); + +//begin modified by zhangkaibo fix ipv6 dial process flow. mantis 0048789 20200605 +// if (strcmp(ifname, profile->usbnet_adapter)) { +// snprintf(shell_cmd, sizeof(shell_cmd) - 1, "busybox ifconfig %s up", +// profile->usbnet_adapter); +// fibo_system(shell_cmd); +// } +//begin modified by zhangkaibo fix ipv6 dial process flow. mantis 0048789 20200605 + // For IPv6, down & up will send protocol packets, and that's needed. + if (profile->ipv6_flag) { + snprintf(shell_cmd, sizeof(shell_cmd) - 1, "busybox ifconfig %s down", ifname); + fibo_system(shell_cmd); + } + + snprintf(shell_cmd, sizeof(shell_cmd) - 1, "busybox ifconfig %s up", ifname); + fibo_system(shell_cmd); + + //begin modified by zhangming Added NOARP and Multilcast on flag bit commands. mantis 0050106 20200713 + snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ip link set %s arp off multicast on", ifname); + fibo_system(shell_cmd); + //begin modified by zhangming Added NOARP and Multilcast on flag bit commands. mantis 0050106 20200713 + //Modified unicom dual stack dialing unsuccessful problem + + // for bridge mode, only one public IP, so do udhcpc manually + if (fibo_bridge_mode_detect(profile)) { + return; + } + + /* Do DHCP using busybox tools */ + { + char udhcpc_cmd[128]; + pthread_attr_t udhcpc_thread_attr; + pthread_t udhcpc_thread_id; + + pthread_attr_init(&udhcpc_thread_attr); + pthread_attr_setdetachstate(&udhcpc_thread_attr, + PTHREAD_CREATE_DETACHED); + + if (profile->ipv4.Address) { + if (access("/usr/share/udhcpc/default.script", X_OK)) { + dbg_time( + "Fail to access /usr/share/udhcpc/default.script, " + "errno: %d (%s)", + errno, strerror(errno)); + } + + //-f,--foreground Run in foreground + //-b,--background Background if lease is not obtained + //-n,--now Exit if lease is not obtained + //-q,--quit Exit after obtaining lease + //-t,--retries N Send up to N discover packets (default 3) + snprintf(udhcpc_cmd, sizeof(udhcpc_cmd), + "busybox udhcpc -f -n -q -t 5 -i %s", ifname); + + if (!access("/lib/netifd/dhcp.script", X_OK) && + !access("/sbin/ifup", X_OK) && + !access("/sbin/ifstatus", X_OK)) { + dbg_time("you are use OpenWrt?"); + dbg_time("should not calling udhcpc manually?"); + dbg_time("should modify /etc/config/network as below?"); + dbg_time("config interface wan"); + dbg_time("\toption ifname %s", ifname); + dbg_time("\toption proto dhcp"); + dbg_time( + "should use \"/sbin/ifstaus wan\" to check %s 's status?", + ifname); + } + + pthread_create(&udhcpc_thread_id, NULL, udhcpc_thread_function, + (void *)strdup(udhcpc_cmd)); + sleep(1); + } + + if (profile->ipv6.Address[0] && profile->ipv6.PrefixLengthIPAddr) { + // module do not support DHCPv6, only support 'Router Solicit' + // and it seem if enable /proc/sys/net/ipv6/conf/all/forwarding, + // Kernel do not send RS + const char *forward_file = "/proc/sys/net/ipv6/conf/all/forwarding"; + int forward_fd = open(forward_file, O_RDONLY); + if (forward_fd > 0) { + char forward_state[2]; + read(forward_fd, forward_state, 2); + if (forward_state[0] == '1') { + dbg_time( + "%s enabled, kernel maybe donot send 'Router Solicit'", + forward_file); + } + close(forward_fd); + } + } + } +} + +void udhcpc_stop(PROFILE_T *profile) +{ + char *ifname = profile->usbnet_adapter; + char shell_cmd[128]; + char reset_ip[128]; + dbg_time("enter %s ", __func__); + + if (profile->qmapnet_adapter) { + ifname = profile->qmapnet_adapter; + } + + if (dibbler_client_alive) { + system("killall dibbler-client"); + dibbler_client_alive = 0; + } + //snprintf(shell_cmd, sizeof(shell_cmd) - 1, "busybox ifconfig %s down", + // profile->usbnet_adapter); + //fibo_system(shell_cmd); + snprintf(shell_cmd, sizeof(shell_cmd) - 1, "busybox ifconfig %s down", ifname); + fibo_system(shell_cmd); + snprintf(reset_ip, sizeof(reset_ip) - 1, "busybox ifconfig %s 0.0.0.0", ifname); + fibo_system(reset_ip); +} diff --git a/package/wwan/app/fibocom-dial/src/udhcpc_netlink.c b/package/wwan/app/fibocom-dial/src/udhcpc_netlink.c new file mode 100755 index 000000000..fddf16639 --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/udhcpc_netlink.c @@ -0,0 +1,421 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libmnl/ifutils.h" +#include "libmnl/dhcp/dhcp.h" +#include "util.h" +#include "QMIThread.h" + +static int fibo_system(const char *shell_cmd) +{ + int ret = 0; + dbg_time("%s", shell_cmd); + ret = system(shell_cmd); + if (ret) { + // dbg_time("Fail to system(\"%s\") = %d, errno: %d (%s)", shell_cmd, + // ret, errno, strerror(errno)); + } + return ret; +} + +int fibo_raw_ip_mode_check(const char *ifname) +{ + int fd; + char raw_ip[128]; + char mode[2] = "X"; + int mode_change = 0; + + snprintf(raw_ip, sizeof(raw_ip), "/sys/class/net/%s/qmi/raw_ip", ifname); + if (access(raw_ip, F_OK)) + return 0; + + fd = open(raw_ip, O_RDWR | O_NONBLOCK | O_NOCTTY); + if (fd < 0) + { + dbg_time("%s %d fail to open(%s), errno:%d (%s)", __FILE__, __LINE__, raw_ip, errno, strerror(errno)); + return 0; + } + + read(fd, mode, 2); + if (mode[0] == '0' || mode[0] == 'N') + { + if_link_down(ifname); + dbg_time("echo Y > /sys/class/net/%s/qmi/raw_ip", ifname); + mode[0] = 'Y'; + write(fd, mode, 2); + mode_change = 1; + if_link_up(ifname); + } + + close(fd); + return mode_change; +} + +static void fibo_set_driver_link_state(PROFILE_T *profile, int link_state) +{ + char link_file[128]; + int fd; + int new_state = 0; + dbg_time("enter %s ", __func__); + + snprintf(link_file, sizeof(link_file), "/sys/class/net/%s/link_state", profile->usbnet_adapter); + fd = open(link_file, O_RDWR | O_NONBLOCK | O_NOCTTY); + if (fd == -1) + { + if (errno != ENOENT) + dbg_time("Fail to access %s, errno: %d (%s)", link_file, errno, strerror(errno)); + return; + } + + if (profile->qmap_mode <= 1) + new_state = !!link_state; + else + { + //0x80 means link off this pdp + new_state = (link_state ? 0x00 : 0x80) + profile->pdp; + } + + snprintf(link_file, sizeof(link_file), "%d\n", new_state); + write(fd, link_file, sizeof(link_file)); + + if (link_state == 0 && profile->qmap_mode > 1) + { + size_t rc; + + lseek(fd, 0, SEEK_SET); + rc = read(fd, link_file, sizeof(link_file)); + if (rc > 1 && (!strcasecmp(link_file, "0\n") || !strcasecmp(link_file, "0x0\n"))) + { + // if_link_down(profile->usbnet_adapter); + } + } + + close(fd); +} + +void udhcpc_start(PROFILE_T *profile) +{ +//2021-02-01 willa.liu@fibocom.com changed begin for support mantis 0069837 + char *ifname = profile->usbnet_adapter; + char shell_cmd[512]; + + fibo_set_driver_link_state(profile, 1); + fibo_raw_ip_mode_check(ifname); + + if (profile->qmapnet_adapter) + { + ifname = profile->qmapnet_adapter; + } + if (profile->rawIP && profile->ipv4.Address && profile->ipv4.Mtu) + { + if_set_mtu(ifname, (profile->ipv4.Mtu)); + } + + if (strcmp(ifname, profile->usbnet_adapter)) + { + //if_link_up(profile->usbnet_adapter); + snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ifconfig %s up", profile->usbnet_adapter); + fibo_system(shell_cmd); + } +//2021-02-01 willa.liu@fibocom.com changed begin for support mantis 0069837 + if_link_up(ifname); + +#if 1 //for bridge mode, only one public IP, so do udhcpc manually + if (fibo_bridge_mode_detect(profile)) + { + return; + } +#endif + // if use DHCP(should make with ${DHCP} src files) + // do_dhcp(ifname); + // return 0; + /* IPv4 Addr Info */ + if (profile->ipv4.Address) + { + dbg_time("IPv4 MTU: %d", profile->ipv4.Mtu); + dbg_time("IPv4 Address: %s", ipaddr_to_string_v4(ntohl(profile->ipv4.Address))); + dbg_time("IPv4 Netmask: %d", mask_to_prefix_v4(ntohl(profile->ipv4.SubnetMask))); + dbg_time("IPv4 Gateway: %s", ipaddr_to_string_v4(ntohl(profile->ipv4.Gateway))); + dbg_time("IPv4 DNS1: %s", ipaddr_to_string_v4(ntohl(profile->ipv4.DnsPrimary))); + dbg_time("IPv4 DNS2: %s", ipaddr_to_string_v4(ntohl(profile->ipv4.DnsSecondary))); + if_set_network_v4(ifname, ntohl(profile->ipv4.Address), + mask_to_prefix_v4(profile->ipv4.SubnetMask), + ntohl(profile->ipv4.Gateway), + ntohl(profile->ipv4.DnsPrimary), + ntohl(profile->ipv4.DnsSecondary)); + } + else + { + dbg_time("The IPv4 Address in profile is NULL"); + } + + if (profile->ipv6.Address && (profile->ipv6.PrefixLengthIPAddr != 0)) + { + //module do not support DHCPv6, only support 'Router Solicit' + //and it seem if enable /proc/sys/net/ipv6/conf/all/forwarding, Kernel do not send RS + const char *forward_file = "/proc/sys/net/ipv6/conf/all/forwarding"; + int forward_fd = open(forward_file, O_RDONLY); + if (forward_fd > 0) + { + char forward_state[2]; + read(forward_fd, forward_state, 2); + if (forward_state[0] == '1') + { + dbg_time("%s enabled, kernel maybe donot send 'Router Solicit'", forward_file); + } + close(forward_fd); + } + + dbg_time("IPv6 MTU: %d", profile->ipv6.Mtu); + dbg_time("IPv6 Address: %s", ipaddr_to_string_v6(profile->ipv6.Address)); + dbg_time("IPv6 PrefixLengthIPAddr: %d", profile->ipv6.PrefixLengthIPAddr); + dbg_time("IPv6 Gateway: %s", ipaddr_to_string_v6(profile->ipv6.Gateway)); + dbg_time("IPv6 DNS1: %s", ipaddr_to_string_v6(profile->ipv6.DnsPrimary)); + dbg_time("IPv6 DNS2: %s", ipaddr_to_string_v6(profile->ipv6.DnsSecondary)); + if_set_network_v6(ifname, profile->ipv6.Address, profile->ipv6.PrefixLengthIPAddr, + profile->ipv6.Gateway, profile->ipv6.DnsPrimary, profile->ipv6.DnsSecondary); + } + else + { + dbg_time("The IPv6 Address in profile is NULL"); + } +} + +void udhcpc_stop(PROFILE_T *profile) +{ + char *ifname = profile->usbnet_adapter; + dbg_time("enter %s ", __func__); + + fibo_set_driver_link_state(profile, 0); + + if (profile->qmapnet_adapter) + { + ifname = profile->qmapnet_adapter; + } + + if_flush_v4_addr(ifname); + if_flush_v6_addr(ifname); + if_link_down(ifname); +} + +static void fibo_set_mtu(const char *ifname, int ifru_mtu) { + int inet_sock; + struct ifreq ifr; + + inet_sock = socket(AF_INET, SOCK_DGRAM, 0); + + if (inet_sock > 0) { + strcpy(ifr.ifr_name, ifname); + + if (!ioctl(inet_sock, SIOCGIFMTU, &ifr)) { + if (ifr.ifr_ifru.ifru_mtu != ifru_mtu) { + dbg_time("change mtu %d -> %d", ifr.ifr_ifru.ifru_mtu , ifru_mtu); + ifr.ifr_ifru.ifru_mtu = ifru_mtu; + ioctl(inet_sock, SIOCSIFMTU, &ifr); + } + } + + close(inet_sock); + } +} + +static void* udhcpc_thread_function(void* arg) { + FILE * udhcpc_fp; + char *udhcpc_cmd = (char *)arg; + + if (udhcpc_cmd == NULL) + return NULL; + + dbg_time("%s", udhcpc_cmd); + udhcpc_fp = popen(udhcpc_cmd, "r"); + free(udhcpc_cmd); + if (udhcpc_fp) { + char buf[0xff]; + + buf[sizeof(buf)-1] = '\0'; + while((fgets(buf, sizeof(buf)-1, udhcpc_fp)) != NULL) { + if ((strlen(buf) > 1) && (buf[strlen(buf) - 1] == '\n')) + buf[strlen(buf) - 1] = '\0'; + dbg_time("%s", buf); + } + + pclose(udhcpc_fp); + } + + return NULL; +} + +void udhcpc_start_pcie(PROFILE_T *profile) { + char *ifname = profile->usbnet_adapter; + char sub_intf_name[100] = {0}; + int intf_id = 0; + char shell_cmd[512]; + dbg_time("enter %s ", __func__); + + if (profile->qmapnet_adapter) { + ifname = profile->qmapnet_adapter; + } + + if (profile->muxid > 0x81) + { + intf_id = profile->muxid - 0x81; + snprintf(sub_intf_name, sizeof(sub_intf_name) - 1, "%s.%d", ifname, intf_id); + } + + if (profile->rawIP && profile->ipv4.Address && profile->ipv4.Mtu) { + fibo_set_mtu(ifname, (profile->ipv4.Mtu)); + } + + fibo_system("echo 1 > /sys/module/fibo_mhi/parameters/macaddr_check"); + + if (strcmp(ifname, profile->usbnet_adapter)) { + snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ifconfig %s up", profile->usbnet_adapter); + fibo_system(shell_cmd); + } + + // For IPv6, down & up will send protocol packets, and that's needed. + if (profile->ipv6_flag && profile->muxid <= 0x81) { + snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ifconfig %s down", ifname); + fibo_system(shell_cmd); + } + + snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ifconfig %s up", ifname); + fibo_system(shell_cmd); + + //for bridge mode, only one public IP, so do udhcpc manually + if (fibo_bridge_mode_detect(profile)) { + return; + } + +/* Do DHCP using busybox tools */ + { + char udhcpc_cmd[128]; + pthread_attr_t udhcpc_thread_attr; + pthread_t udhcpc_thread_id; + + pthread_attr_init(&udhcpc_thread_attr); + pthread_attr_setdetachstate(&udhcpc_thread_attr, PTHREAD_CREATE_DETACHED); + + if (profile->ipv4.Address) + { + char v4add_str[32] = {0}; + char v4gw_str[32] = {0}; + char v4_netmask_str[32] = {0}; + uint32_t Address = ntohl(profile->ipv4.Address); + uint32_t Gateway = ntohl(profile->ipv4.Gateway); + uint32_t SubnetMask = ntohl(profile->ipv4.SubnetMask); + inet_ntop(AF_INET, &Address, v4add_str, sizeof(v4add_str)); + inet_ntop(AF_INET, &Gateway, v4gw_str, sizeof(v4gw_str)); + inet_ntop(AF_INET, &SubnetMask, v4_netmask_str, sizeof(v4_netmask_str)); + + if (profile->muxid == 0x81) + { + snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ifconfig %s %s netmask %s", ifname, v4add_str, v4_netmask_str); + fibo_system(shell_cmd); + + snprintf(shell_cmd, sizeof(shell_cmd) - 1, "route add default gw %s dev %s", v4gw_str, ifname); + fibo_system(shell_cmd); + } + else if (profile->muxid > 0x81) + { + snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ip link add link %s name %s type vlan id %d", ifname, sub_intf_name, intf_id); + fibo_system(shell_cmd); + + snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ip link set %s up", ifname); + fibo_system(shell_cmd); + + snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ip link set %s up", sub_intf_name); + fibo_system(shell_cmd); + + snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ifconfig %s %s netmask %s", sub_intf_name, v4add_str, v4_netmask_str); + fibo_system(shell_cmd); + } + } + + if (profile->ipv6.PrefixLengthIPAddr) + { + //module do not support DHCPv6, only support 'Router Solicit' + //and it seem if enable /proc/sys/net/ipv6/conf/all/forwarding, Kernel do not send RS + const char *forward_file = "/proc/sys/net/ipv6/conf/all/forwarding"; + int forward_fd = open(forward_file, O_RDONLY); + if (forward_fd > 0) { + char forward_state[2]; + read(forward_fd, forward_state, 2); + if (forward_state[0] == '1') { + dbg_time("%s enabled, kernel maybe donot send 'Router Solicit'", forward_file); + } + close(forward_fd); + } + + { + char v6add_str[100] = {0}; + char v6gw_str[100] = {0}; + inet_ntop(AF_INET6, profile->ipv6.Address, v6add_str, sizeof(v6add_str)); + inet_ntop(AF_INET6, profile->ipv6.Gateway, v6gw_str, sizeof(v6gw_str)); + + if (profile->muxid == 0x81) + { + snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ifconfig %s add %s/%d", ifname, v6add_str, profile->ipv6.PrefixLengthIPAddr); + fibo_system(shell_cmd); + + snprintf(shell_cmd, sizeof(shell_cmd) - 1, "route -A inet6 add ::/0 gw %s dev %s", v6gw_str, ifname); + fibo_system(shell_cmd); + } + else if (profile->muxid > 0x81) + { + snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ip link add link %s name %s type vlan id %d", ifname, sub_intf_name, intf_id); + fibo_system(shell_cmd); + + snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ip link set %s up", ifname); + fibo_system(shell_cmd); + + snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ip link set %s up", sub_intf_name); + fibo_system(shell_cmd); + + snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ifconfig %s add %s/%d", sub_intf_name, v6add_str, profile->ipv6.PrefixLengthIPAddr); + fibo_system(shell_cmd); + /* start 2021-01-21 add by haopengfei to fix mantis 69056 */ + snprintf(shell_cmd, sizeof(shell_cmd) - 1, "route -A inet6 add ::/0 gw %s dev %s", v6gw_str, sub_intf_name); + fibo_system(shell_cmd); + /* end 2021-01-21 add by haopengfei to fix mantis 69056 */ + } + } + + } + } +} + +void udhcpc_stop_pcie(PROFILE_T *profile) { + char *ifname = profile->usbnet_adapter; + char shell_cmd[128]; + char reset_ip[128]; + dbg_time("enter %s ", __func__); + + if (profile->qmapnet_adapter) { + ifname = profile->qmapnet_adapter; + } + + if (profile->muxid == 0x81) + { + snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ifconfig %s down", ifname); + fibo_system(shell_cmd); + snprintf(reset_ip, sizeof(reset_ip) - 1, "ifconfig %s 0.0.0.0", ifname); + fibo_system(reset_ip); + } + else if (profile->muxid > 0x81) + { + char sub_intf_name[100]; + int intf_id = profile->muxid - 0x81; + snprintf(sub_intf_name, sizeof(sub_intf_name) - 1, "%s.%d", ifname, intf_id); + + snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ip link del link dev %s", sub_intf_name); + fibo_system(shell_cmd); + } +} + diff --git a/package/wwan/app/fibocom-dial/src/util.c b/package/wwan/app/fibocom-dial/src/util.c new file mode 100755 index 000000000..ecd208601 --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/util.c @@ -0,0 +1,142 @@ +#include + +#include "QMIThread.h" + +#if defined(__STDC__) +#include +#define __V(x) x +#else +#include +#define __V(x) (va_alist) va_dcl +#define const +#define volatile +#endif + +#include + +#define is_bigendian() ((*(char *)&i) == 0) +FILE *logfilefp = NULL; +static pthread_mutex_t printfMutex = PTHREAD_MUTEX_INITIALIZER; +static char line[1024]; +const int i = 1; + +// defined in atchannel.c +static void setTimespecRelative(struct timespec *p_ts, long long msec) +{ + struct timeval tv; + + gettimeofday(&tv, (struct timezone *)NULL); + + /* what's really funny about this is that I know + pthread_cond_timedwait just turns around and makes this + a relative time again */ + p_ts->tv_sec = tv.tv_sec + (msec / 1000); + p_ts->tv_nsec = (tv.tv_usec + (msec % 1000) * 1000L) * 1000L; +} + +int pthread_cond_timeout_np(pthread_cond_t *cond, pthread_mutex_t *mutex, + unsigned msecs) +{ + if (msecs != 0) { + struct timespec ts; + setTimespecRelative(&ts, msecs); + return pthread_cond_timedwait(cond, mutex, &ts); + } else { + return pthread_cond_wait(cond, mutex); + } +} + +static const char *get_time(void) +{ + static char time_buf[50]; + struct timeval tv; + time_t time; + suseconds_t millitm; + struct tm *ti; + + gettimeofday(&tv, NULL); + + time = tv.tv_sec; + millitm = (tv.tv_usec + 500) / 1000; + + if (millitm == 1000) { + ++time; + millitm = 0; + } + + ti = localtime(&time); + sprintf(time_buf, "[%02d-%02d_%02d:%02d:%02d:%03d]", ti->tm_mon + 1, + ti->tm_mday, ti->tm_hour, ti->tm_min, ti->tm_sec, (int)millitm); + return time_buf; +} + +void dbg_time(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + + pthread_mutex_lock(&printfMutex); + + snprintf(line, sizeof(line), "%s ", get_time()); + + vsnprintf(line + strlen(line), sizeof(line) - strlen(line), fmt, args); + fprintf(stdout, "%s\n", line); + + if (logfilefp) { + fprintf(logfilefp, "%s\n", line); + } + fflush(logfilefp); + pthread_mutex_unlock(&printfMutex); +} + +USHORT le16_to_cpu(USHORT v16) +{ + USHORT tmp = v16; + if (is_bigendian()) { + unsigned char *s = (unsigned char *)(&v16); + unsigned char *d = (unsigned char *)(&tmp); + d[0] = s[1]; + d[1] = s[0]; + } + return tmp; +} + +UINT le32_to_cpu(UINT v32) +{ + UINT tmp = v32; + if (is_bigendian()) { + unsigned char *s = (unsigned char *)(&v32); + unsigned char *d = (unsigned char *)(&tmp); + d[0] = s[3]; + d[1] = s[2]; + d[2] = s[1]; + d[3] = s[0]; + } + return tmp; +} + +USHORT cpu_to_le16(USHORT v16) +{ + USHORT tmp = v16; + if (is_bigendian()) { + unsigned char *s = (unsigned char *)(&v16); + unsigned char *d = (unsigned char *)(&tmp); + d[0] = s[1]; + d[1] = s[0]; + } + return tmp; +} + +UINT cpu_to_le32(UINT v32) +{ + UINT tmp = v32; + if (is_bigendian()) { + unsigned char *s = (unsigned char *)(&v32); + unsigned char *d = (unsigned char *)(&tmp); + d[0] = s[3]; + d[1] = s[2]; + d[2] = s[1]; + d[3] = s[0]; + } + return tmp; +} diff --git a/package/wwan/app/fibocom-dial/src/util.h b/package/wwan/app/fibocom-dial/src/util.h new file mode 100755 index 000000000..1dbaf9992 --- /dev/null +++ b/package/wwan/app/fibocom-dial/src/util.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _UTILS_H_ +#define _UTILS_H_ + +#include + +struct listnode { + struct listnode *next; + struct listnode *prev; +}; + +#define node_to_item(node, container, member) \ + (container *)(((char *)(node)) - offsetof(container, member)) + +#define list_declare(name) \ + struct listnode name = { \ + .next = &name, \ + .prev = &name, \ + } + +#define list_for_each(node, list) \ + for (node = (list)->next; node != (list); node = node->next) + +#define list_for_each_reverse(node, list) \ + for (node = (list)->prev; node != (list); node = node->prev) +void dbg_time(const char *fmt, ...); +void list_init(struct listnode *list); +void list_add_tail(struct listnode *list, struct listnode *item); +void list_add_head(struct listnode *head, struct listnode *item); +void list_remove(struct listnode *item); + +#define list_empty(list) ((list) == (list)->next) +#define list_head(list) ((list)->next) +#define list_tail(list) ((list)->prev) + +int epoll_register(int epoll_fd, int fd, unsigned int events); +int epoll_deregister(int epoll_fd, int fd); +#endif diff --git a/package/wwan/app/luci-proto-3x/Makefile b/package/wwan/app/luci-proto-3x/Makefile index ee45aba93..a9f098306 100644 --- a/package/wwan/app/luci-proto-3x/Makefile +++ b/package/wwan/app/luci-proto-3x/Makefile @@ -24,9 +24,9 @@ endef define Package/luci-proto-3x $(call Package/luci-proto-3x/Default) - SECTION:=net - CATEGORY:=ROOter - SUBMENU:=Protocols + SECTION:=luci + CATEGORY:=LuCI + SUBMENU:=5. Protocols TITLE:=Support for 3x endef diff --git a/package/wwan/driver/quectel_cm_5G/Makefile b/package/wwan/app/quectel_cm_5G/Makefile similarity index 100% rename from package/wwan/driver/quectel_cm_5G/Makefile rename to package/wwan/app/quectel_cm_5G/Makefile diff --git a/package/wwan/driver/quectel_cm_5G/files/dhcp b/package/wwan/app/quectel_cm_5G/files/dhcp similarity index 100% rename from package/wwan/driver/quectel_cm_5G/files/dhcp rename to package/wwan/app/quectel_cm_5G/files/dhcp diff --git a/package/wwan/driver/quectel_cm_5G/files/rmnet.script b/package/wwan/app/quectel_cm_5G/files/rmnet.script similarity index 100% rename from package/wwan/driver/quectel_cm_5G/files/rmnet.script rename to package/wwan/app/quectel_cm_5G/files/rmnet.script diff --git a/package/wwan/driver/quectel_cm_5G/files/rmnet.sh b/package/wwan/app/quectel_cm_5G/files/rmnet.sh similarity index 100% rename from package/wwan/driver/quectel_cm_5G/files/rmnet.sh rename to package/wwan/app/quectel_cm_5G/files/rmnet.sh diff --git a/package/wwan/driver/quectel_cm_5G/files/rmnet6.script b/package/wwan/app/quectel_cm_5G/files/rmnet6.script similarity index 100% rename from package/wwan/driver/quectel_cm_5G/files/rmnet6.script rename to package/wwan/app/quectel_cm_5G/files/rmnet6.script diff --git a/package/wwan/driver/quectel_cm_5G/files/rmnet6.sh b/package/wwan/app/quectel_cm_5G/files/rmnet6.sh similarity index 100% rename from package/wwan/driver/quectel_cm_5G/files/rmnet6.sh rename to package/wwan/app/quectel_cm_5G/files/rmnet6.sh diff --git a/package/wwan/driver/quectel_cm_5G/files/rmnet_init.sh b/package/wwan/app/quectel_cm_5G/files/rmnet_init.sh similarity index 100% rename from package/wwan/driver/quectel_cm_5G/files/rmnet_init.sh rename to package/wwan/app/quectel_cm_5G/files/rmnet_init.sh diff --git a/package/wwan/driver/quectel_cm_5G/src/CMakeLists.txt b/package/wwan/app/quectel_cm_5G/src/CMakeLists.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/CMakeLists.txt rename to package/wwan/app/quectel_cm_5G/src/CMakeLists.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/GobiNetCM.c b/package/wwan/app/quectel_cm_5G/src/GobiNetCM.c similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/GobiNetCM.c rename to package/wwan/app/quectel_cm_5G/src/GobiNetCM.c diff --git a/package/wwan/driver/quectel_cm_5G/src/MPQCTL.h b/package/wwan/app/quectel_cm_5G/src/MPQCTL.h similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/MPQCTL.h rename to package/wwan/app/quectel_cm_5G/src/MPQCTL.h diff --git a/package/wwan/driver/quectel_cm_5G/src/MPQMI.h b/package/wwan/app/quectel_cm_5G/src/MPQMI.h similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/MPQMI.h rename to package/wwan/app/quectel_cm_5G/src/MPQMI.h diff --git a/package/wwan/driver/quectel_cm_5G/src/MPQMUX.c b/package/wwan/app/quectel_cm_5G/src/MPQMUX.c similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/MPQMUX.c rename to package/wwan/app/quectel_cm_5G/src/MPQMUX.c diff --git a/package/wwan/driver/quectel_cm_5G/src/MPQMUX.h b/package/wwan/app/quectel_cm_5G/src/MPQMUX.h similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/MPQMUX.h rename to package/wwan/app/quectel_cm_5G/src/MPQMUX.h diff --git a/package/wwan/driver/quectel_cm_5G/src/Makefile b/package/wwan/app/quectel_cm_5G/src/Makefile similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/Makefile rename to package/wwan/app/quectel_cm_5G/src/Makefile diff --git a/package/wwan/driver/quectel_cm_5G/src/Makefile.am b/package/wwan/app/quectel_cm_5G/src/Makefile.am similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/Makefile.am rename to package/wwan/app/quectel_cm_5G/src/Makefile.am diff --git a/package/wwan/driver/quectel_cm_5G/src/NOTICE b/package/wwan/app/quectel_cm_5G/src/NOTICE similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/NOTICE rename to package/wwan/app/quectel_cm_5G/src/NOTICE diff --git a/package/wwan/driver/quectel_cm_5G/src/QMIThread.c b/package/wwan/app/quectel_cm_5G/src/QMIThread.c similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/QMIThread.c rename to package/wwan/app/quectel_cm_5G/src/QMIThread.c diff --git a/package/wwan/driver/quectel_cm_5G/src/QMIThread.h b/package/wwan/app/quectel_cm_5G/src/QMIThread.h similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/QMIThread.h rename to package/wwan/app/quectel_cm_5G/src/QMIThread.h diff --git a/package/wwan/driver/quectel_cm_5G/src/QmiWwanCM.c b/package/wwan/app/quectel_cm_5G/src/QmiWwanCM.c similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/QmiWwanCM.c rename to package/wwan/app/quectel_cm_5G/src/QmiWwanCM.c diff --git a/package/wwan/driver/quectel_cm_5G/src/ReleaseNote.txt b/package/wwan/app/quectel_cm_5G/src/ReleaseNote.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/ReleaseNote.txt rename to package/wwan/app/quectel_cm_5G/src/ReleaseNote.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/at_tok.c b/package/wwan/app/quectel_cm_5G/src/at_tok.c similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/at_tok.c rename to package/wwan/app/quectel_cm_5G/src/at_tok.c diff --git a/package/wwan/driver/quectel_cm_5G/src/at_tok.h b/package/wwan/app/quectel_cm_5G/src/at_tok.h similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/at_tok.h rename to package/wwan/app/quectel_cm_5G/src/at_tok.h diff --git a/package/wwan/driver/quectel_cm_5G/src/atc.c b/package/wwan/app/quectel_cm_5G/src/atc.c similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/atc.c rename to package/wwan/app/quectel_cm_5G/src/atc.c diff --git a/package/wwan/driver/quectel_cm_5G/src/atchannel.c b/package/wwan/app/quectel_cm_5G/src/atchannel.c similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/atchannel.c rename to package/wwan/app/quectel_cm_5G/src/atchannel.c diff --git a/package/wwan/driver/quectel_cm_5G/src/atchannel.h b/package/wwan/app/quectel_cm_5G/src/atchannel.h similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/atchannel.h rename to package/wwan/app/quectel_cm_5G/src/atchannel.h diff --git a/package/wwan/driver/quectel_cm_5G/src/configure.ac b/package/wwan/app/quectel_cm_5G/src/configure.ac similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/configure.ac rename to package/wwan/app/quectel_cm_5G/src/configure.ac diff --git a/package/wwan/app/quectel_cm_5G/src/default.script b/package/wwan/app/quectel_cm_5G/src/default.script new file mode 100644 index 000000000..26b95c1b9 --- /dev/null +++ b/package/wwan/app/quectel_cm_5G/src/default.script @@ -0,0 +1,63 @@ +#!/bin/sh +# Busybox udhcpc dispatcher script. Copyright (C) 2009 by Axel Beckert. +# +# Based on the busybox example scripts and the old udhcp source +# package default.* scripts. + +RESOLV_CONF="/etc/resolv.conf" + +case $1 in + bound|renew) + [ -n "$broadcast" ] && BROADCAST="broadcast $broadcast" + [ -n "$subnet" ] && NETMASK="netmask $subnet" + + /sbin/ifconfig $interface $ip $BROADCAST $NETMASK + + if [ -n "$router" ]; then + echo "$0: Resetting default routes" + while /sbin/route del default gw 0.0.0.0 dev $interface; do :; done + + metric=0 + for i in $router; do + /sbin/route add default gw $i dev $interface metric $metric + metric=$(($metric + 1)) + done + fi + + # Update resolver configuration file + R="" + [ -n "$domain" ] && R="domain $domain +" + for i in $dns; do + echo "$0: Adding DNS $i" + R="${R}nameserver $i +" + done + + if [ -x /sbin/resolvconf ]; then + echo -n "$R" | resolvconf -a "${interface}.udhcpc" + else + echo -n "$R" > "$RESOLV_CONF" + fi + ;; + + deconfig) + if [ -x /sbin/resolvconf ]; then + resolvconf -d "${interface}.udhcpc" + fi + /sbin/ifconfig $interface 0.0.0.0 + ;; + + leasefail) + echo "$0: Lease failed: $message" + ;; + + nak) + echo "$0: Received a NAK: $message" + ;; + + *) + echo "$0: Unknown udhcpc command: $1"; + exit 1; + ;; +esac diff --git a/package/wwan/driver/quectel_cm_5G/src/default.script_ip b/package/wwan/app/quectel_cm_5G/src/default.script_ip similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/default.script_ip rename to package/wwan/app/quectel_cm_5G/src/default.script_ip diff --git a/package/wwan/driver/quectel_cm_5G/src/device.c b/package/wwan/app/quectel_cm_5G/src/device.c similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/device.c rename to package/wwan/app/quectel_cm_5G/src/device.c diff --git a/package/wwan/driver/quectel_cm_5G/src/ethtool-copy.h b/package/wwan/app/quectel_cm_5G/src/ethtool-copy.h similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/ethtool-copy.h rename to package/wwan/app/quectel_cm_5G/src/ethtool-copy.h diff --git a/package/wwan/driver/quectel_cm_5G/src/log/cdc_mbim.txt b/package/wwan/app/quectel_cm_5G/src/log/cdc_mbim.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/log/cdc_mbim.txt rename to package/wwan/app/quectel_cm_5G/src/log/cdc_mbim.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/log/cdc_mbim_vlan.txt b/package/wwan/app/quectel_cm_5G/src/log/cdc_mbim_vlan.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/log/cdc_mbim_vlan.txt rename to package/wwan/app/quectel_cm_5G/src/log/cdc_mbim_vlan.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/log/ecm_ncm_rndis.txt b/package/wwan/app/quectel_cm_5G/src/log/ecm_ncm_rndis.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/log/ecm_ncm_rndis.txt rename to package/wwan/app/quectel_cm_5G/src/log/ecm_ncm_rndis.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/log/gobinet.txt b/package/wwan/app/quectel_cm_5G/src/log/gobinet.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/log/gobinet.txt rename to package/wwan/app/quectel_cm_5G/src/log/gobinet.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/log/gobinet_bridge.txt b/package/wwan/app/quectel_cm_5G/src/log/gobinet_bridge.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/log/gobinet_bridge.txt rename to package/wwan/app/quectel_cm_5G/src/log/gobinet_bridge.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/log/gobinet_qmap=1.txt b/package/wwan/app/quectel_cm_5G/src/log/gobinet_qmap=1.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/log/gobinet_qmap=1.txt rename to package/wwan/app/quectel_cm_5G/src/log/gobinet_qmap=1.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/log/gobinet_qmap=1_bridge.txt b/package/wwan/app/quectel_cm_5G/src/log/gobinet_qmap=1_bridge.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/log/gobinet_qmap=1_bridge.txt rename to package/wwan/app/quectel_cm_5G/src/log/gobinet_qmap=1_bridge.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/log/gobinet_qmap=4.txt b/package/wwan/app/quectel_cm_5G/src/log/gobinet_qmap=4.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/log/gobinet_qmap=4.txt rename to package/wwan/app/quectel_cm_5G/src/log/gobinet_qmap=4.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/log/gobinet_qmap=4_bridge.txt b/package/wwan/app/quectel_cm_5G/src/log/gobinet_qmap=4_bridge.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/log/gobinet_qmap=4_bridge.txt rename to package/wwan/app/quectel_cm_5G/src/log/gobinet_qmap=4_bridge.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/log/pcie_mhi_mbim.txt b/package/wwan/app/quectel_cm_5G/src/log/pcie_mhi_mbim.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/log/pcie_mhi_mbim.txt rename to package/wwan/app/quectel_cm_5G/src/log/pcie_mhi_mbim.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/log/pcie_mhi_mbim_qmap=4.txt b/package/wwan/app/quectel_cm_5G/src/log/pcie_mhi_mbim_qmap=4.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/log/pcie_mhi_mbim_qmap=4.txt rename to package/wwan/app/quectel_cm_5G/src/log/pcie_mhi_mbim_qmap=4.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/log/pcie_mhi_qmap=1.txt b/package/wwan/app/quectel_cm_5G/src/log/pcie_mhi_qmap=1.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/log/pcie_mhi_qmap=1.txt rename to package/wwan/app/quectel_cm_5G/src/log/pcie_mhi_qmap=1.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/log/pcie_mhi_qmap=1_bridge.txt b/package/wwan/app/quectel_cm_5G/src/log/pcie_mhi_qmap=1_bridge.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/log/pcie_mhi_qmap=1_bridge.txt rename to package/wwan/app/quectel_cm_5G/src/log/pcie_mhi_qmap=1_bridge.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/log/pcie_mhi_qmap=4.txt b/package/wwan/app/quectel_cm_5G/src/log/pcie_mhi_qmap=4.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/log/pcie_mhi_qmap=4.txt rename to package/wwan/app/quectel_cm_5G/src/log/pcie_mhi_qmap=4.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/log/pcie_mhi_qmap=4_bridge.txt b/package/wwan/app/quectel_cm_5G/src/log/pcie_mhi_qmap=4_bridge.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/log/pcie_mhi_qmap=4_bridge.txt rename to package/wwan/app/quectel_cm_5G/src/log/pcie_mhi_qmap=4_bridge.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/log/qmi_wwan_q.txt b/package/wwan/app/quectel_cm_5G/src/log/qmi_wwan_q.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/log/qmi_wwan_q.txt rename to package/wwan/app/quectel_cm_5G/src/log/qmi_wwan_q.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/log/qmi_wwan_q_bridge.txt b/package/wwan/app/quectel_cm_5G/src/log/qmi_wwan_q_bridge.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/log/qmi_wwan_q_bridge.txt rename to package/wwan/app/quectel_cm_5G/src/log/qmi_wwan_q_bridge.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/log/qmi_wwan_q_qmap=1.txt b/package/wwan/app/quectel_cm_5G/src/log/qmi_wwan_q_qmap=1.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/log/qmi_wwan_q_qmap=1.txt rename to package/wwan/app/quectel_cm_5G/src/log/qmi_wwan_q_qmap=1.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/log/qmi_wwan_q_qmap=1_bridge.txt b/package/wwan/app/quectel_cm_5G/src/log/qmi_wwan_q_qmap=1_bridge.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/log/qmi_wwan_q_qmap=1_bridge.txt rename to package/wwan/app/quectel_cm_5G/src/log/qmi_wwan_q_qmap=1_bridge.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/log/qmi_wwan_q_qmap=4.txt b/package/wwan/app/quectel_cm_5G/src/log/qmi_wwan_q_qmap=4.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/log/qmi_wwan_q_qmap=4.txt rename to package/wwan/app/quectel_cm_5G/src/log/qmi_wwan_q_qmap=4.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/log/qmi_wwan_q_qmap=4_bridge.txt b/package/wwan/app/quectel_cm_5G/src/log/qmi_wwan_q_qmap=4_bridge.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/log/qmi_wwan_q_qmap=4_bridge.txt rename to package/wwan/app/quectel_cm_5G/src/log/qmi_wwan_q_qmap=4_bridge.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/log/qmi_wwan_qmap=4.txt b/package/wwan/app/quectel_cm_5G/src/log/qmi_wwan_qmap=4.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/log/qmi_wwan_qmap=4.txt rename to package/wwan/app/quectel_cm_5G/src/log/qmi_wwan_qmap=4.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/log/usage_of_argument/6.txt b/package/wwan/app/quectel_cm_5G/src/log/usage_of_argument/6.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/log/usage_of_argument/6.txt rename to package/wwan/app/quectel_cm_5G/src/log/usage_of_argument/6.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/log/usage_of_argument/m.txt b/package/wwan/app/quectel_cm_5G/src/log/usage_of_argument/m.txt similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/log/usage_of_argument/m.txt rename to package/wwan/app/quectel_cm_5G/src/log/usage_of_argument/m.txt diff --git a/package/wwan/driver/quectel_cm_5G/src/main.c b/package/wwan/app/quectel_cm_5G/src/main.c similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/main.c rename to package/wwan/app/quectel_cm_5G/src/main.c diff --git a/package/wwan/driver/quectel_cm_5G/src/mbim-cm.c b/package/wwan/app/quectel_cm_5G/src/mbim-cm.c similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/mbim-cm.c rename to package/wwan/app/quectel_cm_5G/src/mbim-cm.c diff --git a/package/wwan/driver/quectel_cm_5G/src/qendian.h b/package/wwan/app/quectel_cm_5G/src/qendian.h similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/qendian.h rename to package/wwan/app/quectel_cm_5G/src/qendian.h diff --git a/package/wwan/driver/quectel_cm_5G/src/qlist.h b/package/wwan/app/quectel_cm_5G/src/qlist.h similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/qlist.h rename to package/wwan/app/quectel_cm_5G/src/qlist.h diff --git a/package/wwan/driver/quectel_cm_5G/src/qmap_bridge_mode.c b/package/wwan/app/quectel_cm_5G/src/qmap_bridge_mode.c similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/qmap_bridge_mode.c rename to package/wwan/app/quectel_cm_5G/src/qmap_bridge_mode.c diff --git a/package/wwan/driver/quectel_cm_5G/src/qrtr.c b/package/wwan/app/quectel_cm_5G/src/qrtr.c similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/qrtr.c rename to package/wwan/app/quectel_cm_5G/src/qrtr.c diff --git a/package/wwan/driver/quectel_cm_5G/src/qrtr.h b/package/wwan/app/quectel_cm_5G/src/qrtr.h similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/qrtr.h rename to package/wwan/app/quectel_cm_5G/src/qrtr.h diff --git a/package/wwan/driver/quectel_cm_5G/src/quectel-atc-proxy.c b/package/wwan/app/quectel_cm_5G/src/quectel-atc-proxy.c similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/quectel-atc-proxy.c rename to package/wwan/app/quectel_cm_5G/src/quectel-atc-proxy.c diff --git a/package/wwan/driver/quectel_cm_5G/src/quectel-mbim-proxy.c b/package/wwan/app/quectel_cm_5G/src/quectel-mbim-proxy.c similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/quectel-mbim-proxy.c rename to package/wwan/app/quectel_cm_5G/src/quectel-mbim-proxy.c diff --git a/package/wwan/driver/quectel_cm_5G/src/quectel-qmi-proxy.c b/package/wwan/app/quectel_cm_5G/src/quectel-qmi-proxy.c similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/quectel-qmi-proxy.c rename to package/wwan/app/quectel_cm_5G/src/quectel-qmi-proxy.c diff --git a/package/wwan/driver/quectel_cm_5G/src/quectel-qrtr-proxy.c b/package/wwan/app/quectel_cm_5G/src/quectel-qrtr-proxy.c similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/quectel-qrtr-proxy.c rename to package/wwan/app/quectel_cm_5G/src/quectel-qrtr-proxy.c diff --git a/package/wwan/driver/quectel_cm_5G/src/rmnetctl.c b/package/wwan/app/quectel_cm_5G/src/rmnetctl.c similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/rmnetctl.c rename to package/wwan/app/quectel_cm_5G/src/rmnetctl.c diff --git a/package/wwan/driver/quectel_cm_5G/src/udhcpc.c b/package/wwan/app/quectel_cm_5G/src/udhcpc.c similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/udhcpc.c rename to package/wwan/app/quectel_cm_5G/src/udhcpc.c diff --git a/package/wwan/driver/quectel_cm_5G/src/udhcpc_netlink.c b/package/wwan/app/quectel_cm_5G/src/udhcpc_netlink.c similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/udhcpc_netlink.c rename to package/wwan/app/quectel_cm_5G/src/udhcpc_netlink.c diff --git a/package/wwan/driver/quectel_cm_5G/src/udhcpc_script.c b/package/wwan/app/quectel_cm_5G/src/udhcpc_script.c similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/udhcpc_script.c rename to package/wwan/app/quectel_cm_5G/src/udhcpc_script.c diff --git a/package/wwan/driver/quectel_cm_5G/src/util.c b/package/wwan/app/quectel_cm_5G/src/util.c similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/util.c rename to package/wwan/app/quectel_cm_5G/src/util.c diff --git a/package/wwan/driver/quectel_cm_5G/src/util.h b/package/wwan/app/quectel_cm_5G/src/util.h similarity index 100% rename from package/wwan/driver/quectel_cm_5G/src/util.h rename to package/wwan/app/quectel_cm_5G/src/util.h diff --git a/package/wwan/driver/fibocom_QMI_WWAN/Makefile b/package/wwan/driver/fibocom_QMI_WWAN/Makefile new file mode 100755 index 000000000..836085e20 --- /dev/null +++ b/package/wwan/driver/fibocom_QMI_WWAN/Makefile @@ -0,0 +1,47 @@ +# +# Copyright (C) 2015 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=qmi_wwan_f +PKG_VERSION:=1.0 +PKG_RELEASE:=2 + +include $(INCLUDE_DIR)/kernel.mk +include $(INCLUDE_DIR)/package.mk + +define KernelPackage/qmi_wwan_f + SUBMENU:=WWAN Support + TITLE:=Fibocom Linux USB QMI WWAN Driver + DEPENDS:=+kmod-usb-net +kmod-usb-wdm + FILES:=$(PKG_BUILD_DIR)/qmi_wwan_f.ko + AUTOLOAD:=$(call AutoLoad,82,qmi_wwan_f) +endef + +define KernelPackage/qmi_wwan_f/description + Fibocom Linux USB QMI WWAN Driver +endef + +MAKE_OPTS:= \ + ARCH="$(LINUX_KARCH)" \ + CROSS_COMPILE="$(TARGET_CROSS)" \ + CXXFLAGS="$(TARGET_CXXFLAGS)" \ + M="$(PKG_BUILD_DIR)" \ + $(EXTRA_KCONFIG) + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ +endef + +define Build/Compile + $(MAKE) -C "$(LINUX_DIR)" \ + $(MAKE_OPTS) \ + modules +endef + +$(eval $(call KernelPackage,qmi_wwan_f)) diff --git a/package/wwan/driver/fibocom_QMI_WWAN/src/Makefile b/package/wwan/driver/fibocom_QMI_WWAN/src/Makefile new file mode 100755 index 000000000..00250a1c1 --- /dev/null +++ b/package/wwan/driver/fibocom_QMI_WWAN/src/Makefile @@ -0,0 +1,38 @@ +obj-m += qmi_wwan_f.o + +PWD := $(shell pwd) +OUTPUTDIR=/lib/modules/`uname -r`/kernel/drivers/net/usb/ + +ifeq ($(ARCH),) +ARCH := $(shell uname -m) +endif +ifeq ($(CROSS_COMPILE),) +CROSS_COMPILE := +endif +ifeq ($(KDIR),) +KDIR := /lib/modules/$(shell uname -r)/build +ifeq ($(ARCH),i686) +ifeq ($(wildcard $KDIR/arch/$ARCH),) +ARCH=i386 +endif +endif +endif + +ifneq ($(findstring &,${PWD}),) +$(warning "${PWD}") +$(warning "current directory contain special char '&' !") +$(error "please remove it!") +endif + +default: + $(MAKE) ARCH=${ARCH} CROSS_COMPILE=${CROSS_COMPILE} -C $(KDIR) M=$(PWD) modules + +install: default + cp $(PWD)/qmi_wwan_f.ko /lib/modules/$(shell uname -r)/kernel/drivers/net/usb/ + depmod + modprobe -r qmi_wwan_f + modprobe -r qmi_wwan + modprobe qmi_wwan_f +clean: + rm -rf *~ .tmp_versions modules.order Module.symvers + find . -type f -name "*~" -o -name "*.o" -o -name "*.ko" -o -name "*.cmd" -o -name "*.mod.c" | xargs rm -rf diff --git a/package/wwan/driver/fibocom_QMI_WWAN/src/qmi_wwan_f.c b/package/wwan/driver/fibocom_QMI_WWAN/src/qmi_wwan_f.c new file mode 100755 index 000000000..165a38c1e --- /dev/null +++ b/package/wwan/driver/fibocom_QMI_WWAN/src/qmi_wwan_f.c @@ -0,0 +1,2506 @@ +/* + * Copyright (c) 2012 Bjørn Mork + * + * The probing code is heavily inspired by cdc_ether, which is: + * Copyright (C) 2003-2005 by David Brownell + * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE > KERNEL_VERSION(3,16,0) //8b094cd03b4a3793220d8d8d86a173bfea8c285b +#include +#else +#define timespec64 timespec +#define ktime_get_ts64 ktime_get_ts +#define timespec64_sub timespec_sub +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef ETH_P_MAP +#define ETH_P_MAP 0xDA1A +#endif + +#if (ETH_P_MAP == 0x00F9) +#undef ETH_P_MAP +#define ETH_P_MAP 0xDA1A +#endif + +#ifndef ARPHRD_RAWIP +#define ARPHRD_RAWIP ARPHRD_NONE +#endif + +#ifdef CONFIG_PINCTRL_IPQ807x +#define CONFIG_QCA_NSS_DRV +#endif + +#if 1//def CONFIG_QCA_NSS_DRV +#define _RMNET_NSS_H_ +#define _RMENT_NSS_H_ +struct rmnet_nss_cb { + int (*nss_create)(struct net_device *dev); + int (*nss_free)(struct net_device *dev); + int (*nss_tx)(struct sk_buff *skb); +}; +static struct rmnet_nss_cb *rmnet_nss_callbacks __rcu __read_mostly; +#ifdef CONFIG_QCA_NSS_DRV +static uint __read_mostly qca_nss_enabled = 1; +module_param( qca_nss_enabled, uint, S_IRUGO); +#endif +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION( 4,0,0 )) //1e9e39f4a29857a396ac7b669d109f697f66695e +#define usbnet_set_skb_tx_stats(skb, packets, bytes_delta) do { dev->net->stats.tx_packets += packets; } while(0) +#endif + +/* This driver supports wwan (3G/LTE/?) devices using a vendor + * specific management protocol called Qualcomm MSM Interface (QMI) - + * in addition to the more common AT commands over serial interface + * management + * + * QMI is wrapped in CDC, using CDC encapsulated commands on the + * control ("master") interface of a two-interface CDC Union + * resembling standard CDC ECM. The devices do not use the control + * interface for any other CDC messages. Most likely because the + * management protocol is used in place of the standard CDC + * notifications NOTIFY_NETWORK_CONNECTION and NOTIFY_SPEED_CHANGE + * + * Alternatively, control and data functions can be combined in a + * single USB interface. + * + * Handling a protocol like QMI is out of the scope for any driver. + * It is exported as a character device using the cdc-wdm driver as + * a subdriver, enabling userspace applications ("modem managers") to + * handle it. + * + * These devices may alternatively/additionally be configured using AT + * commands on a serial interface + */ +#define VERSION_NUMBER "V1.0.5" +#define FIBOCOM_WWAN_VERSION "Fibocom_QMI_WWAN_Driver_"VERSION_NUMBER +static const char driver_name[] = "qmi_wwan_f"; + +/* driver specific data */ +struct qmi_wwan_state { + struct usb_driver *subdriver; + atomic_t pmcount; + unsigned long unused; + struct usb_interface *control; + struct usb_interface *data; +}; + +/* default ethernet address used by the modem */ +static const u8 default_modem_addr[ETH_ALEN] = {0x02, 0x50, 0xf3}; + +#if 1 +#define FIBOCOM_WWAN_QMAP 4 //MAX is 7 + +#if defined(FIBOCOM_WWAN_QMAP) +#define FIBOCOM_QMAP_MUX_ID 0x81 + +static uint __read_mostly qmap_mode = 0; +module_param( qmap_mode, uint, S_IRUGO); +module_param_named( rx_qmap, qmap_mode, uint, S_IRUGO ); +#endif + +#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) +#define FIBOCOM_BRIDGE_MODE +#endif + +#ifdef FIBOCOM_BRIDGE_MODE +static uint __read_mostly bridge_mode = 0/*|BIT(1)*/; +module_param( bridge_mode, uint, S_IRUGO ); +#endif + +#if defined(FIBOCOM_WWAN_QMAP) +#define FIBOCOM_UL_DATA_AGG 1 + +#if defined(FIBOCOM_UL_DATA_AGG) +struct tx_agg_ctx { + /* QMIWDS_ADMIN_SET_DATA_FORMAT_RESP TLV_0x17 and TLV_0x18 */ + uint ul_data_aggregation_max_datagrams; //UplinkDataAggregationMaxDatagramsTlv + uint ul_data_aggregation_max_size; //UplinkDataAggregationMaxSizeTlv + uint dl_minimum_padding; //0x1A +}; +#endif + +typedef struct { + unsigned int size; + unsigned int rx_urb_size; + unsigned int ep_type; + unsigned int iface_id; + unsigned int qmap_mode; + unsigned int qmap_version; + unsigned int dl_minimum_padding; + char ifname[8][16]; + unsigned char mux_id[8]; +} RMNET_INFO; + +typedef struct sQmiWwanQmap +{ + struct usbnet *mpNetDev; + struct driver_info driver_info; + atomic_t refcount; + struct net_device *mpQmapNetDev[FIBOCOM_WWAN_QMAP]; + uint link_state; + uint qmap_mode; + uint qmap_size; + uint qmap_version; + struct sk_buff_head skb_chain; + +#if defined(FIBOCOM_UL_DATA_AGG) + struct tx_agg_ctx tx_ctx; + struct tasklet_struct txq; +#endif + +#ifdef FIBOCOM_BRIDGE_MODE + uint bridge_mode; + uint bridge_ipv4; + unsigned char bridge_mac[ETH_ALEN]; +#endif + uint use_rmnet_usb; + RMNET_INFO rmnet_info; +} sQmiWwanQmap; +//2021-03-19 willa.liu@fibocom.com changed begin for support mantis 0073129 +//#if LINUX_VERSION_CODE > KERNEL_VERSION(3,10,0) +#if LINUX_VERSION_CODE > KERNEL_VERSION(3,15,0) +//2021-03-19 willa.liu@fibocom.com changed end for support mantis 0073129 +#define MHI_NETDEV_STATUS64 +#endif +struct qmap_priv { + struct usbnet *dev; + struct net_device *real_dev; + struct net_device *self_dev; + u8 offset_id; + u8 mux_id; + u8 qmap_version; + u8 link_state; + +#if defined(MHI_NETDEV_STATUS64) + struct pcpu_sw_netstats __percpu *stats64; +#endif + + spinlock_t agg_lock; + struct sk_buff *agg_skb; + unsigned agg_count; + struct timespec64 agg_time; + struct hrtimer agg_hrtimer; + struct work_struct agg_wq; + +#ifdef FIBOCOM_BRIDGE_MODE + uint bridge_mode; + uint bridge_ipv4; + unsigned char bridge_mac[ETH_ALEN]; +#endif +}; + +struct qmap_hdr { + u8 cd_rsvd_pad; + u8 mux_id; + u16 pkt_len; +} __packed; + +enum rmnet_map_v5_header_type { + RMNET_MAP_HEADER_TYPE_UNKNOWN, + RMNET_MAP_HEADER_TYPE_COALESCING = 0x1, + RMNET_MAP_HEADER_TYPE_CSUM_OFFLOAD = 0x2, + RMNET_MAP_HEADER_TYPE_ENUM_LENGTH +}; + +/* Main QMAP header */ +struct rmnet_map_header { + u8 pad_len:6; + u8 next_hdr:1; + u8 cd_bit:1; + u8 mux_id; + __be16 pkt_len; +} __aligned(1); + +/* QMAP v5 headers */ +struct rmnet_map_v5_csum_header { + u8 next_hdr:1; + u8 header_type:7; + u8 hw_reserved:7; + u8 csum_valid_required:1; + __be16 reserved; +} __aligned(1); + +#ifdef FIBOCOM_BRIDGE_MODE +static int is_qmap_netdev(const struct net_device *netdev); +#endif +#endif + +#ifdef FIBOCOM_BRIDGE_MODE +static int bridge_arp_reply(struct net_device *net, struct sk_buff *skb, uint bridge_ipv4) { + struct arphdr *parp; + u8 *arpptr, *sha; + u8 sip[4], tip[4], ipv4[4]; + struct sk_buff *reply = NULL; + + ipv4[0] = (bridge_ipv4 >> 24) & 0xFF; + ipv4[1] = (bridge_ipv4 >> 16) & 0xFF; + ipv4[2] = (bridge_ipv4 >> 8) & 0xFF; + ipv4[3] = (bridge_ipv4 >> 0) & 0xFF; + + parp = arp_hdr(skb); + + if (parp->ar_hrd == htons(ARPHRD_ETHER) && parp->ar_pro == htons(ETH_P_IP) + && parp->ar_op == htons(ARPOP_REQUEST) && parp->ar_hln == 6 && parp->ar_pln == 4) { + arpptr = (u8 *)parp + sizeof(struct arphdr); + sha = arpptr; + arpptr += net->addr_len; /* sha */ + memcpy(sip, arpptr, sizeof(sip)); + arpptr += sizeof(sip); + arpptr += net->addr_len; /* tha */ + memcpy(tip, arpptr, sizeof(tip)); + + pr_info("%s sip = %d.%d.%d.%d, tip=%d.%d.%d.%d, ipv4=%d.%d.%d.%d\n", netdev_name(net), + sip[0], sip[1], sip[2], sip[3], tip[0], tip[1], tip[2], tip[3], ipv4[0], ipv4[1], ipv4[2], ipv4[3]); + //wwan0 sip = 10.151.137.255, tip=10.151.138.0, ipv4=10.151.137.255 + if (tip[0] == ipv4[0] && tip[1] == ipv4[1] && (tip[2]&0xFC) == (ipv4[2]&0xFC) && tip[3] != ipv4[3]) + reply = arp_create(ARPOP_REPLY, ETH_P_ARP, *((__be32 *)sip), net, *((__be32 *)tip), sha, default_modem_addr, sha); + + if (reply) { + skb_reset_mac_header(reply); + __skb_pull(reply, skb_network_offset(reply)); + reply->ip_summed = CHECKSUM_UNNECESSARY; + reply->pkt_type = PACKET_HOST; + + netif_rx_ni(reply); + } + return 1; + } + + return 0; +} + +static struct sk_buff *bridge_mode_tx_fixup(struct net_device *net, struct sk_buff *skb, uint bridge_ipv4, unsigned char *bridge_mac) { + struct ethhdr *ehdr; + const struct iphdr *iph; + + skb_reset_mac_header(skb); + ehdr = eth_hdr(skb); + + if (ehdr->h_proto == htons(ETH_P_ARP)) { + if (bridge_ipv4) + bridge_arp_reply(net, skb, bridge_ipv4); + return NULL; + } + + iph = ip_hdr(skb); + //DBG("iphdr: "); + //PrintHex((void *)iph, sizeof(struct iphdr)); + +// 1 0.000000000 0.0.0.0 255.255.255.255 DHCP 362 DHCP Request - Transaction ID 0xe7643ad7 + if (ehdr->h_proto == htons(ETH_P_IP) && iph->protocol == IPPROTO_UDP && iph->saddr == 0x00000000 && iph->daddr == 0xFFFFFFFF) { + //if (udp_hdr(skb)->dest == htons(67)) //DHCP Request + { + memcpy(bridge_mac, ehdr->h_source, ETH_ALEN); + pr_info("%s PC Mac Address: %02x:%02x:%02x:%02x:%02x:%02x\n", netdev_name(net), + bridge_mac[0], bridge_mac[1], bridge_mac[2], bridge_mac[3], bridge_mac[4], bridge_mac[5]); + } + } + + if (memcmp(ehdr->h_source, bridge_mac, ETH_ALEN)) { + return NULL; + } + + return skb; +} + +static void bridge_mode_rx_fixup(sQmiWwanQmap *pQmapDev, struct net_device *net, struct sk_buff *skb) { + uint bridge_mode = 0; + unsigned char *bridge_mac; + + if (pQmapDev->qmap_mode > 1 || pQmapDev->use_rmnet_usb == 1) { + struct qmap_priv *priv = netdev_priv(net); + bridge_mode = priv->bridge_mode; + bridge_mac = priv->bridge_mac; + } + else { + bridge_mode = pQmapDev->bridge_mode; + bridge_mac = pQmapDev->bridge_mac; + } + + if (bridge_mode) + memcpy(eth_hdr(skb)->h_dest, bridge_mac, ETH_ALEN); + else + memcpy(eth_hdr(skb)->h_dest, net->dev_addr, ETH_ALEN); +} +#endif + +#if defined(FIBOCOM_WWAN_QMAP) +static ssize_t qmap_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct net_device *netdev = to_net_dev(dev); + struct usbnet * usbnetdev = netdev_priv( netdev ); + struct qmi_wwan_state *info = (void *)&usbnetdev->data; + sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; + + return snprintf(buf, PAGE_SIZE, "%d\n", pQmapDev->qmap_mode); +} + +static DEVICE_ATTR(qmap_mode, S_IRUGO, qmap_mode_show, NULL); + +static ssize_t qmap_size_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct net_device *netdev = to_net_dev(dev); + struct usbnet * usbnetdev = netdev_priv( netdev ); + struct qmi_wwan_state *info = (void *)&usbnetdev->data; + sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; + + return snprintf(buf, PAGE_SIZE, "%u\n", pQmapDev->qmap_size); +} + +static DEVICE_ATTR(qmap_size, S_IRUGO, qmap_size_show, NULL); + +static ssize_t link_state_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct net_device *netdev = to_net_dev(dev); + struct usbnet * usbnetdev = netdev_priv( netdev ); + struct qmi_wwan_state *info = (void *)&usbnetdev->data; + sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; + + return snprintf(buf, PAGE_SIZE, "0x%x\n", pQmapDev->link_state); +} + +static ssize_t link_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + struct net_device *netdev = to_net_dev(dev); + struct usbnet * usbnetdev = netdev_priv( netdev ); + struct qmi_wwan_state *info = (void *)&usbnetdev->data; + sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; + unsigned link_state = 0; + unsigned old_link = pQmapDev->link_state; + uint offset_id = 0; + + link_state = simple_strtoul(buf, NULL, 0); + + if (pQmapDev->qmap_mode == 1) { + pQmapDev->link_state = !!link_state; + } + else if (pQmapDev->qmap_mode > 1) { + offset_id = ((link_state&0x7F) - 1); + + if (offset_id >= pQmapDev->qmap_mode) { + dev_info(dev, "%s offset_id is %d. but qmap_mode is %d\n", __func__, offset_id, pQmapDev->qmap_mode); + return count; + } + + if (link_state&0x80) + pQmapDev->link_state &= ~(1 << offset_id); + else + pQmapDev->link_state |= (1 << offset_id); + } + + if (old_link != pQmapDev->link_state) { + struct net_device *qmap_net = pQmapDev->mpQmapNetDev[offset_id]; + + if (pQmapDev->link_state) { + netif_carrier_on(usbnetdev->net); + } else { + netif_carrier_off(usbnetdev->net); + } + + if (qmap_net && qmap_net != netdev) { + struct qmap_priv *priv = netdev_priv(qmap_net); + + priv->link_state = !!(pQmapDev->link_state & (1 << offset_id)); + if (priv->link_state) { + netif_carrier_on(qmap_net); + if (netif_queue_stopped(qmap_net) && !netif_queue_stopped(usbnetdev->net)) + netif_wake_queue(qmap_net); + } + else { + netif_carrier_off(qmap_net); + } + } + + dev_info(dev, "link_state 0x%x -> 0x%x\n", old_link, pQmapDev->link_state); + } + + return count; +} + +#ifdef FIBOCOM_BRIDGE_MODE +static ssize_t bridge_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + struct net_device *netdev = to_net_dev(dev); + uint old_mode = 0; + uint bridge_mode = simple_strtoul(buf, NULL, 0); + + if (netdev->type != ARPHRD_ETHER) { + return count; + } + + if (is_qmap_netdev(netdev)) { + struct qmap_priv *priv = netdev_priv(netdev); + old_mode = priv->bridge_mode; + priv->bridge_mode = bridge_mode; + } + else { + struct usbnet * usbnetdev = netdev_priv( netdev ); + struct qmi_wwan_state *info = (void *)&usbnetdev->data; + sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; + old_mode = pQmapDev->bridge_mode; + pQmapDev->bridge_mode = bridge_mode; + } + + if (old_mode != bridge_mode) { + dev_info(dev, "bridge_mode change to 0x%x\n", bridge_mode); + } + + return count; +} + +static ssize_t bridge_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct net_device *netdev = to_net_dev(dev); + uint bridge_mode = 0; + + if (is_qmap_netdev(netdev)) { + struct qmap_priv *priv = netdev_priv(netdev); + bridge_mode = priv->bridge_mode; + } + else { + struct usbnet * usbnetdev = netdev_priv( netdev ); + struct qmi_wwan_state *info = (void *)&usbnetdev->data; + sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; + bridge_mode = pQmapDev->bridge_mode; + } + + return snprintf(buf, PAGE_SIZE, "%u\n", bridge_mode); +} + +static ssize_t bridge_ipv4_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct net_device *netdev = to_net_dev(dev); + unsigned int bridge_ipv4 = 0; + unsigned char ipv4[4]; + + if (is_qmap_netdev(netdev)) { + struct qmap_priv *priv = netdev_priv(netdev); + bridge_ipv4 = priv->bridge_ipv4; + } + else { + struct usbnet * usbnetdev = netdev_priv( netdev ); + struct qmi_wwan_state *info = (void *)&usbnetdev->data; + sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; + bridge_ipv4 = pQmapDev->bridge_ipv4; + } + + ipv4[0] = (bridge_ipv4 >> 24) & 0xFF; + ipv4[1] = (bridge_ipv4 >> 16) & 0xFF; + ipv4[2] = (bridge_ipv4 >> 8) & 0xFF; + ipv4[3] = (bridge_ipv4 >> 0) & 0xFF; + + return snprintf(buf, PAGE_SIZE, "%d.%d.%d.%d\n", ipv4[0], ipv4[1], ipv4[2], ipv4[3]); +} + +static ssize_t bridge_ipv4_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + struct net_device *netdev = to_net_dev(dev); + + if (is_qmap_netdev(netdev)) { + struct qmap_priv *priv = netdev_priv(netdev); + priv->bridge_ipv4 = simple_strtoul(buf, NULL, 16); + } + else { + struct usbnet * usbnetdev = netdev_priv( netdev ); + struct qmi_wwan_state *info = (void *)&usbnetdev->data; + sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; + pQmapDev->bridge_ipv4 = simple_strtoul(buf, NULL, 16); + } + + return count; +} +#endif + +static DEVICE_ATTR(link_state, S_IWUSR | S_IRUGO, link_state_show, link_state_store); +#ifdef FIBOCOM_BRIDGE_MODE +static DEVICE_ATTR(bridge_mode, S_IWUSR | S_IRUGO, bridge_mode_show, bridge_mode_store); +static DEVICE_ATTR(bridge_ipv4, S_IWUSR | S_IRUGO, bridge_ipv4_show, bridge_ipv4_store); +#endif + +static struct attribute *qmi_wwan_sysfs_attrs[] = { + &dev_attr_link_state.attr, + &dev_attr_qmap_mode.attr, + &dev_attr_qmap_size.attr, +#ifdef FIBOCOM_BRIDGE_MODE + &dev_attr_bridge_mode.attr, + &dev_attr_bridge_ipv4.attr, +#endif + NULL, +}; + +static struct attribute_group qmi_wwan_sysfs_attr_group = { + .attrs = qmi_wwan_sysfs_attrs, +}; + +#ifdef FIBOCOM_BRIDGE_MODE +static struct attribute *qmi_qmap_sysfs_attrs[] = { + &dev_attr_bridge_mode.attr, + &dev_attr_bridge_ipv4.attr, + NULL, +}; + +static struct attribute_group qmi_qmap_sysfs_attr_group = { + .attrs = qmi_qmap_sysfs_attrs, +}; +#endif + +static int qmap_open(struct net_device *dev) +{ + struct qmap_priv *priv = netdev_priv(dev); + struct net_device *real_dev = priv->real_dev; + + if (!(priv->real_dev->flags & IFF_UP)) + return -ENETDOWN; + + if (netif_carrier_ok(real_dev) && priv->link_state) + netif_carrier_on(dev); + + if (netif_carrier_ok(dev)) { + if (netif_queue_stopped(dev) && !netif_queue_stopped(real_dev)) + netif_wake_queue(dev); + } + + return 0; +} + +static int qmap_stop(struct net_device *pNet) +{ + netif_carrier_off(pNet); + return 0; +} + +static struct sk_buff * add_qhdr(struct sk_buff *skb, u8 mux_id) { + struct qmap_hdr *qhdr; + int pad = 0; + + pad = skb->len%4; + if (pad) { + pad = 4 - pad; + if (skb_tailroom(skb) < pad) { + printk("skb_tailroom small!\n"); + pad = 0; + } + if (pad) + __skb_put(skb, pad); + } + + qhdr = (struct qmap_hdr *)skb_push(skb, sizeof(struct qmap_hdr)); + qhdr->cd_rsvd_pad = pad; + qhdr->mux_id = mux_id; + qhdr->pkt_len = cpu_to_be16(skb->len - sizeof(struct qmap_hdr)); + + return skb; +} + +static struct sk_buff * add_qhdr_v5(struct sk_buff *skb, u8 mux_id) { + struct rmnet_map_header *map_header; + struct rmnet_map_v5_csum_header *ul_header; + u32 padding, map_datalen; + + map_datalen = skb->len; + padding = map_datalen%4; + if (padding) { + padding = 4 - padding; + if (skb_tailroom(skb) < padding) { + printk("skb_tailroom small!\n"); + padding = 0; + } + if (padding) + __skb_put(skb, padding); + } + + map_header = (struct rmnet_map_header *)skb_push(skb, (sizeof(struct rmnet_map_header) + sizeof(struct rmnet_map_v5_csum_header))); + map_header->cd_bit = 0; + map_header->next_hdr = 1; + map_header->pad_len = padding; + map_header->mux_id = mux_id; + map_header->pkt_len = htons(map_datalen + padding); + + ul_header = (struct rmnet_map_v5_csum_header *)(map_header + 1); + memset(ul_header, 0, sizeof(*ul_header)); + ul_header->header_type = RMNET_MAP_HEADER_TYPE_CSUM_OFFLOAD; + if (skb->ip_summed == CHECKSUM_PARTIAL) { +#if 0 //TODO + skb->ip_summed = CHECKSUM_NONE; + /* Ask for checksum offloading */ + ul_header->csum_valid_required = 1; +#endif + } + + return skb; +} + +static void rmnet_vnd_update_rx_stats(struct net_device *net, + unsigned rx_packets, unsigned rx_bytes) { +#if defined(MHI_NETDEV_STATUS64) + struct qmap_priv *dev = netdev_priv(net); + struct pcpu_sw_netstats *stats64 = this_cpu_ptr(dev->stats64); + + u64_stats_update_begin(&stats64->syncp); + stats64->rx_packets += rx_packets; + stats64->rx_bytes += rx_bytes; + u64_stats_update_end(&stats64->syncp); +#else + net->stats.rx_packets += rx_packets; + net->stats.rx_bytes += rx_bytes; +#endif +} + +static void rmnet_vnd_update_tx_stats(struct net_device *net, + unsigned tx_packets, unsigned tx_bytes) { +#if defined(MHI_NETDEV_STATUS64) + struct qmap_priv *dev = netdev_priv(net); + struct pcpu_sw_netstats *stats64 = this_cpu_ptr(dev->stats64); + + u64_stats_update_begin(&stats64->syncp); + stats64->tx_packets += tx_packets; + stats64->tx_bytes += tx_bytes; + u64_stats_update_end(&stats64->syncp); +#else + net->stats.tx_packets += tx_packets; + net->stats.tx_bytes += tx_bytes; +#endif +} + +#if defined(MHI_NETDEV_STATUS64) +static struct rtnl_link_stats64 *_rmnet_vnd_get_stats64(struct net_device *net, struct rtnl_link_stats64 *stats) +{ + struct qmap_priv *dev = netdev_priv(net); + unsigned int start; + int cpu; + struct rmnet_nss_cb *nss_cb; + + netdev_stats_to_stats64(stats, &net->stats); + + nss_cb = rcu_dereference(rmnet_nss_callbacks); + if (nss_cb) { // rmnet_nss.c:rmnet_nss_tx() will update rx stats + stats->rx_packets = 0; + stats->rx_bytes = 0; + } + + for_each_possible_cpu(cpu) { + struct pcpu_sw_netstats *stats64; + u64 rx_packets, rx_bytes; + u64 tx_packets, tx_bytes; + + stats64 = per_cpu_ptr(dev->stats64, cpu); + + do { + start = u64_stats_fetch_begin_irq(&stats64->syncp); + rx_packets = stats64->rx_packets; + rx_bytes = stats64->rx_bytes; + tx_packets = stats64->tx_packets; + tx_bytes = stats64->tx_bytes; + } while (u64_stats_fetch_retry_irq(&stats64->syncp, start)); + + stats->rx_packets += rx_packets; + stats->rx_bytes += rx_bytes; + stats->tx_packets += tx_packets; + stats->tx_bytes += tx_bytes; + } + + return stats; +} + +#if (LINUX_VERSION_CODE > KERNEL_VERSION( 4,10,0 )) //bc1f44709cf27fb2a5766cadafe7e2ad5e9cb221 +static void rmnet_vnd_get_stats64(struct net_device *net, struct rtnl_link_stats64 *stats) { + _rmnet_vnd_get_stats64(net, stats); +} +#else +static struct rtnl_link_stats64 *rmnet_vnd_get_stats64(struct net_device *net, struct rtnl_link_stats64 *stats) { + return _rmnet_vnd_get_stats64(net, stats); +} +#endif +#endif + +#if defined(FIBOCOM_UL_DATA_AGG) +static void rmnet_usb_tx_wake_queue(unsigned long data) { + sQmiWwanQmap *pQmapDev = (void *)data; + int i; + + for (i = 0; i < pQmapDev->qmap_mode; i++) { + struct net_device *qmap_net = pQmapDev->mpQmapNetDev[i]; + if (qmap_net) { + if (netif_queue_stopped(qmap_net) && !netif_queue_stopped(pQmapDev->mpNetDev->net)) { + netif_wake_queue(qmap_net); + } + } + } +} + +static void rmnet_usb_tx_skb_destructor(struct sk_buff *skb) { + struct net_device *net = skb->dev; + struct usbnet * dev = netdev_priv( net ); + struct qmi_wwan_state *info = (void *)&dev->data; + sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; + + if (pQmapDev && pQmapDev->use_rmnet_usb) { + int i; + + for (i = 0; i < pQmapDev->qmap_mode; i++) { + struct net_device *qmap_net = pQmapDev->mpQmapNetDev[i]; + + if (qmap_net) { + if (netif_queue_stopped(qmap_net)) { + tasklet_schedule(&pQmapDev->txq); + break; + } + } + } + } +} + +static int rmnet_usb_tx_agg_skip(struct sk_buff *skb, int offset) +{ + u8 *packet_start = skb->data + offset; + int ready2send = 0; + + if (skb->protocol == htons(ETH_P_IP)) { + struct iphdr *ip4h = (struct iphdr *)(packet_start); + + if (ip4h->protocol == IPPROTO_TCP) { + const struct tcphdr *th = (const struct tcphdr *)(packet_start + sizeof(struct iphdr)); + if (th->psh) { + ready2send = 1; + } + } + else if (ip4h->protocol == IPPROTO_ICMP) + ready2send = 1; + + } else if (skb->protocol == htons(ETH_P_IPV6)) { + struct ipv6hdr *ip6h = (struct ipv6hdr *)(packet_start); + + if (ip6h->nexthdr == NEXTHDR_TCP) { + const struct tcphdr *th = (const struct tcphdr *)(packet_start + sizeof(struct ipv6hdr)); + if (th->psh) { + ready2send = 1; + } + } else if (ip6h->nexthdr == NEXTHDR_ICMP) { + ready2send = 1; + } else if (ip6h->nexthdr == NEXTHDR_FRAGMENT) { + struct frag_hdr *frag; + + frag = (struct frag_hdr *)(packet_start + + sizeof(struct ipv6hdr)); + if (frag->nexthdr == IPPROTO_ICMPV6) + ready2send = 1; + } + } + + return ready2send; +} + +static void rmnet_usb_tx_agg_work(struct work_struct *work) +{ + struct qmap_priv *priv = + container_of(work, struct qmap_priv, agg_wq); + struct sk_buff *skb = NULL; + unsigned long flags; + + spin_lock_irqsave(&priv->agg_lock, flags); + if (likely(priv->agg_skb)) { + skb = priv->agg_skb; + priv->agg_skb = NULL; + priv->agg_count = 0; + skb->protocol = htons(ETH_P_MAP); + skb->dev = priv->real_dev; + ktime_get_ts64(&priv->agg_time); + } + spin_unlock_irqrestore(&priv->agg_lock, flags); + + if (skb) { + int err = dev_queue_xmit(skb); + if (err != NET_XMIT_SUCCESS) { + priv->self_dev->stats.tx_errors++; + } + } +} + +static enum hrtimer_restart rmnet_usb_tx_agg_timer_cb(struct hrtimer *timer) +{ + struct qmap_priv *priv = + container_of(timer, struct qmap_priv, agg_hrtimer); + + schedule_work(&priv->agg_wq); + return HRTIMER_NORESTART; +} + +static long agg_time_limit __read_mostly = 1000000L; //reduce this time, can get better TPUT performance, but will increase USB interrupts +module_param(agg_time_limit, long, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(agg_time_limit, "Maximum time packets sit in the agg buf"); + +static long agg_bypass_time __read_mostly = 10000000L; +module_param(agg_bypass_time, long, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(agg_bypass_time, "Skip agg when apart spaced more than this"); + +static int rmnet_usb_tx_agg(struct sk_buff *skb, struct qmap_priv *priv) { + struct qmi_wwan_state *info = (void *)&priv->dev->data; + sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; + struct tx_agg_ctx *ctx = &pQmapDev->tx_ctx; + int ready2send = 0; + int xmit_more = 0; + struct timespec64 diff, now; + struct sk_buff *agg_skb = NULL; + unsigned long flags; + int err; + struct net_device *pNet = priv->self_dev; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,1,0) //6b16f9ee89b8d5709f24bc3ac89ae8b5452c0d7c +#if LINUX_VERSION_CODE > KERNEL_VERSION(3,16,0) + xmit_more = skb->xmit_more; +#endif +#else + xmit_more = netdev_xmit_more(); +#endif + + rmnet_vnd_update_tx_stats(pNet, 1, skb->len); + + if (ctx->ul_data_aggregation_max_datagrams == 1) { + skb->protocol = htons(ETH_P_MAP); + skb->dev = priv->real_dev; + if (!skb->destructor) + skb->destructor = rmnet_usb_tx_skb_destructor; + err = dev_queue_xmit(skb); + if (err != NET_XMIT_SUCCESS) + pNet->stats.tx_errors++; + return NET_XMIT_SUCCESS; + } + +new_packet: + spin_lock_irqsave(&priv->agg_lock, flags); + agg_skb = NULL; + ready2send = 0; + ktime_get_ts64(&now); + diff = timespec64_sub(now, priv->agg_time); + + if (priv->agg_skb) { + if ((priv->agg_skb->len + skb->len) < ctx->ul_data_aggregation_max_size) { + memcpy(skb_put(priv->agg_skb, skb->len), skb->data, skb->len); + priv->agg_count++; + + if (diff.tv_sec > 0 || diff.tv_nsec > agg_time_limit) { + ready2send = 1; + } + else if (priv->agg_count == ctx->ul_data_aggregation_max_datagrams) { + ready2send = 1; + } + else if (xmit_more == 0) { + struct rmnet_map_header *map_header = (struct rmnet_map_header *)skb->data; + size_t offset = sizeof(struct rmnet_map_header); + if (map_header->next_hdr) + offset += sizeof(struct rmnet_map_v5_csum_header); + + ready2send = rmnet_usb_tx_agg_skip(skb, offset); + } + + dev_kfree_skb_any(skb); + skb = NULL; + } + else { + ready2send = 1; + } + + if (ready2send) { + agg_skb = priv->agg_skb; + priv->agg_skb = NULL; + priv->agg_count = 0; + } + } + else if (skb) { + if (diff.tv_sec > 0 || diff.tv_nsec > agg_bypass_time) { + ready2send = 1; + } + else if (xmit_more == 0) { + struct rmnet_map_header *map_header = (struct rmnet_map_header *)skb->data; + size_t offset = sizeof(struct rmnet_map_header); + if (map_header->next_hdr) + offset += sizeof(struct rmnet_map_v5_csum_header); + + ready2send = rmnet_usb_tx_agg_skip(skb, offset); + } + + if (ready2send == 0) { + priv->agg_skb = alloc_skb(ctx->ul_data_aggregation_max_size, GFP_ATOMIC); + if (priv->agg_skb) { + memcpy(skb_put(priv->agg_skb, skb->len), skb->data, skb->len); + priv->agg_count++; + dev_kfree_skb_any(skb); + skb = NULL; + } + else { + ready2send = 1; + } + } + + if (ready2send) { + agg_skb = skb; + skb = NULL; + } + } + + if (ready2send) { + priv->agg_time = now; + } + spin_unlock_irqrestore(&priv->agg_lock, flags); + + if (agg_skb) { + agg_skb->protocol = htons(ETH_P_MAP); + agg_skb->dev = priv->real_dev; + if (!agg_skb->destructor) + agg_skb->destructor = rmnet_usb_tx_skb_destructor; + err = dev_queue_xmit(agg_skb); + if (err != NET_XMIT_SUCCESS) { + pNet->stats.tx_errors++; + } + } + + if (skb) { + goto new_packet; + } + + if (priv->agg_skb) { + if (!hrtimer_is_queued(&priv->agg_hrtimer)) + hrtimer_start(&priv->agg_hrtimer, ns_to_ktime(NSEC_PER_MSEC * 2), HRTIMER_MODE_REL); + } + + return NET_XMIT_SUCCESS; +} +#endif + +static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb, + struct net_device *pNet) +{ + int err; + struct qmap_priv *priv = netdev_priv(pNet); + + if (netif_queue_stopped(priv->real_dev)) { + netif_stop_queue(pNet); + return NETDEV_TX_BUSY; + } + + //printk("%s 1 skb=%p, len=%d, protocol=%x, hdr_len=%d\n", __func__, skb, skb->len, skb->protocol, skb->hdr_len); + if (pNet->type == ARPHRD_ETHER) { + skb_reset_mac_header(skb); + +#ifdef FIBOCOM_BRIDGE_MODE + if (priv->bridge_mode && bridge_mode_tx_fixup(pNet, skb, priv->bridge_ipv4, priv->bridge_mac) == NULL) { + dev_kfree_skb_any (skb); + return NETDEV_TX_OK; + } +#endif + + if (skb_pull(skb, ETH_HLEN) == NULL) { + dev_kfree_skb_any (skb); + return NETDEV_TX_OK; + } + } + //printk("%s 2 skb=%p, len=%d, protocol=%x, hdr_len=%d\n", __func__, skb, skb->len, skb->protocol, skb->hdr_len); + + if (priv->qmap_version == 5) { + add_qhdr(skb, priv->mux_id); + } + else if (priv->qmap_version == 9) { + add_qhdr_v5(skb, priv->mux_id); + } + else { + dev_kfree_skb_any (skb); + return NETDEV_TX_OK; + } + //printk("%s skb=%p, len=%d, protocol=%x, hdr_len=%d\n", __func__, skb, skb->len, skb->protocol, skb->hdr_len); + +#if 0 + skb->protocol = htons(ETH_P_MAP); + skb->dev = priv->real_dev; + err = dev_queue_xmit(skb); + + if (err == NET_XMIT_SUCCESS) { + rmnet_vnd_update_tx_stats(pNet, 1, skb->len); + } else { + pNet->stats.tx_errors++; + } +#else + err = rmnet_usb_tx_agg(skb, priv); +#endif + + return err; +} + +static int rmnet_vnd_change_mtu(struct net_device *rmnet_dev, int new_mtu) +{ + if (new_mtu < 0 || new_mtu > 1500) + return -EINVAL; + + rmnet_dev->mtu = new_mtu; + return 0; +} + +/* drivers may override default ethtool_ops in their bind() routine */ +static const struct ethtool_ops rmnet_vnd_ethtool_ops = { + .get_link = ethtool_op_get_link, +}; + +static int qmap_start_xmit(struct sk_buff *skb, struct net_device *pNet) +{ + int err; + struct qmap_priv *priv = netdev_priv(pNet); + + //printk("%s 1 skb=%p, len=%d, protocol=%x, hdr_len=%d\n", __func__, skb, skb->len, skb->protocol, skb->hdr_len); + if (pNet->type == ARPHRD_ETHER) { + skb_reset_mac_header(skb); + +#ifdef FIBOCOM_BRIDGE_MODE + if (priv->bridge_mode && bridge_mode_tx_fixup(pNet, skb, priv->bridge_ipv4, priv->bridge_mac) == NULL) { + dev_kfree_skb_any (skb); + return NETDEV_TX_OK; + } +#endif + + if (skb_pull(skb, ETH_HLEN) == NULL) { + dev_kfree_skb_any (skb); + return NETDEV_TX_OK; + } + } + + + add_qhdr(skb, FIBOCOM_QMAP_MUX_ID + priv->offset_id); + + skb->dev = priv->real_dev; + err = dev_queue_xmit(skb); + if (err == NET_XMIT_SUCCESS) { + pNet->stats.tx_packets++; + pNet->stats.tx_bytes += skb->len; + } else { + pNet->stats.tx_errors++; + } + + return err; +} + +static const struct net_device_ops qmap_netdev_ops = { + .ndo_open = qmap_open, + .ndo_stop = qmap_stop, + .ndo_start_xmit = qmap_start_xmit, +}; + +static const struct net_device_ops rmnet_vnd_ops = { + .ndo_open = qmap_open, + .ndo_stop = qmap_stop, + .ndo_start_xmit = rmnet_vnd_start_xmit, + .ndo_change_mtu = rmnet_vnd_change_mtu, +#if defined(MHI_NETDEV_STATUS64) + .ndo_get_stats64 = rmnet_vnd_get_stats64, +#endif +}; + +static void rmnet_usb_vnd_setup(struct net_device *rmnet_dev) +{ + rmnet_dev->needed_headroom = 16; + + /* Raw IP mode */ + rmnet_dev->header_ops = NULL; /* No header */ + rmnet_dev->type = ARPHRD_RAWIP; + rmnet_dev->hard_header_len = 0; + rmnet_dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST); +} + +static rx_handler_result_t rmnet_usb_rx_priv_handler(struct sk_buff **pskb) +{ + struct sk_buff *skb = *pskb; + struct rmnet_nss_cb *nss_cb; + + if (!skb) + return RX_HANDLER_CONSUMED; + + //printk("%s skb=%p, len=%d, protocol=%x, hdr_len=%d\n", __func__, skb, skb->len, skb->protocol, skb->hdr_len); + + if (skb->pkt_type == PACKET_LOOPBACK) + return RX_HANDLER_PASS; + + /* Check this so that we dont loop around netif_receive_skb */ + if (skb->cb[0] == 1) { + skb->cb[0] = 0; + + return RX_HANDLER_PASS; + } + + nss_cb = rcu_dereference(rmnet_nss_callbacks); + if (nss_cb) { + nss_cb->nss_tx(skb); + return RX_HANDLER_CONSUMED; + } + + return RX_HANDLER_PASS; +} + +static int qmap_register_device(sQmiWwanQmap * pDev, u8 offset_id) +{ + struct net_device *real_dev = pDev->mpNetDev->net; + struct net_device *qmap_net; + struct qmap_priv *priv; + int err; + struct rmnet_nss_cb *nss_cb; + + qmap_net = alloc_etherdev(sizeof(*priv)); + if (!qmap_net) + return -ENOBUFS; + + SET_NETDEV_DEV(qmap_net, &real_dev->dev); + priv = netdev_priv(qmap_net); + priv->offset_id = offset_id; + priv->real_dev = real_dev; + priv->self_dev = qmap_net; + priv->dev = pDev->mpNetDev; + priv->qmap_version = pDev->qmap_version; + priv->mux_id = FIBOCOM_QMAP_MUX_ID + offset_id; + sprintf(qmap_net->name, "%s.%d", real_dev->name, offset_id + 1); + qmap_net->netdev_ops = &qmap_netdev_ops; + memcpy (qmap_net->dev_addr, real_dev->dev_addr, ETH_ALEN); + +#ifdef FIBOCOM_BRIDGE_MODE + priv->bridge_mode = !!(pDev->bridge_mode & BIT(offset_id)); + qmap_net->sysfs_groups[0] = &qmi_qmap_sysfs_attr_group; +#endif + + priv->agg_skb = NULL; + priv->agg_count = 0; + hrtimer_init(&priv->agg_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + priv->agg_hrtimer.function = rmnet_usb_tx_agg_timer_cb; + INIT_WORK(&priv->agg_wq, rmnet_usb_tx_agg_work); + ktime_get_ts64(&priv->agg_time); + spin_lock_init(&priv->agg_lock); + + if (pDev->use_rmnet_usb) { + qmap_net->ethtool_ops = &rmnet_vnd_ethtool_ops; + qmap_net->netdev_ops = &rmnet_vnd_ops; +#if defined(MHI_NETDEV_STATUS64) + priv->stats64 = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); + if (!priv->stats64) { + err = -ENOBUFS; + goto out_free_newdev; + } +#endif + } + + nss_cb = rcu_dereference(rmnet_nss_callbacks); +#ifdef FIBOCOM_BRIDGE_MODE + if(nss_cb && !priv->bridge_mode) { +#else + if (nss_cb) { +#endif + rmnet_usb_vnd_setup(qmap_net); + } + + err = register_netdev(qmap_net); + dev_info(&real_dev->dev, "%s(%s)=%d\n", __func__, qmap_net->name, err); + if (err < 0) + goto out_free_newdev; + netif_device_attach (qmap_net); + netif_carrier_off(qmap_net); + + nss_cb = rcu_dereference(rmnet_nss_callbacks); +#ifdef FIBOCOM_BRIDGE_MODE + if(nss_cb && !priv->bridge_mode) { +#else + if (nss_cb) { +#endif + int rc = nss_cb->nss_create(qmap_net); + if (rc) { + /* Log, but don't fail the device creation */ + netdev_err(qmap_net, "Device will not use NSS path: %d\n", rc); + } else { + netdev_info(qmap_net, "NSS context created\n"); + rtnl_lock(); + netdev_rx_handler_register(qmap_net, rmnet_usb_rx_priv_handler, NULL); + rtnl_unlock(); + } + } + + if (pDev->use_rmnet_usb) { + strcpy(pDev->rmnet_info.ifname[offset_id], qmap_net->name); + pDev->rmnet_info.mux_id[offset_id] = priv->mux_id; + } + + pDev->mpQmapNetDev[offset_id] = qmap_net; + qmap_net->flags |= IFF_NOARP; + qmap_net->flags &= ~(IFF_BROADCAST | IFF_MULTICAST); + + dev_info(&real_dev->dev, "%s %s\n", __func__, qmap_net->name); + + return 0; + +out_free_newdev: + free_netdev(qmap_net); + return err; +} + +static void qmap_unregister_device(sQmiWwanQmap * pDev, u8 offset_id) { + struct net_device *qmap_net = pDev->mpQmapNetDev[offset_id]; + + if (qmap_net != NULL && qmap_net != pDev->mpNetDev->net) { + struct rmnet_nss_cb *nss_cb; + struct qmap_priv *priv = netdev_priv(qmap_net); + unsigned long flags; + + pr_info("qmap_unregister_device(%s)\n", qmap_net->name); + pDev->mpQmapNetDev[offset_id] = NULL; + netif_carrier_off( qmap_net ); + netif_stop_queue( qmap_net ); + + hrtimer_cancel(&priv->agg_hrtimer); + cancel_work_sync(&priv->agg_wq); + spin_lock_irqsave(&priv->agg_lock, flags); + if (priv->agg_skb) { + kfree_skb(priv->agg_skb); + } + spin_unlock_irqrestore(&priv->agg_lock, flags); + nss_cb = rcu_dereference(rmnet_nss_callbacks); + +#ifdef FIBOCOM_BRIDGE_MODE + if(nss_cb && !priv->bridge_mode) { +#else + if (nss_cb) { +#endif + rtnl_lock(); + netdev_rx_handler_unregister(qmap_net); + rtnl_unlock(); + nss_cb->nss_free(qmap_net); + } + +#if defined(MHI_NETDEV_STATUS64) + free_percpu(priv->stats64); +#endif + unregister_netdev (qmap_net); + free_netdev(qmap_net); + } +} + +#if 1//def CONFIG_ANDROID +typedef struct { + unsigned int size; + unsigned int rx_urb_size; + unsigned int ep_type; + unsigned int iface_id; + unsigned int MuxId; + unsigned int ul_data_aggregation_max_datagrams; //0x17 + unsigned int ul_data_aggregation_max_size ;//0x18 + unsigned int dl_minimum_padding; //0x1A +} QMAP_SETTING; + +int qma_setting_store(struct device *dev, QMAP_SETTING *qmap_settings, size_t size) { + struct net_device *netdev = to_net_dev(dev); + struct usbnet * usbnetdev = netdev_priv( netdev ); + struct qmi_wwan_state *info = (void *)&usbnetdev->data; + sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; + + if (qmap_settings->size != size) { + dev_err(dev, "ERROR: qmap_settings.size donot match!\n"); + return -EOPNOTSUPP; + } + +#ifdef FIBOCOM_UL_DATA_AGG + netif_tx_lock_bh(netdev); + if (pQmapDev->tx_ctx.ul_data_aggregation_max_datagrams == 1 && qmap_settings->ul_data_aggregation_max_datagrams > 1) { + pQmapDev->tx_ctx.ul_data_aggregation_max_datagrams = qmap_settings->ul_data_aggregation_max_datagrams; + pQmapDev->tx_ctx.ul_data_aggregation_max_size = qmap_settings->ul_data_aggregation_max_size; + pQmapDev->tx_ctx.dl_minimum_padding = qmap_settings->dl_minimum_padding; + dev_info(dev, "ul_data_aggregation_max_datagrams=%d, ul_data_aggregation_max_size=%d, dl_minimum_padding=%d\n", + pQmapDev->tx_ctx.ul_data_aggregation_max_datagrams, + pQmapDev->tx_ctx.ul_data_aggregation_max_size, + pQmapDev->tx_ctx.dl_minimum_padding); + } + netif_tx_unlock_bh(netdev); + return 0; +#endif + + return -EOPNOTSUPP; +} + +static int qmap_ndo_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { + struct usbnet * usbnetdev = netdev_priv( dev ); + struct qmi_wwan_state *info = (void *)&usbnetdev->data; + sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; + int rc = -EOPNOTSUPP; + uint link_state = 0; + QMAP_SETTING qmap_settings = {0}; + + switch (cmd) { + case 0x89F1: //SIOCDEVPRIVATE + rc = copy_from_user(&link_state, ifr->ifr_ifru.ifru_data, sizeof(link_state)); + if (!rc) { + char buf[32]; + snprintf(buf, sizeof(buf), "%u", link_state); + link_state_store(&dev->dev, NULL, buf, strlen(buf)); + } + break; + + case 0x89F2: //SIOCDEVPRIVATE + rc = copy_from_user(&qmap_settings, ifr->ifr_ifru.ifru_data, sizeof(qmap_settings)); + if (!rc) { + rc = qma_setting_store(&dev->dev, &qmap_settings, sizeof(qmap_settings)); + } + break; + + case 0x89F3: //SIOCDEVPRIVATE + if (pQmapDev->use_rmnet_usb) { + uint i; + + for (i = 0; i < pQmapDev->qmap_mode; i++) { + struct net_device *qmap_net = pQmapDev->mpQmapNetDev[i]; + + if (!qmap_net) + break; + + strcpy(pQmapDev->rmnet_info.ifname[i], qmap_net->name); + } + rc = copy_to_user(ifr->ifr_ifru.ifru_data, &pQmapDev->rmnet_info, sizeof(pQmapDev->rmnet_info)); + } + break; + + default: + break; + } + + return rc; +} +#endif + +#ifdef FIBOCOM_BRIDGE_MODE +static int is_qmap_netdev(const struct net_device *netdev) { + return netdev->netdev_ops == &qmap_netdev_ops || netdev->netdev_ops == &rmnet_vnd_ops; +} +#endif +#endif + +static struct sk_buff *qmi_wwan_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { + if ((dev->driver_info->flags & FLAG_NOARP) == 0) + return skb; + + // Skip Ethernet header from message + if (dev->net->hard_header_len == 0) + return skb; + else + skb_reset_mac_header(skb); + +#ifdef FIBOCOM_BRIDGE_MODE +{ + struct qmi_wwan_state *info = (void *)&dev->data; + sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; + + if (pQmapDev->bridge_mode && bridge_mode_tx_fixup(dev->net, skb, pQmapDev->bridge_ipv4, pQmapDev->bridge_mac) == NULL) { + dev_kfree_skb_any (skb); + return NULL; + } +} +#endif + + if (skb_pull(skb, ETH_HLEN)) { + return skb; + } else { + dev_err(&dev->intf->dev, "Packet Dropped "); + } + + // Filter the packet out, release it + dev_kfree_skb_any(skb); + return NULL; +} +#endif + +/* Make up an ethernet header if the packet doesn't have one. + * + * A firmware bug common among several devices cause them to send raw + * IP packets under some circumstances. There is no way for the + * driver/host to know when this will happen. And even when the bug + * hits, some packets will still arrive with an intact header. + * + * The supported devices are only capably of sending IPv4, IPv6 and + * ARP packets on a point-to-point link. Any packet with an ethernet + * header will have either our address or a broadcast/multicast + * address as destination. ARP packets will always have a header. + * + * This means that this function will reliably add the appropriate + * header if necessary, provided our hardware address does not start + * with 4 or 6. + * + * Another common firmware bug results in all packets being addressed + * to 00:a0:c6:00:00:00 despite the host address being different. + * This function will also fixup such packets. + */ +static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ + __be16 proto; + + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + + switch (skb->data[0] & 0xf0) { + case 0x40: + proto = htons(ETH_P_IP); + break; + case 0x60: + proto = htons(ETH_P_IPV6); + break; + case 0x00: + if (is_multicast_ether_addr(skb->data)) + return 1; + /* possibly bogus destination - rewrite just in case */ + skb_reset_mac_header(skb); + goto fix_dest; + default: + /* pass along other packets without modifications */ + return 1; + } + if (skb_headroom(skb) < ETH_HLEN) + return 0; + skb_push(skb, ETH_HLEN); + skb_reset_mac_header(skb); + eth_hdr(skb)->h_proto = proto; + memset(eth_hdr(skb)->h_source, 0, ETH_ALEN); +#if 1 //Added by Fibocom + //some kernel will drop ethernet packet which's souce mac is all zero + memcpy(eth_hdr(skb)->h_source, default_modem_addr, ETH_ALEN); +#endif + +fix_dest: +#ifdef FIBOCOM_BRIDGE_MODE +{ + struct qmi_wwan_state *info = (void *)&dev->data; + sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; + bridge_mode_rx_fixup(pQmapDev, dev->net, skb); +} +#else + memcpy(eth_hdr(skb)->h_dest, dev->net->dev_addr, ETH_ALEN); +#endif + + return 1; +} + +#if defined(FIBOCOM_WWAN_QMAP) +static struct sk_buff *qmap_qmi_wwan_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { + struct qmi_wwan_state *info = (void *)&dev->data; + sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; + struct qmap_hdr *qhdr; + + if (unlikely(pQmapDev == NULL)) { + goto drop_skb; + } else if (unlikely(pQmapDev->qmap_mode && !pQmapDev->link_state)) { + dev_dbg(&dev->net->dev, "link_state 0x%x, drop skb, len = %u\n", pQmapDev->link_state, skb->len); + goto drop_skb; + } else if (pQmapDev->qmap_mode == 0) { + skb = qmi_wwan_tx_fixup(dev, skb, flags); + } + else if (pQmapDev->qmap_mode > 1) { + if (likely(skb)) { + qhdr = (struct qmap_hdr *)skb->data; + if ((qhdr->mux_id&0xF0) != 0x80 || ((be16_to_cpu(qhdr->pkt_len) + sizeof(struct qmap_hdr)) != skb->len)) { + goto drop_skb; + } + } + } + else { + if (likely(skb)) { + skb = qmi_wwan_tx_fixup(dev, skb, flags); + + if (skb) { + add_qhdr(skb, FIBOCOM_QMAP_MUX_ID); + } + else { + return NULL; + } + } + } + + if (skb && (dev->driver_info->flags&FLAG_MULTI_PACKET)) { + usbnet_set_skb_tx_stats(skb, 1, 0); + } + + + return skb; +drop_skb: + dev_kfree_skb_any (skb); + return NULL; +} + +static int qmap_qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in) +{ + struct qmi_wwan_state *info = (void *)&dev->data; + sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; + unsigned headroom = 0; + const unsigned need_headroot = ETH_HLEN; + struct sk_buff *qmap_skb; + + if (pQmapDev->qmap_mode == 0) + return qmi_wwan_rx_fixup(dev, skb_in); + + headroom = skb_headroom(skb_in); + + while (skb_in->len > sizeof(struct qmap_hdr)) { + struct qmap_hdr *qhdr = (struct qmap_hdr *)skb_in->data; + struct net_device *qmap_net; + int pkt_len = be16_to_cpu(qhdr->pkt_len); + int skb_len; + __be16 protocol; + int mux_id; + + skb_len = pkt_len - (qhdr->cd_rsvd_pad&0x3F); + if (skb_len > 1500) { + dev_info(&dev->net->dev, "drop skb_len=%x larger than 1500\n", skb_len); + goto error_pkt; + } + + if (skb_in->len < (pkt_len + sizeof(struct qmap_hdr))) { + dev_info(&dev->net->dev, "drop qmap unknow pkt, len=%d, pkt_len=%d\n", skb_in->len, pkt_len); + goto error_pkt; + } + + if (qhdr->cd_rsvd_pad & 0x80) { + dev_info(&dev->net->dev, "skip qmap command packet %x\n", qhdr->cd_rsvd_pad); + goto skip_pkt; + } + + switch (skb_in->data[sizeof(struct qmap_hdr)] & 0xf0) { + case 0x40: + protocol = htons(ETH_P_IP); + break; + case 0x60: + protocol = htons(ETH_P_IPV6); + break; + default: + dev_info(&dev->net->dev, "unknow skb->protocol %02x\n", skb_in->data[sizeof(struct qmap_hdr)]); + goto error_pkt; + } + + mux_id = qhdr->mux_id - FIBOCOM_QMAP_MUX_ID; + if (mux_id >= pQmapDev->qmap_mode) { + dev_info(&dev->net->dev, "drop qmap unknow mux_id %x\n", qhdr->mux_id); + goto error_pkt; + } + + qmap_net = pQmapDev->mpQmapNetDev[mux_id]; + + if (qmap_net == NULL) { + dev_info(&dev->net->dev, "drop qmap unknow mux_id %x\n", qhdr->mux_id); + goto skip_pkt; + } + + if (headroom >= need_headroot) { + qmap_skb = skb_clone(skb_in, GFP_ATOMIC); + if (qmap_skb) { + qmap_skb->dev = qmap_net; + skb_pull(qmap_skb, sizeof(struct qmap_hdr)); + skb_trim(qmap_skb, skb_len); + } + headroom = (qhdr->cd_rsvd_pad&0x3F); + } + else { + qmap_skb = netdev_alloc_skb(qmap_net, need_headroot + skb_len); + if (qmap_skb) { + skb_reserve(qmap_skb, need_headroot); + skb_put(qmap_skb, skb_len); + memcpy(qmap_skb->data, skb_in->data + sizeof(struct qmap_hdr), skb_len); + } + headroom = pkt_len; + } + + if (qmap_skb == NULL) { + dev_info(&dev->net->dev, "fail to alloc skb, pkt_len = %d\n", skb_len); + return 0; + } + + skb_push(qmap_skb, ETH_HLEN); + skb_reset_mac_header(qmap_skb); + memcpy(eth_hdr(qmap_skb)->h_source, default_modem_addr, ETH_ALEN); + memcpy(eth_hdr(qmap_skb)->h_dest, qmap_net->dev_addr, ETH_ALEN); + eth_hdr(qmap_skb)->h_proto = protocol; +#ifdef FIBOCOM_BRIDGE_MODE + bridge_mode_rx_fixup(pQmapDev, qmap_net, qmap_skb); +#endif + + if (qmap_net != dev->net) { + qmap_net->stats.rx_packets++; + qmap_net->stats.rx_bytes += qmap_skb->len; + } + + skb_queue_tail(&pQmapDev->skb_chain, qmap_skb); + +skip_pkt: + skb_pull(skb_in, pkt_len + sizeof(struct qmap_hdr)); + } + + while ((qmap_skb = skb_dequeue (&pQmapDev->skb_chain))) { + if (qmap_skb->dev != dev->net) { + qmap_skb->protocol = eth_type_trans (qmap_skb, qmap_skb->dev); + netif_rx(qmap_skb); + } + else { + qmap_skb->protocol = 0; + usbnet_skb_return(dev, qmap_skb); + } + } + +error_pkt: + return 0; +} +#endif + +/* very simplistic detection of IPv4 or IPv6 headers */ +static bool possibly_iphdr(const char *data) +{ + return (data[0] & 0xd0) == 0x40; +} + +/* disallow addresses which may be confused with IP headers */ +static int qmi_wwan_mac_addr(struct net_device *dev, void *p) +{ + int ret; + struct sockaddr *addr = p; + + ret = eth_prepare_mac_addr_change(dev, p); + if (ret < 0) + return ret; + if (possibly_iphdr(addr->sa_data)) + return -EADDRNOTAVAIL; + eth_commit_mac_addr_change(dev, p); + return 0; +} + +#if (LINUX_VERSION_CODE > KERNEL_VERSION( 4,10,0 )) //bc1f44709cf27fb2a5766cadafe7e2ad5e9cb221 +static void (*_usbnet_get_stats64)(struct net_device *net, struct rtnl_link_stats64 *stats); + +static void qmi_wwan_get_stats64(struct net_device *net, struct rtnl_link_stats64 *stats) { + if (_usbnet_get_stats64) ////c8b5d129ee293bcf972e7279ac996bb8a138505c + return _usbnet_get_stats64(net, stats); + + netdev_stats_to_stats64(stats, &net->stats); +} +#else +static struct rtnl_link_stats64 * (*_usbnet_get_stats64)(struct net_device *net, struct rtnl_link_stats64 *stats); + +static struct rtnl_link_stats64 * qmi_wwan_get_stats64(struct net_device *net, struct rtnl_link_stats64 *stats) { + if (_usbnet_get_stats64) + return _usbnet_get_stats64(net, stats); + + netdev_stats_to_stats64(stats, &net->stats); + return stats; +} +#endif + +static netdev_tx_t qmi_wwan_start_xmit (struct sk_buff *skb, + struct net_device *net) +{ + struct usbnet * usbnetdev = netdev_priv( net ); + struct qmi_wwan_state *info = (void *)&usbnetdev->data; + sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; + int retval; + + retval = usbnet_start_xmit(skb, net); + + if (netif_queue_stopped(net) && pQmapDev && pQmapDev->use_rmnet_usb) { + int i; + + for (i = 0; i < pQmapDev->qmap_mode; i++) { + struct net_device *qmap_net = pQmapDev->mpQmapNetDev[i]; + if (qmap_net) { + netif_stop_queue(qmap_net); + } + } + } + + return retval; +} + +static const struct net_device_ops qmi_wwan_netdev_ops = { + .ndo_open = usbnet_open, + .ndo_stop = usbnet_stop, + .ndo_start_xmit = qmi_wwan_start_xmit, + .ndo_tx_timeout = usbnet_tx_timeout, + .ndo_change_mtu = usbnet_change_mtu, + .ndo_get_stats64 = qmi_wwan_get_stats64, + .ndo_set_mac_address = qmi_wwan_mac_addr, + .ndo_validate_addr = eth_validate_addr, +#if defined(FIBOCOM_WWAN_QMAP)// && defined(CONFIG_ANDROID) + .ndo_do_ioctl = qmap_ndo_do_ioctl, +#endif +}; + +static void ql_net_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) +{ + /* Inherit standard device info */ + usbnet_get_drvinfo(net, info); + strlcpy(info->driver, driver_name, sizeof(info->driver)); + strlcpy(info->version, VERSION_NUMBER, sizeof(info->version)); +} + +static struct ethtool_ops ql_net_ethtool_ops; + +/* using a counter to merge subdriver requests with our own into a + * combined state + */ +static int qmi_wwan_manage_power(struct usbnet *dev, int on) +{ + struct qmi_wwan_state *info = (void *)&dev->data; + int rv; + + dev_dbg(&dev->intf->dev, "%s() pmcount=%d, on=%d\n", __func__, + atomic_read(&info->pmcount), on); + + if ((on && atomic_add_return(1, &info->pmcount) == 1) || + (!on && atomic_dec_and_test(&info->pmcount))) { + /* need autopm_get/put here to ensure the usbcore sees + * the new value + */ + rv = usb_autopm_get_interface(dev->intf); + dev->intf->needs_remote_wakeup = on; + if (!rv) + usb_autopm_put_interface(dev->intf); + } + return 0; +} + +static int qmi_wwan_cdc_wdm_manage_power(struct usb_interface *intf, int on) +{ + struct usbnet *dev = usb_get_intfdata(intf); + + /* can be called while disconnecting */ + if (!dev) + return 0; + return qmi_wwan_manage_power(dev, on); +} + +/* collect all three endpoints and register subdriver */ +static int qmi_wwan_register_subdriver(struct usbnet *dev) +{ + int rv; + struct usb_driver *subdriver = NULL; + struct qmi_wwan_state *info = (void *)&dev->data; + + /* collect bulk endpoints */ + rv = usbnet_get_endpoints(dev, info->data); + if (rv < 0) + goto err; + + /* update status endpoint if separate control interface */ + if (info->control != info->data) + dev->status = &info->control->cur_altsetting->endpoint[0]; + + /* require interrupt endpoint for subdriver */ + if (!dev->status) { + rv = -EINVAL; + goto err; + } + + /* for subdriver power management */ + atomic_set(&info->pmcount, 0); + + /* register subdriver */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION( 5,12,0 )) //cac6fb015f719104e60b1c68c15ca5b734f57b9c + subdriver = usb_cdc_wdm_register(info->control, &dev->status->desc, + 4096, WWAN_PORT_QMI, &qmi_wwan_cdc_wdm_manage_power); +#else + subdriver = usb_cdc_wdm_register(info->control, &dev->status->desc, + 4096, &qmi_wwan_cdc_wdm_manage_power); + +#endif + if (IS_ERR(subdriver)) { + dev_err(&info->control->dev, "subdriver registration failed\n"); + rv = PTR_ERR(subdriver); + goto err; + } + + /* prevent usbnet from using status endpoint */ + dev->status = NULL; + + /* save subdriver struct for suspend/resume wrappers */ + info->subdriver = subdriver; + +err: + return rv; +} + +static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf) +{ + int status = -1; + struct usb_driver *driver = driver_of(intf); + struct qmi_wwan_state *info = (void *)&dev->data; + + BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data) < + sizeof(struct qmi_wwan_state))); + + /* set up initial state */ + info->control = intf; + info->data = intf; + + status = qmi_wwan_register_subdriver(dev); + if (status < 0 && info->control != info->data) { + usb_set_intfdata(info->data, NULL); + usb_driver_release_interface(driver, info->data); + } + + /* Never use the same address on both ends of the link, even + * if the buggy firmware told us to. + */ + if (ether_addr_equal(dev->net->dev_addr, default_modem_addr)) + eth_hw_addr_random(dev->net); + + /* make MAC addr easily distinguishable from an IP header */ + if (possibly_iphdr(dev->net->dev_addr)) { + dev->net->dev_addr[0] |= 0x02; /* set local assignment bit */ + dev->net->dev_addr[0] &= 0xbf; /* clear "IP" bit */ + } + if (!_usbnet_get_stats64) + _usbnet_get_stats64 = dev->net->netdev_ops->ndo_get_stats64; + dev->net->netdev_ops = &qmi_wwan_netdev_ops; + + ql_net_ethtool_ops = *dev->net->ethtool_ops; + ql_net_ethtool_ops.get_drvinfo = ql_net_get_drvinfo; + dev->net->ethtool_ops = &ql_net_ethtool_ops; + +#if 1 //Added by Fibocom + if (dev->driver_info->flags & FLAG_NOARP) { + int ret; + char buf[32] = "Module"; + + ret = usb_string(dev->udev, dev->udev->descriptor.iProduct, buf, sizeof(buf)); + if (ret > 0) { + buf[ret] = '\0'; + } + + dev_err(&intf->dev, "Fibocom %s work on RawIP mode\n", buf); + dev->net->flags |= IFF_NOARP; + dev->net->flags &= ~(IFF_BROADCAST | IFF_MULTICAST); + + usb_control_msg( + interface_to_usbdev(intf), + usb_sndctrlpipe(interface_to_usbdev(intf), 0), + 0x22, //USB_CDC_REQ_SET_CONTROL_LINE_STATE + 0x21, //USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE + 1, //active CDC DTR + intf->cur_altsetting->desc.bInterfaceNumber, + NULL, 0, 100); + } + + dev->rx_urb_size = ETH_DATA_LEN + ETH_HLEN + 6; + +#if defined(FIBOCOM_WWAN_QMAP) + if (qmap_mode > FIBOCOM_WWAN_QMAP) + qmap_mode = FIBOCOM_WWAN_QMAP; + + if (!status) + { + sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)kzalloc(sizeof(sQmiWwanQmap), GFP_KERNEL); + + if (pQmapDev == NULL) + return -ENODEV; + +#ifdef FIBOCOM_BRIDGE_MODE + pQmapDev->bridge_mode = bridge_mode; +#endif + pQmapDev->mpNetDev = dev; + pQmapDev->link_state = 1; + + dev->net->features |= (NETIF_F_VLAN_CHALLENGED); + + skb_queue_head_init(&pQmapDev->skb_chain); + + if (dev->driver_info->flags & FLAG_NOARP) + { + int idProduct = le16_to_cpu(dev->udev->descriptor.idProduct); + int lte_a = (idProduct == 0x0104 || idProduct == 0x0109 || idProduct == 0x0113 || idProduct == 0x1000 || idProduct == 0x1001); + + pQmapDev->qmap_mode = qmap_mode; + if (lte_a || dev->udev->speed >= USB_SPEED_SUPER) { + if (pQmapDev->qmap_mode == 0) { + pQmapDev->qmap_mode = 1; + if(qmap_mode == 0) + qmap_mode = 1; + } + } + + if (pQmapDev->qmap_mode) { + pQmapDev->qmap_version = 5; + pQmapDev->qmap_size = (dev->udev->speed >= USB_SPEED_SUPER) ? 16*1024 : 4*1024; +/* + switch (idProduct) { + case 0x0104: + pQmapDev->qmap_version = 9; + pQmapDev->qmap_size = 31*1024; + break; + default: + break; + } +*/ + dev->rx_urb_size = pQmapDev->qmap_size; + //for these modules, if send pakcet before qmi_start_network, or cause host PC crash, or cause modules crash + if (lte_a || dev->udev->speed >= USB_SPEED_SUPER) + pQmapDev->link_state = 0; + } + +#if defined(FIBOCOM_UL_DATA_AGG) + if (pQmapDev->qmap_mode) { + struct tx_agg_ctx *ctx = &pQmapDev->tx_ctx; + ctx->ul_data_aggregation_max_datagrams = 1; + ctx->ul_data_aggregation_max_size = 1500; + } +#endif + + if (pQmapDev->qmap_mode == 0) { + pQmapDev->driver_info = *dev->driver_info; + pQmapDev->driver_info.flags &= ~(FLAG_MULTI_PACKET); //see usbnet.c rx_process() + dev->driver_info = &pQmapDev->driver_info; + } + } + + info->unused = (unsigned long)pQmapDev; + dev->net->sysfs_groups[0] = &qmi_wwan_sysfs_attr_group; + + dev_info(&intf->dev, "rx_urb_size = %zd\n", dev->rx_urb_size); + } +#endif +#endif + + return status; +} + +static void qmi_wwan_unbind(struct usbnet *dev, struct usb_interface *intf) +{ + struct qmi_wwan_state *info = (void *)&dev->data; + struct usb_driver *driver = driver_of(intf); + struct usb_interface *other; + + if (dev->udev && dev->udev->state == USB_STATE_CONFIGURED) { + usb_control_msg( + interface_to_usbdev(intf), + usb_sndctrlpipe(interface_to_usbdev(intf), 0), + 0x22, //USB_CDC_REQ_SET_CONTROL_LINE_STATE + 0x21, //USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE + 0, //deactive CDC DTR + intf->cur_altsetting->desc.bInterfaceNumber, + NULL, 0, 100); + } + + if (info->subdriver && info->subdriver->disconnect) + info->subdriver->disconnect(info->control); + + /* allow user to unbind using either control or data */ + if (intf == info->control) + other = info->data; + else + other = info->control; + + /* only if not shared */ + if (other && intf != other) { + usb_set_intfdata(other, NULL); + usb_driver_release_interface(driver, other); + } + + info->subdriver = NULL; + info->data = NULL; + info->control = NULL; +} + +/* suspend/resume wrappers calling both usbnet and the cdc-wdm + * subdriver if present. + * + * NOTE: cdc-wdm also supports pre/post_reset, but we cannot provide + * wrappers for those without adding usbnet reset support first. + */ +static int qmi_wwan_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct usbnet *dev = usb_get_intfdata(intf); + struct qmi_wwan_state *info = (void *)&dev->data; + int ret; + + /* Both usbnet_suspend() and subdriver->suspend() MUST return 0 + * in system sleep context, otherwise, the resume callback has + * to recover device from previous suspend failure. + */ + ret = usbnet_suspend(intf, message); + if (ret < 0) + goto err; + + if (intf == info->control && info->subdriver && + info->subdriver->suspend) + ret = info->subdriver->suspend(intf, message); + if (ret < 0) + usbnet_resume(intf); +err: + return ret; +} + +static int qmi_wwan_resume(struct usb_interface *intf) +{ + struct usbnet *dev = usb_get_intfdata(intf); + struct qmi_wwan_state *info = (void *)&dev->data; + int ret = 0; + bool callsub = (intf == info->control && info->subdriver && + info->subdriver->resume); + + if (callsub) + ret = info->subdriver->resume(intf); + if (ret < 0) + goto err; + ret = usbnet_resume(intf); + if (ret < 0 && callsub) + info->subdriver->suspend(intf, PMSG_SUSPEND); +err: + return ret; +} + +static int qmi_wwan_reset_resume(struct usb_interface *intf) +{ + dev_info(&intf->dev, "device do not support reset_resume\n"); + intf->needs_binding = 1; + return -EOPNOTSUPP; +} + +static int rmnet_usb_bind(struct usbnet *dev, struct usb_interface *intf) +{ + dev_err(&intf->dev, "rmnet_usb_bind\n"); + int status = qmi_wwan_bind(dev, intf); + + if (!status) { + struct qmi_wwan_state *info = (void *)&dev->data; + sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; + + if (pQmapDev && pQmapDev->qmap_mode) { + struct net_device *rmmet_usb = dev->net; + + pQmapDev->use_rmnet_usb = 1; + pQmapDev->rmnet_info.size = sizeof(RMNET_INFO); + pQmapDev->rmnet_info.rx_urb_size = pQmapDev->qmap_size; + pQmapDev->rmnet_info.ep_type = 2; //DATA_EP_TYPE_HSUSB + pQmapDev->rmnet_info.iface_id = 4; + pQmapDev->rmnet_info.qmap_mode = pQmapDev->qmap_mode; + pQmapDev->rmnet_info.qmap_version = pQmapDev->qmap_version; + pQmapDev->rmnet_info.dl_minimum_padding = 0; + + strcpy(rmmet_usb->name, "rmnet_usb%d"); + +#if 0 + rmmet_usb->header_ops = NULL; /* No header */ + rmmet_usb->type = ARPHRD_RAWIP; + rmmet_usb->hard_header_len = 0; + rmmet_usb->addr_len = 0; +#endif + rmmet_usb->flags &= ~(IFF_BROADCAST | IFF_MULTICAST); + rmmet_usb->flags |= (IFF_NOARP); + } + } + + return status; +} + +static struct sk_buff *rmnet_usb_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) +{ + //printk("%s skb=%p, len=%d, protocol=%x, hdr_len=%d\n", __func__, skb, skb->len, skb->protocol, skb->hdr_len); + if (skb->protocol != htons(ETH_P_MAP)) { + dev_kfree_skb_any(skb); + return NULL; + } + + return skb; +} + +static int rmnet_usb_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ + struct net_device *net = dev->net; + + //printk("%s skb=%p, len=%d, protocol=%x, hdr_len=%d\n", __func__, skb, skb->len, skb->protocol, skb->hdr_len); + if (net->type == ARPHRD_ETHER && skb_headroom(skb) >= ETH_HLEN) { + //usbnet.c rx_process() usbnet_skb_return() eth_type_trans() + skb_push(skb, ETH_HLEN); + skb_reset_mac_header(skb); + memcpy(eth_hdr(skb)->h_source, default_modem_addr, ETH_ALEN); + memcpy(eth_hdr(skb)->h_dest, net->dev_addr, ETH_ALEN); + eth_hdr(skb)->h_proto = htons(ETH_P_MAP); + + return 1; + } + + return 0; +} + +static void _rmnet_usb_rx_handler(struct usbnet *dev, struct sk_buff *skb_in) +{ + struct qmi_wwan_state *info = (void *)&dev->data; + sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; + struct sk_buff *qmap_skb; + struct sk_buff_head skb_chain; + uint dl_minimum_padding = 0; + + if (pQmapDev->qmap_version == 9) + dl_minimum_padding = pQmapDev->tx_ctx.dl_minimum_padding; + + __skb_queue_head_init(&skb_chain); + + while (skb_in->len > sizeof(struct qmap_hdr)) { + struct rmnet_map_header *map_header = (struct rmnet_map_header *)skb_in->data; + struct rmnet_map_v5_csum_header *ul_header = NULL; + size_t hdr_size = sizeof(struct rmnet_map_header); + struct net_device *qmap_net; + int pkt_len = ntohs(map_header->pkt_len); + int skb_len; + __be16 protocol; + int mux_id; + + if (map_header->next_hdr) { + ul_header = (struct rmnet_map_v5_csum_header *)(map_header + 1); + hdr_size += sizeof(struct rmnet_map_v5_csum_header); + } + + skb_len = pkt_len - (map_header->pad_len&0x3F); + skb_len -= dl_minimum_padding; + if (skb_len > 1500) { + dev_info(&dev->net->dev, "drop skb_len=%x larger than 1500\n", skb_len); + goto error_pkt; + } + + if (skb_in->len < (pkt_len + hdr_size)) { + dev_info(&dev->net->dev, "drop qmap unknow pkt, len=%d, pkt_len=%d\n", skb_in->len, pkt_len); + goto error_pkt; + } + + if (map_header->cd_bit) { + dev_info(&dev->net->dev, "skip qmap command packet\n"); + goto skip_pkt; + } + + switch (skb_in->data[hdr_size] & 0xf0) { + case 0x40: + protocol = htons(ETH_P_IP); + break; + case 0x60: + protocol = htons(ETH_P_IPV6); + break; + default: + dev_info(&dev->net->dev, "unknow skb->protocol %02x\n", skb_in->data[hdr_size]); + goto error_pkt; + } + + mux_id = map_header->mux_id - FIBOCOM_QMAP_MUX_ID; + if (mux_id >= pQmapDev->qmap_mode) { + dev_info(&dev->net->dev, "drop qmap unknow mux_id %x\n", map_header->mux_id); + goto error_pkt; + } + + qmap_net = pQmapDev->mpQmapNetDev[mux_id]; + + if (qmap_net == NULL) { + dev_info(&dev->net->dev, "drop qmap unknow mux_id %x\n", map_header->mux_id); + goto skip_pkt; + } + + qmap_skb = netdev_alloc_skb(qmap_net, skb_len); + if (qmap_skb) { + skb_put(qmap_skb, skb_len); + memcpy(qmap_skb->data, skb_in->data + hdr_size, skb_len); + } + + if (qmap_skb == NULL) { + dev_info(&dev->net->dev, "fail to alloc skb, pkt_len = %d\n", skb_len); + goto error_pkt; + } + + skb_reset_transport_header(qmap_skb); + skb_reset_network_header(qmap_skb); + qmap_skb->pkt_type = PACKET_HOST; + skb_set_mac_header(qmap_skb, 0); + qmap_skb->protocol = protocol; + + if (ul_header && ul_header->header_type == RMNET_MAP_HEADER_TYPE_CSUM_OFFLOAD + && ul_header->csum_valid_required) { +#if 0 //TODO + qmap_skb->ip_summed = CHECKSUM_UNNECESSARY; +#endif + } + + if (qmap_skb->dev->type == ARPHRD_ETHER) { + skb_push(qmap_skb, ETH_HLEN); + skb_reset_mac_header(qmap_skb); + memcpy(eth_hdr(qmap_skb)->h_source, default_modem_addr, ETH_ALEN); + memcpy(eth_hdr(qmap_skb)->h_dest, qmap_net->dev_addr, ETH_ALEN); + eth_hdr(qmap_skb)->h_proto = protocol; +#ifdef FIBOCOM_BRIDGE_MODE + bridge_mode_rx_fixup(pQmapDev, qmap_net, qmap_skb); +#endif + __skb_pull(qmap_skb, ETH_HLEN); + } + + rmnet_vnd_update_rx_stats(qmap_net, 1, skb_len); + __skb_queue_tail(&skb_chain, qmap_skb); + +skip_pkt: + skb_pull(skb_in, pkt_len + hdr_size); + } + +error_pkt: + while ((qmap_skb = __skb_dequeue (&skb_chain))) { + netif_receive_skb(qmap_skb); + } +} + +static rx_handler_result_t rmnet_usb_rx_handler(struct sk_buff **pskb) +{ + struct sk_buff *skb = *pskb; + struct usbnet *dev; + + if (!skb) + goto done; + + //printk("%s skb=%p, protocol=%x, len=%d\n", __func__, skb, skb->protocol, skb->len); + + if (skb->pkt_type == PACKET_LOOPBACK) + return RX_HANDLER_PASS; + + if (skb->protocol != htons(ETH_P_MAP)) { + WARN_ON(1); + return RX_HANDLER_PASS; + } + /* when open hyfi function, run cm will make system crash */ + //dev = rcu_dereference(skb->dev->rx_handler_data); + dev = netdev_priv(skb->dev); + + if (dev == NULL) { + WARN_ON(1); + return RX_HANDLER_PASS; + } + + _rmnet_usb_rx_handler(dev, skb); + consume_skb(skb); + +done: + return RX_HANDLER_CONSUMED; +} + +static const struct driver_info qmi_wwan_info = { + .description = "WWAN/QMI device", + .flags = FLAG_WWAN, + .bind = qmi_wwan_bind, + .unbind = qmi_wwan_unbind, + .manage_power = qmi_wwan_manage_power, + .rx_fixup = qmi_wwan_rx_fixup, +}; + +static const struct driver_info qmi_wwan_raw_ip_info = { + .description = "WWAN/QMI device", + .flags = FLAG_WWAN | FLAG_RX_ASSEMBLE | FLAG_NOARP | FLAG_SEND_ZLP | FLAG_MULTI_PACKET, + .bind = qmi_wwan_bind, + .unbind = qmi_wwan_unbind, + .manage_power = qmi_wwan_manage_power, +#if defined(FIBOCOM_WWAN_QMAP) + .tx_fixup = qmap_qmi_wwan_tx_fixup, + .rx_fixup = qmap_qmi_wwan_rx_fixup, +#else + .tx_fixup = qmi_wwan_tx_fixup, + .rx_fixup = qmi_wwan_rx_fixup, +#endif +}; + +static const struct driver_info rmnet_usb_info = { + .description = "RMNET/USB device", + .flags = FLAG_NOARP | FLAG_SEND_ZLP, + .bind = rmnet_usb_bind, + .unbind = qmi_wwan_unbind, + .manage_power = qmi_wwan_manage_power, + .tx_fixup = rmnet_usb_tx_fixup, + .rx_fixup = rmnet_usb_rx_fixup, +}; + +/* map QMI/wwan function by a fixed interface number */ +#define QMI_FIXED_INTF(vend, prod, num) \ + USB_DEVICE_INTERFACE_NUMBER(vend, prod, num), \ + .driver_info = (unsigned long)&qmi_wwan_info + +#define QMI_FIXED_RAWIP_INTF(vend, prod, num) \ + USB_DEVICE_INTERFACE_NUMBER(vend, prod, num), \ + .driver_info = (unsigned long)&qmi_wwan_raw_ip_info + +#define RMNET_USB_INTF(vend, prod, num) \ + USB_DEVICE_INTERFACE_NUMBER(vend, prod, num), \ + .driver_info = (unsigned long) &rmnet_usb_info + +static const struct usb_device_id products[] = { +#if 1 //Added by Fibocom + { QMI_FIXED_RAWIP_INTF(0x2cb7, 0x0104, 4) }, /* Fibocom FG150/FM150/NL952/FG101 */ + { QMI_FIXED_RAWIP_INTF(0x2cb7, 0x0109, 2) }, /* Fibocom FG150/FM150 */ + { QMI_FIXED_RAWIP_INTF(0x2cb7, 0x0113, 0) }, /* Fibocom FG101 */ + { QMI_FIXED_RAWIP_INTF(0x1508, 0x1000, 2) }, /* Fibocom NL668 */ + { QMI_FIXED_RAWIP_INTF(0x1508, 0x1001, 4) }, /* Fibocom NL668 */ + { QMI_FIXED_RAWIP_INTF(0x05c6, 0x9025, 4) }, /* Fibocom NL668 */ +#endif + { } /* END */ +}; +MODULE_DEVICE_TABLE(usb, products); + +static int qmi_wwan_probe(struct usb_interface *intf, + const struct usb_device_id *prod) +{ + struct usb_device_id *id = (struct usb_device_id *)prod; + + /* Workaround to enable dynamic IDs. This disables usbnet + * blacklisting functionality. Which, if required, can be + * reimplemented here by using a magic "blacklist" value + * instead of 0 in the static device id table + */ + if (!id->driver_info) { + dev_dbg(&intf->dev, "setting defaults for dynamic device id\n"); + id->driver_info = (unsigned long)&qmi_wwan_info; + } + + if (intf->cur_altsetting->desc.bInterfaceClass != 0xff) { + dev_info(&intf->dev, "Fibocom module not qmi_wwan mode!\n"); + return -ENODEV; + } + + return usbnet_probe(intf, id); +} + +#if defined(FIBOCOM_WWAN_QMAP) +static int qmap_qmi_wwan_probe(struct usb_interface *intf, + const struct usb_device_id *prod) +{ + int status = qmi_wwan_probe(intf, prod); + + if (!status) { + struct usbnet *dev = usb_get_intfdata(intf); + struct qmi_wwan_state *info = (void *)&dev->data; + sQmiWwanQmap *pQmapDev = (sQmiWwanQmap *)info->unused; + unsigned i; + + if (!pQmapDev) + return status; + + tasklet_init(&pQmapDev->txq, rmnet_usb_tx_wake_queue, (unsigned long)pQmapDev); + + if (pQmapDev->qmap_mode == 1) { + pQmapDev->mpQmapNetDev[0] = dev->net; + if (pQmapDev->use_rmnet_usb) { + pQmapDev->mpQmapNetDev[0] = NULL; + qmap_register_device(pQmapDev, 0); + } + } + else if (pQmapDev->qmap_mode > 1) { + for (i = 0; i < pQmapDev->qmap_mode; i++) { + qmap_register_device(pQmapDev, i); + } + } + + if (pQmapDev->use_rmnet_usb) { + rtnl_lock(); + /* when open hyfi function, run cm will make system crash */ + //netdev_rx_handler_register(dev->net, rmnet_usb_rx_handler, dev); + netdev_rx_handler_register(dev->net, rmnet_usb_rx_handler, NULL); + rtnl_unlock(); + } + + if (pQmapDev->link_state == 0) { + netif_carrier_off(dev->net); + } + } + + return status; +} + +static void qmap_qmi_wwan_disconnect(struct usb_interface *intf) +{ + struct usbnet *dev = usb_get_intfdata(intf); + struct qmi_wwan_state *info; + sQmiWwanQmap *pQmapDev; + uint i; + + if (!dev) + return; + + info = (void *)&dev->data; + pQmapDev = (sQmiWwanQmap *)info->unused; + + if (!pQmapDev) { + return usbnet_disconnect(intf); + } + + pQmapDev->link_state = 0; + + if (pQmapDev->qmap_mode > 1) { + for (i = 0; i < pQmapDev->qmap_mode; i++) { + qmap_unregister_device(pQmapDev, i); + } + } + + if (pQmapDev->use_rmnet_usb) { + qmap_unregister_device(pQmapDev, 0); + rtnl_lock(); + netdev_rx_handler_unregister(dev->net); + rtnl_unlock(); + } + + tasklet_kill(&pQmapDev->txq); + + usbnet_disconnect(intf); + info->unused = 0; + kfree(pQmapDev); +} +#endif + +static struct usb_driver qmi_wwan_driver = { + .name = "qmi_wwan_f", + .id_table = products, + .probe = qmi_wwan_probe, +#if defined(FIBOCOM_WWAN_QMAP) + .probe = qmap_qmi_wwan_probe, + .disconnect = qmap_qmi_wwan_disconnect, +#else + .probe = qmi_wwan_probe, + .disconnect = usbnet_disconnect, +#endif + .suspend = qmi_wwan_suspend, + .resume = qmi_wwan_resume, + .reset_resume = qmi_wwan_reset_resume, + .supports_autosuspend = 1, + .disable_hub_initiated_lpm = 1, +}; + +#ifdef CONFIG_QCA_NSS_DRV +/* + EXTRA_CFLAGS="-I$(STAGING_DIR)/usr/include/qca-nss-drv $(EXTRA_CFLAGS)" + qsdk/qca/src/data-kernel/drivers/rmnet-nss/rmnet_nss.c +*/ +#include "rmnet_nss.c" +#endif + +static int __init qmi_wwan_driver_init(void) +{ + RCU_INIT_POINTER(rmnet_nss_callbacks, NULL); +#ifdef CONFIG_QCA_NSS_DRV + if (qca_nss_enabled) + rmnet_nss_init(); +#endif + return usb_register(&qmi_wwan_driver); +} +module_init(qmi_wwan_driver_init); +static void __exit qmi_wwan_driver_exit(void) +{ +#ifdef CONFIG_QCA_NSS_DRV + if (qca_nss_enabled) + rmnet_nss_exit(); +#endif + usb_deregister(&qmi_wwan_driver); +} +module_exit(qmi_wwan_driver_exit); + +MODULE_AUTHOR("Bjørn Mork "); +MODULE_DESCRIPTION("Qualcomm MSM Interface (QMI) WWAN driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(FIBOCOM_WWAN_VERSION); diff --git a/package/wwan/driver/quectel_Gobinet/Makefile b/package/wwan/driver/quectel_Gobinet/Makefile index 5457008a4..abdba443e 100755 --- a/package/wwan/driver/quectel_Gobinet/Makefile +++ b/package/wwan/driver/quectel_Gobinet/Makefile @@ -15,7 +15,7 @@ include $(INCLUDE_DIR)/kernel.mk include $(INCLUDE_DIR)/package.mk define KernelPackage/gobinet - SUBMENU:=Gobinet Support + SUBMENU:=WWAN Support TITLE:=Quectel Linux USB Gobinet Driver DEPENDS:=+kmod-usb-net FILES:=$(PKG_BUILD_DIR)/GobiNet.ko diff --git a/package/wwan/driver/quectel_QMI_WWAN/Makefile b/package/wwan/driver/quectel_QMI_WWAN/Makefile index c60881d10..b27dfad76 100755 --- a/package/wwan/driver/quectel_QMI_WWAN/Makefile +++ b/package/wwan/driver/quectel_QMI_WWAN/Makefile @@ -15,7 +15,7 @@ include $(INCLUDE_DIR)/kernel.mk include $(INCLUDE_DIR)/package.mk define KernelPackage/qmi_wwan_q - SUBMENU:=qmiwwan Support + SUBMENU:=WWAN Support TITLE:=Quectel Linux USB QMI WWAN Driver DEPENDS:=+kmod-usb-net +kmod-usb-wdm FILES:=$(PKG_BUILD_DIR)/qmi_wwan_q.ko