package/wwan: remove outdated packages

This commit is contained in:
coolsnowwolf 2025-02-23 21:09:15 +08:00
parent 0608f510fc
commit 04b8d9bdd6
87 changed files with 5 additions and 26715 deletions

View File

@ -1,15 +0,0 @@
#
# 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
LUCI_TITLE:=PCI Modem Server
LUCI_DEPENDS:=+kmod-pcie_mhi +pciutils +quectel-CM-5G
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@ -1,9 +0,0 @@
module("luci.controller.pcimodem", package.seeall)
function index()
if not nixio.fs.access("/etc/config/pcimodem") then
return
end
entry({"admin", "network", "pcimodem"}, cbi("pcimodem"), _("PCI Modem Server"), 80).dependent = false
end

View File

@ -1,39 +0,0 @@
-- Copyright 2016 David Thornley <david.thornley@touchstargroup.com>
-- Licensed to the public under the Apache License 2.0.
mp = Map("pcimodem")
mp.title = translate("PCI Modem Server")
mp.description = translate("Modem Server For OpenWrt")
s = mp:section(TypedSection, "service", "Base Setting")
s.anonymous = true
enabled = s:option(Flag, "enabled", translate("Enable"))
enabled.default = 0
enabled.rmempty = false
apn = s:option(Value, "apn", translate("APN"))
apn.rmempty = true
pincode = s:option(Value, "pincode", translate("PIN"))
pincode.rmempty = true
username = s:option(Value, "username", translate("PAP/CHAP username"))
username.rmempty = true
password = s:option(Value, "password", translate("PAP/CHAP password"))
password.rmempty = true
auth = s:option(Value, "auth", translate("Authentication Type"))
auth.rmempty = true
auth:value("", translate("-- Please choose --"))
auth:value("both", "PAP/CHAP (both)")
auth:value("pap", "PAP")
auth:value("chap", "CHAP")
auth:value("none", "NONE")
tool = s:option(Value, "tool", translate("Tools"))
tool:value("quectel-CM", "quectel-CM")
tool.rmempty = true
return mp

View File

@ -1,24 +0,0 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Last-Translator: dingpengyu <dingpengyu06@gmail.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: zh_CN\n"
"X-Generator: Poedit 2.3.1\n"
msgid "Base Setting"
msgstr "基本设置"
msgid "PCI Modem Server"
msgstr "PCI移动网络拨号服务"
msgid "Modem Server For OpenWrt"
msgstr "OpenWrt移动网络拨号服务"
msgid "Tools"
msgstr "拨号工具"

View File

@ -1,4 +0,0 @@
config service
option tool 'quectel-CM'
option enabled '0'

View File

@ -1,75 +0,0 @@
#!/bin/sh /etc/rc.common
# Copyright (C) 2006-2014 OpenWrt.org
START=99
STOP=16
USE_PROCD=1
#使用procd启动
run_5g()
{
local enabled
config_get_bool enabled $1 enabled
echo "run 4G" >> /tmp/log4g
if [ "$enabled" = "1" ]; then
local user
local password
local apn
local auth
local pincode
local tool
# echo "enable 5G" >> /tmp/log5g
config_get user $1 user
config_get password $1 password
config_get apn $1 apn
config_get auth $1 auth
config_get pincode $1 pincode
config_get tool $1 tool
config_get tty $1 tty
config_get atcmd $1 atcmd
if [ "$tool" = "at" ];then
at_tool "$atcmd" -d $tty
else
procd_open_instance
#创建一个实例, 在procd看来一个应用程序可以多个实\E4\BE?
#ubus call service list 可以查看实例
procd_set_param command $tool -i rmnet_mhi0 -s $apn
if [ "$password" != "" ];then
procd_append_param command $user $password $auth
fi
if [ "$pincode" != "" ]; then
procd_append_param command -p $pincode
fi
# procd_append_param command -f /tmp/4g.log
procd_set_param respawn
echo "quectel-CM has started."
procd_close_instance
#关闭实例
fi
fi
}
service_triggers()
{
procd_add_reload_trigger "pcimodem"
}
start_service() {
config_load pcimodem
config_foreach run_5g service
}
stop_service()
{
echo "5G stop" >> /tmp/log5g
killall quectel-CM
echo "quectel-CM has stoped."
}

View File

@ -1,11 +0,0 @@
#!/bin/sh
uci -q batch <<-EOF >/dev/null
delete ucitrack.@pcimodem[-1]
add ucitrack pcimodem
set ucitrack.@pcimodem[-1].init=pcimodem
commit ucitrack
EOF
rm -f /tmp/luci-indexcache
exit 0

View File

@ -1,19 +0,0 @@
#
# 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
LUCI_TITLE:=Modem Server
LUCI_DEPENDS:=+luci-compat +quectel-CM-5G +kmod-usb-acm \
+kmod-usb-net-cdc-ether +kmod-usb-net-cdc-mbim \
+kmod-usb-net-qmi-wwan +kmod-usb-net-rndis \
+kmod-usb-serial-option +kmod-usb-wdm \
+kmod-qmi_wwan_f +kmod-qmi_wwan_q
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature

View File

@ -1,9 +0,0 @@
module("luci.controller.usbmodem", package.seeall)
function index()
if not nixio.fs.access("/etc/config/usbmodem") then
return
end
entry({"admin", "network", "usbmodem"}, cbi("usbmodem"), _("USB Modem Server"), 80).dependent = false
end

View File

@ -1,51 +0,0 @@
-- Copyright 2016 David Thornley <david.thornley@touchstargroup.com>
-- Licensed to the public under the Apache License 2.0.
mp = Map("usbmodem")
mp.title = translate("USB Modem Server")
mp.description = translate("Modem Server For OpenWrt")
s = mp:section(TypedSection, "service", "Base Setting")
s.anonymous = true
enabled = s:option(Flag, "enabled", translate("Enable"))
enabled.default = 0
enabled.rmempty = false
device = s:option(Value, "device", translate("Modem device"))
device.rmempty = false
local device_suggestions = nixio.fs.glob("/dev/cdc-wdm*")
if device_suggestions then
local node
for node in device_suggestions do
device:value(node)
end
end
apn = s:option(Value, "apn", translate("APN"))
apn.rmempty = true
pincode = s:option(Value, "pincode", translate("PIN"))
pincode.rmempty = true
username = s:option(Value, "username", translate("PAP/CHAP username"))
username.rmempty = true
password = s:option(Value, "password", translate("PAP/CHAP password"))
password.rmempty = true
auth = s:option(Value, "auth", translate("Authentication Type"))
auth.rmempty = true
auth:value("", translate("-- Please choose --"))
auth:value("both", "PAP/CHAP (both)")
auth:value("pap", "PAP")
auth:value("chap", "CHAP")
auth:value("none", "NONE")
tool = s:option(Value, "tool", translate("Tools"))
tool:value("quectel-CM", "quectel-CM")
tool.rmempty = true
return mp

View File

@ -1,24 +0,0 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Last-Translator: dingpengyu <dingpengyu06@gmail.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: zh_CN\n"
"X-Generator: Poedit 2.3.1\n"
msgid "Base Setting"
msgstr "基本设置"
msgid "USB Modem Server"
msgstr "USB移动网络拨号服务"
msgid "Modem Server For OpenWrt"
msgstr "OpenWrt移动网络拨号服务"
msgid "Tools"
msgstr "拨号工具"

View File

@ -1,5 +0,0 @@
config service
option tool 'quectel-CM'
option device '/dev/cdc-wdm0'
option enabled '0'

View File

@ -1,80 +0,0 @@
#!/bin/sh /etc/rc.common
# Copyright (C) 2006-2014 OpenWrt.org
START=99
STOP=16
USE_PROCD=1
#使用procd启动
run_4g()
{
local enabled
config_get_bool enabled $1 enabled
echo "run 4G" >> /tmp/log4g
if [ "$enabled" = "1" ]; then
local user
local password
local apn
local auth
local pincode
local device
local tool
# echo "enable 4G" >> /tmp/log4g
config_get user $1 user
config_get password $1 password
config_get apn $1 apn
config_get auth $1 auth
config_get pincode $1 pincode
config_get device $1 device
config_get tool $1 tool
config_get tty $1 tty
config_get atcmd $1 atcmd
devname="$(basename "$device")"
devpath="$(readlink -f /sys/class/usbmisc/$devname/device/)"
ifname="$( ls "$devpath"/net )"
if [ "$tool" = "at" ];then
at_tool "$atcmd" -d $tty
else
procd_open_instance
#创建一个实例, 在procd看来一个应用程序可以多个实\E4\BE?
#ubus call service list 可以查看实例
procd_set_param command $tool -i $ifname -s $apn
if [ "$password" != "" ];then
procd_append_param command $user $password $auth
fi
if [ "$pincode" != "" ]; then
procd_append_param command -p $pincode
fi
# procd_append_param command -f /tmp/4g.log
procd_set_param respawn
echo "quectel-CM has started."
procd_close_instance
#关闭实例
fi
fi
}
service_triggers()
{
procd_add_reload_trigger "usbmodem"
}
start_service() {
config_load usbmodem
config_foreach run_4g service
}
stop_service()
{
echo "4G stop" >> /tmp/log4g
killall quectel-CM
echo "quectel-CM has stoped."
}

View File

@ -1,11 +0,0 @@
#!/bin/sh
uci -q batch <<-EOF >/dev/null
delete ucitrack.@usbmodem[-1]
add ucitrack usbmodem
set ucitrack.@usbmodem[-1].init=usbmodem
commit ucitrack
EOF
rm -f /tmp/luci-indexcache
exit 0

View File

@ -1,39 +0,0 @@
include $(TOPDIR)/rules.mk
PKG_NAME:= quectel-CM-5G
PKG_VERSION:=1.6.5
PKG_RELEASE:=1
include $(INCLUDE_DIR)/package.mk
define Package/quectel-CM-5G
SECTION:=utils
CATEGORY:=Utilities
TITLE:=quectel-CM-5G app
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Build/Compile
$(MAKE) -C "$(PKG_BUILD_DIR)" \
EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \
CROSS_COMPILE="$(TARGET_CROSS)" \
ARCH="$(LINUX_KARCH)" \
M="$(PKG_BUILD_DIR)" \
CC="$(TARGET_CC)"
endef
define Package/quectel-CM-5G/install
$(INSTALL_DIR) $(1)/usr/bin $(1)/lib/netifd/proto
$(INSTALL_BIN) $(PKG_BUILD_DIR)/quectel-CM $(1)/usr/bin
$(INSTALL_BIN) ./files/rmnet_init.sh $(1)/lib/netifd
$(INSTALL_BIN) ./files/rmnet.script $(1)/lib/netifd
$(INSTALL_BIN) ./files/rmnet.sh $(1)/lib/netifd/proto
$(INSTALL_BIN) ./files/rmnet6.sh $(1)/lib/netifd/proto
$(INSTALL_BIN) ./files/rmnet6.script $(1)/lib/netifd
endef
$(eval $(call BuildPackage,quectel-CM-5G))

View File

@ -1,48 +0,0 @@
config dnsmasq
option domainneeded '1'
option boguspriv '1'
option filterwin2k '0'
option localise_queries '1'
option rebind_protection '1'
option rebind_localhost '1'
option local '/lan/'
option domain 'lan'
option expandhosts '1'
option nonegcache '0'
option authoritative '1'
option readethers '1'
option leasefile '/tmp/dhcp.leases'
option resolvfile '/tmp/resolv.conf.auto'
option nonwildcard '1'
option localservice '1'
config dhcp 'lan'
option interface 'lan'
option start '100'
option limit '150'
option leasetime '12h'
option ra 'relay'
option dhcpv6 'disabled'
option ndp 'relay'
config dhcp 'wan'
option interface 'wan'
option ignore '1'
option ra 'relay'
option dhcpv6 'disabled'
option ndp 'relay'
option ndproxy_routing '0'
option master '1'
config dhcp 'wan6'
option ra 'relay'
option dhcpv6 'disabled'
option ndp 'relay'
option ndproxy_routing '0'
option master '1'
option interface 'wan6'
config odhcpd 'odhcpd'
option loglevel '7'

View File

@ -1,66 +0,0 @@
#!/bin/sh
# Copyright (c) 2019 Qualcomm Technologies, Inc.
# All Rights Reserved.
# Confidential and Proprietary - Qualcomm Technologies, Inc.
[ -z "$1" ] && echo "Error: should be run by rmnet" && exit 1
[ -z "$2" ] && echo "Error: should be run by rmnet" && exit 1
. /lib/functions.sh
. /lib/functions/network.sh
. /lib/netifd/netifd-proto.sh
setup_interface() {
INTERFACE=$1
CONFIG=/tmp/rmnet_$2_ipv4config
logger "rmnet setup_interface $1 $2 here"
#Fetch information from lower.
[ -f ${CONFIG} ] || {
proto_notify_error "$INTERFACE" "RMNET data call Not ready"
proto_block_restart "$INTERFACE"
return
}
. ${CONFIG}
ip=$PUBLIC_IP
DNS=$DNSSERVERS
router=$GATEWAY
subnet=$NETMASK
interface=$IFNAME
#Send the information to the netifd
proto_init_update "$interface" 1 1
#ip and subnet
proto_add_ipv4_address "$ip" "${subnet:-255.255.255.0}"
#Any router? if not, remove below scripts
#router format should be separated by space
for i in $router; do
proto_add_ipv4_route "$i" 32 "" "$ip"
proto_add_ipv4_route 0.0.0.0 0 "$i" "$ip"
done
#dns information tell the netifd.
for dns in $DNS; do
proto_add_dns_server "$dns"
done
#Domain information tell the netifd
for domain in $domain; do
proto_add_dns_search "$domain"
done
#proto_add_data
[ -n "$ZONE" ] && json_add_string zone "$ZONE"
proto_close_data
proto_send_update "$INTERFACE"
}
case "$1" in
renew)
setup_interface $2 $3
;;
esac
exit 0

View File

@ -1,32 +0,0 @@
#!/bin/sh
# Copyright (c) 2019 Qualcomm Technologies, Inc.
# All Rights Reserved.
# Confidential and Proprietary - Qualcomm Technologies, Inc.
. /lib/functions.sh
. /lib/functions/network.sh
. ../netifd-proto.sh
init_proto "$@"
proto_rmnet_setup() {
local cfg="$1"
local iface="$2"
logger "rmnet started"
#Call rmnet management script below!!
logger "rmnet updated ${cfg} ${iface}"
/lib/netifd/rmnet.script renew $cfg $iface
}
proto_rmnet_teardown() {
local cfg="$1"
#Tear down rmnet manager script here.*/
}
proto_rmnet_init_config() {
#ddno_device=1
available=1
}
add_protocol rmnet

View File

@ -1,61 +0,0 @@
#!/bin/sh
# Copyright (c) 2019 Qualcomm Technologies, Inc.
# All Rights Reserved.
# Confidential and Proprietary - Qualcomm Technologies, Inc.
[ -z "$1" ] && echo "Error: should be run by rmnet" && exit 1
[ -z "$2" ] && echo "Error: should be run by rmnet" && exit 1
. /lib/functions.sh
. /lib/functions/network.sh
. /lib/netifd/netifd-proto.sh
setup_interface() {
INTERFACE=$1
CONFIG=/tmp/rmnet_$2_ipv6config
logger "rmnet setup_interface $1 $2 here"
#Fetch information from lower.
[ -f ${CONFIG} ] || {
proto_notify_error "$INTERFACE" "RMNET data call NOT ready"
proto_block_restart "$INTERFACE"
return
}
. ${CONFIG}
ADDRESSES=$PUBLIC_IP
interface=$IFNAME
#Send the information to the netifd
proto_init_update "$interface" 1 1
#ip and subnet
proto_add_ipv6_address "${PUBLIC_IP}" "128"
proto_add_ipv6_prefix "${PUBLIC_IP}/${PrefixLength}"
#router format should be separated by space
proto_add_ipv6_route "$GATEWAY" 128
proto_add_ipv6_route "::0" 0 "$GATEWAY" "" "" "${PUBLIC_IP}/${PrefixLength}"
#dns information tell the netifd.
for dns in $DNSSERVERS; do
proto_add_dns_server "$dns"
done
#Domain information tell the netifd
for domain in $domain; do
proto_add_dns_search "$domain"
done
#proto_add_data
[ -n "$ZONE" ] && json_add_string zone "$ZONE"
proto_close_data
proto_send_update "$INTERFACE"
}
case "$1" in
renew|bound)
setup_interface $2 $3
;;
esac
exit 0

View File

@ -1,32 +0,0 @@
#!/bin/sh
# Copyright (c) 2019 Qualcomm Technologies, Inc.
# All Rights Reserved.
# Confidential and Proprietary - Qualcomm Technologies, Inc.
. /lib/functions.sh
. /lib/functions/network.sh
. ../netifd-proto.sh
init_proto "$@"
proto_rmnet6_setup() {
local cfg="$1"
local iface="$2"
logger "rmnet6 started"
#Call rmnet management script below!!
/lib/netifd/rmnet6.script renew $cfg $iface
logger "rmnet6 updated"
}
proto_rmnet6_teardown() {
local cfg="$1"
#Tear down rmnet manager script here.*/
}
proto_rmnet6_init_config() {
#ddno_device=1
available=1
}
add_protocol rmnet6

View File

@ -1,31 +0,0 @@
#!/bin/sh
uci set network.wan='interface'
uci set network.wan.ifname='wwan0'
uci set network.wan.proto='rmnet'
uci set network.wan6='interface'
uci set network.wan6.ifname='wwan0'
uci set network.wan6.proto='rmnet6'
uci set dhcp.lan.ra='relay'
uci set dhcp.lan.dhcpv6='disabled'
uci set dhcp.lan.ndp='relay'
uci set dhcp.wan.ra='relay'
uci set dhcp.wan.dhcpv6='disabled'
uci set dhcp.wan.ndp='relay'
uci set dhcp.wan.ndproxy_routing='0'
uci set dhcp.wan6=dhcp
uci set dhcp.wan6.interface='wan6'
uci set dhcp.wan6.ra='relay'
uci set dhcp.wan6.dhcpv6='disabled'
uci set dhcp.wan6.ndp='relay'
uci set dhcp.wan6.ndproxy_routing='0'
uci set dhcp.wan6.master='1'
uci set dhcp.odhcpd=odhcpd
uci set dhcp.odhcpd.loglevel='7'
uci commit

View File

@ -1,36 +0,0 @@
cmake_minimum_required(VERSION 2.4)
project(quectel-CM)
add_definitions(-Wall -Wextra -Werror -O1)
option(USE_QRTR "Enable QRTR" OFF)
set( QL_CM_SRC
QmiWwanCM.c GobiNetCM.c main.c MPQMUX.c QMIThread.c util.c qmap_bridge_mode.c mbim-cm.c device.c
atc.c atchannel.c at_tok.c
udhcpc.c
)
if(USE_QRTR)
add_definitions(-DCONFIG_QRTR)
set( QRTR_SRC qrtr.c rmnetctl.c)
endif()
add_executable(quectel-CM ${QL_CM_SRC} ${QRTR_SRC})
target_link_libraries(quectel-CM PUBLIC pthread)
install (TARGETS quectel-CM DESTINATION bin)
add_executable(quectel-qmi-proxy quectel-qmi-proxy.c)
target_link_libraries(quectel-qmi-proxy PUBLIC pthread)
install (TARGETS quectel-qmi-proxy DESTINATION bin)
add_executable(quectel-mbim-proxy quectel-mbim-proxy.c)
target_link_libraries(quectel-mbim-proxy PUBLIC pthread)
install (TARGETS quectel-mbim-proxy DESTINATION bin)
add_executable(quectel-atc-proxy quectel-atc-proxy.c atchannel.c at_tok.c util.c)
target_link_libraries(quectel-atc-proxy PUBLIC pthread)
install (TARGETS quectel-atc-proxy DESTINATION bin)
add_executable(quectel-qrtr-proxy quectel-qrtr-proxy.c)
target_link_libraries(quectel-qrtr-proxy PUBLIC pthread)
install (TARGETS quectel-qrtr-proxy DESTINATION bin)

View File

@ -1,246 +0,0 @@
/******************************************************************************
@file GobiNetCM.c
@brief GobiNet driver.
DESCRIPTION
Connectivity Management Tool for USB network adapter of Quectel wireless cellular modules.
INITIALIZATION AND SEQUENCING REQUIREMENTS
None.
---------------------------------------------------------------------------
Copyright (c) 2016 - 2023 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
Quectel Wireless Solution Proprietary and Confidential.
---------------------------------------------------------------------------
******************************************************************************/
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <stdio.h>
#include <ctype.h>
#include "QMIThread.h"
#ifdef CONFIG_GOBINET
static int qmiclientId[QMUX_TYPE_ALL];
// 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;
fd = qmiclientId[pRequest->QMIHdr.QMIType];
pRequest->QMIHdr.ClientId = (fd&0xFF) ? fd&0xFF : pRequest->QMIHdr.QMIType;
if (fd <= 0) {
dbg_time("%s QMIType: %d has no clientID", __func__, pRequest->QMIHdr.QMIType);
return -ENODEV;
}
// Always ready to 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;
} else {
dbg_time("%s write=%d, errno: %d (%s)", __func__, ret, errno, strerror(errno));
}
} 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 = cm_open_dev(qcqmi);
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;
}
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_COEX: dbg_time("Get clientCOEX = %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;
qmiclientId[QMUX_TYPE_WDS] = GobiNetGetClientID(qcqmi, QMUX_TYPE_WDS);
if (profile->enable_ipv6)
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);
#ifdef CONFIG_COEX_WWAN_STATE
qmiclientId[QMUX_TYPE_COEX] = GobiNetGetClientID(qcqmi, QMUX_TYPE_COEX);
#endif
if (profile->qmap_mode == 0 || profile->loopback_state) {//when QMAP enabled, set data format in GobiNet Driver
qmiclientId[QMUX_TYPE_WDS_ADMIN] = GobiNetGetClientID(qcqmi, QMUX_TYPE_WDS_ADMIN);
profile->wda_client = qmiclientId[QMUX_TYPE_WDS_ADMIN];
}
//donot check clientWDA, there is only one client for WDA, if quectel-CM is killed by SIGKILL, i cannot get client ID for WDA again!
if (qmiclientId[QMUX_TYPE_WDS] == 0) /*|| (clientWDA == -1)*/ {
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 SIG_EVENT_STOP:
wait_for_request_quit = 1;
break;
default:
break;
}
}
continue;
}
{
ssize_t nreads;
PQCQMIMSG pResponse = (PQCQMIMSG)cm_recv_buf;
nreads = read(fd, &pResponse->MUXMsg, sizeof(cm_recv_buf) - 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) ? fd&0xFF : pResponse->QMIHdr.QMIType;;
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;
}
const struct qmi_device_ops gobi_qmidev_ops = {
.deinit = GobiNetDeInit,
.send = GobiNetSendQMI,
.read = GobiNetThread,
};
#endif

View File

@ -1,46 +0,0 @@
ifneq ($(CROSS_COMPILE),)
CROSS-COMPILE:=$(CROSS_COMPILE)
endif
#CROSS-COMPILE:=/workspace/buildroot/buildroot-qemu_mips_malta_defconfig/output/host/usr/bin/mips-buildroot-linux-uclibc-
#CROSS-COMPILE:=/workspace/buildroot/buildroot-qemu_arm_vexpress_defconfig/output/host/usr/bin/arm-buildroot-linux-uclibcgnueabi-
#CROSS-COMPILE:=/workspace/buildroot-git/qemu_mips64_malta/output/host/usr/bin/mips-gnu-linux-
ifeq ($(CC),cc)
CC:=$(CROSS-COMPILE)gcc
endif
LD:=$(CROSS-COMPILE)ld
QL_CM_SRC=QmiWwanCM.c GobiNetCM.c main.c QCQMUX.c QMIThread.c util.c qmap_bridge_mode.c mbim-cm.c device.c
QL_CM_SRC+=atc.c atchannel.c at_tok.c
#QL_CM_SRC+=qrtr.c rmnetctl.c
ifeq (1,1)
QL_CM_DHCP=udhcpc.c
else
LIBMNL=libmnl/ifutils.c libmnl/attr.c libmnl/callback.c libmnl/nlmsg.c libmnl/socket.c
DHCP=libmnl/dhcp/dhcpclient.c libmnl/dhcp/dhcpmsg.c libmnl/dhcp/packet.c
QL_CM_DHCP=udhcpc_netlink.c
QL_CM_DHCP+=${LIBMNL}
endif
CFLAGS += -Wall -Wextra -Werror -O1 #-s
LDFLAGS += -lpthread -ldl -lrt
release: clean qmi-proxy mbim-proxy atc-proxy #qrtr-proxy
$(CC) ${CFLAGS} ${QL_CM_SRC} ${QL_CM_DHCP} -o quectel-CM ${LDFLAGS}
debug: clean
$(CC) ${CFLAGS} -g -DCM_DEBUG ${QL_CM_SRC} ${QL_CM_DHCP} -o quectel-CM -lpthread -ldl -lrt
qmi-proxy:
$(CC) ${CFLAGS} quectel-qmi-proxy.c -o quectel-qmi-proxy ${LDFLAGS}
mbim-proxy:
$(CC) ${CFLAGS} quectel-mbim-proxy.c -o quectel-mbim-proxy ${LDFLAGS}
qrtr-proxy:
$(CC) ${CFLAGS} quectel-qrtr-proxy.c -o quectel-qrtr-proxy ${LDFLAGS}
atc-proxy:
$(CC) ${CFLAGS} quectel-atc-proxy.c atchannel.c at_tok.c util.c -o quectel-atc-proxy ${LDFLAGS}
clean:
rm -rf *.o libmnl/*.o quectel-CM quectel-qmi-proxy quectel-mbim-proxy quectel-atc-proxy

View File

@ -1,22 +0,0 @@
bin_PROGRAMS = quectel-CM
QL_CM_SRC=QmiWwanCM.c GobiNetCM.c main.c MPQMUX.c QMIThread.c util.c qmap_bridge_mode.c mbim-cm.c device.c
QL_CM_SRC+=atc.c atchannel.c at_tok.c
#QL_CM_SRC+=qrtr.c rmnetctl.c
QL_CM_DHCP=udhcpc.c
if USE_QRTR
quectel_CM_CFLAGS = -DCONFIG_QRTR
QL_CM_SRC += qrtr.c rmnetctl.c
if USE_MSM_IPC
quectel_CM_CFLAGS += -DUSE_LINUX_MSM_IPC
endif
endif
quectel_CM_SOURCES = ${QL_CM_SRC} ${QL_CM_DHCP}
bin_PROGRAMS += quectel-qmi-proxy
quectel_qmi_proxy_SOURCES = quectel-qmi-proxy.c
bin_PROGRAMS += quectel-mbim-proxy
quectel_mbim_proxy_SOURCES = quectel-mbim-proxy.c
LIBS = -l pthread
CFLAGS = -Wall -Wextra -Werror -O1

View File

@ -1,7 +0,0 @@
This program is totally open souce code, and public domain software for customers of Quectel company.
The APIs of QMI WWAMN interfaces are defined by Qualcomm. And this program complies with Qualcomm QMI WWAN interfaces specification.
Customers are free to modify the source codes and redistribute them.
For those who is not Quectel's customer, all rights are closed, and any copying and commercial development over this progrma is not allowed.

View File

@ -1,394 +0,0 @@
/******************************************************************************
@file QCQCTL.h
DESCRIPTION
This module contains QMI QCTL module.
INITIALIZATION AND SEQUENCING REQUIREMENTS
None.
---------------------------------------------------------------------------
Copyright (c) 2016 - 2023 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
Quectel Wireless Solution Proprietary and Confidential.
---------------------------------------------------------------------------
******************************************************************************/
#ifndef QCQCTL_H
#define QCQCTL_H
#include "QCQMI.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 QMI_MESSAGE_CTL_INTERNAL_PROXY_OPEN 0xFF00
#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_LIBQMI_PROXY_OPEN_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
char device_path[0]; // result code
} __attribute__ ((packed)) QMICTL_LIBQMI_PROXY_OPEN_MSG, *PQMICTL_LIBQMI_PROXY_OPEN_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;
QMICTL_LIBQMI_PROXY_OPEN_MSG LibQmiProxyOpenReq;
};
} __attribute__ ((packed)) QMICTL_MSG, *PQMICTL_MSG;
#pragma pack(pop)
#endif //QCQCTL_H

View File

@ -1,320 +0,0 @@
/******************************************************************************
@file QCQMI.h
DESCRIPTION
This module contains QMI module.
INITIALIZATION AND SEQUENCING REQUIREMENTS
None.
---------------------------------------------------------------------------
Copyright (c) 2016 - 2023 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
Quectel Wireless Solution Proprietary and Confidential.
---------------------------------------------------------------------------
******************************************************************************/
#ifndef USBQMI_H
#define USBQMI_H
typedef uint8_t uint8;
typedef int8_t int8;
typedef uint16_t uint16;
typedef int16_t int16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef signed char CHAR;
typedef unsigned char UCHAR;
typedef short SHORT;
typedef unsigned short USHORT;
typedef int INT;
typedef unsigned int UINT;
typedef long LONG;
typedef unsigned int ULONG;
typedef unsigned long long ULONG64;
typedef signed 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_COEX = 0x22,
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;
typedef struct _QMI_TLV
{
UCHAR TLVType;
USHORT TLVLength;
union {
int8_t s8;
uint8_t u8;
int16_t s16;
uint16_t u16;
int32_t s32;
uint32_t u32;
uint64_t u64;
};
} __attribute__ ((packed)) QMI_TLV, *PQMI_TLV;
// 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

View File

@ -1,477 +0,0 @@
/******************************************************************************
@file MPQMUX.c
@brief QMI mux.
DESCRIPTION
Connectivity Management Tool for USB network adapter of Quectel wireless cellular modules.
INITIALIZATION AND SEQUENCING REQUIREMENTS
None.
---------------------------------------------------------------------------
Copyright (c) 2016 - 2023 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
Quectel Wireless Solution Proprietary and Confidential.
---------------------------------------------------------------------------
******************************************************************************/
#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}
#if 0
static const QMI_NAME_T qmi_IFType[] = {
{USB_CTL_MSG_TYPE_QMI, "USB_CTL_MSG_TYPE_QMI"},
};
static const QMI_NAME_T qmi_CtlFlags[] = {
qmi_name_item(QMICTL_CTL_FLAG_CMD),
qmi_name_item(QCQMI_CTL_FLAG_SERVICE),
};
static const QMI_NAME_T qmi_QMIType[] = {
qmi_name_item(QMUX_TYPE_CTL),
qmi_name_item(QMUX_TYPE_WDS),
qmi_name_item(QMUX_TYPE_DMS),
qmi_name_item(QMUX_TYPE_NAS),
qmi_name_item(QMUX_TYPE_QOS),
qmi_name_item(QMUX_TYPE_WMS),
qmi_name_item(QMUX_TYPE_PDS),
qmi_name_item(QMUX_TYPE_WDS_ADMIN),
qmi_name_item(QMUX_TYPE_COEX),
};
static const QMI_NAME_T qmi_ctl_CtlFlags[] = {
qmi_name_item(QMICTL_FLAG_REQUEST),
qmi_name_item(QMICTL_FLAG_RESPONSE),
qmi_name_item(QMICTL_FLAG_INDICATION),
};
#endif
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
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_qos_Type[] = {
qmi_name_item( QMI_QOS_SET_EVENT_REPORT_REQ), // 0x0001
qmi_name_item( QMI_QOS_SET_EVENT_REPORT_RESP), // 0x0001
qmi_name_item( QMI_QOS_SET_EVENT_REPORT_IND), // 0x0001
qmi_name_item( QMI_QOS_BIND_DATA_PORT_REQ), // 0x002B
qmi_name_item( QMI_QOS_BIND_DATA_PORT_RESP), // 0x002B
qmi_name_item( QMI_QOS_INDICATION_REGISTER_REQ), // 0x002F
qmi_name_item( QMI_QOS_INDICATION_REGISTER_RESP), // 0x002F
qmi_name_item( QMI_QOS_GLOBAL_QOS_FLOW_IND), // 0x0031
qmi_name_item( QMI_QOS_GET_QOS_INFO_REQ), // 0x0033
qmi_name_item( QMI_QOS_GET_QOS_INFO_RESP), // 0x0033
};
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_CELL_LOCATION_INFO_REQ),
qmi_name_item(QMINAS_GET_CELL_LOCATION_INFO_RESP),
qmi_name_item(QMINAS_GET_PLMN_NAME_REQ), // 0x0044
qmi_name_item(QMINAS_GET_PLMN_NAME_RESP), // 0x0044
qmi_name_item(QUECTEL_PACKET_TRANSFER_START_IND), // 0X100
qmi_name_item(QUECTEL_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
qmi_name_item(QMINAS_GET_SIG_INFO_REQ),
qmi_name_item(QMINAS_GET_SIG_INFO_RESP),
};
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
qmi_name_item(QMI_WDA_SET_LOOPBACK_CONFIG_REQ), // 0x002F
qmi_name_item(QMI_WDA_SET_LOOPBACK_CONFIG_RESP), // 0x002F
qmi_name_item(QMI_WDA_SET_LOOPBACK_CONFIG_IND), // 0x002F
};
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 QMI_NAME_T qmux_coex_Type[] = {
qmi_name_item(QMI_COEX_GET_WWAN_STATE_REQ), // 0x0022
qmi_name_item(QMI_COEX_GET_WWAN_STATE_RESP), // 0x0022
};
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);
const 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:
case QMUX_TYPE_WDS_IPV6:
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:
dbg("Type: %04x\t%s\n", le16_to_cpu(QMUXMsgHdr->Type),
QMUX_NAME(qmux_qos_Type, le16_to_cpu(QMUXMsgHdr->Type), tag));
break;
case QMUX_TYPE_COEX:
dbg("Type: %04x\t%s\n", le16_to_cpu(QMUXMsgHdr->Type),
QMUX_NAME(qmux_coex_Type, le16_to_cpu(QMUXMsgHdr->Type), tag));
break;
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);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,423 +0,0 @@
#ifndef __QMI_THREAD_H__
#define __QMI_THREAD_H__
#define CONFIG_GOBINET
#define CONFIG_QMIWWAN
#define CONFIG_SIM
#define CONFIG_APN
#define CONFIG_VERSION
//#define CONFIG_SIGNALINFO
//#define CONFIG_CELLINFO
//#define CONFIG_COEX_WWAN_STATE
#define CONFIG_DEFAULT_PDP 1
//#define CONFIG_IMSI_ICCID
#define QUECTEL_UL_DATA_AGG
//#define QUECTEL_QMI_MERGE
//#define REBOOT_SIM_CARD_WHEN_APN_CHANGE
//#define REBOOT_SIM_CARD_WHEN_LONG_TIME_NO_PS 60 //unit is seconds
//#define CONFIG_QRTR
//#define CONFIG_ENABLE_QOS
//#define CONFIG_REG_QOS_IND
//#define CONFIG_GET_QOS_INFO
//#define CONFIG_GET_QOS_DATA_RATE
#if (defined(CONFIG_REG_QOS_IND) || defined(CONFIG_GET_QOS_INFO) || defined(CONFIG_GET_QOS_DATA_RATE))
#ifndef CONFIG_REG_QOS_IND
#define CONFIG_REG_QOS_IND
#endif
#ifndef CONFIG_ENABLE_QOS
#define CONFIG_ENABLE_QOS
#endif
#endif
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/epoll.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <stddef.h>
#include "qendian.h"
#include "QCQMI.h"
#include "QCQCTL.h"
#include "QCQMUX.h"
#include "util.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
#define WWAN_DATA_CLASS_5G_NSA 0x00000040
#define WWAN_DATA_CLASS_5G_SA 0x00000080
#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;
const char *str;
};
#pragma pack(push, 1)
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;
typedef struct {
UINT size;
UINT rx_urb_size;
UINT ep_type;
UINT iface_id;
UINT MuxId;
UINT ul_data_aggregation_max_datagrams; //0x17
UINT ul_data_aggregation_max_size ;//0x18
UINT dl_minimum_padding; //0x1A
} QMAP_SETTING;
//Configured downlink data aggregationprotocol
#define WDA_DL_DATA_AGG_DISABLED (0x00) //DL data aggregation is disabled (default)
#define WDA_DL_DATA_AGG_TLP_ENABLED (0x01) // DL TLP is enabled
#define WDA_DL_DATA_AGG_QC_NCM_ENABLED (0x02) // DL QC_NCM isenabled
#define WDA_DL_DATA_AGG_MBIM_ENABLED (0x03) // DL MBIM isenabled
#define WDA_DL_DATA_AGG_RNDIS_ENABLED (0x04) // DL RNDIS is enabled
#define WDA_DL_DATA_AGG_QMAP_ENABLED (0x05) // DL QMAP isenabled
#define WDA_DL_DATA_AGG_QMAP_V2_ENABLED (0x06) // DL QMAP V2 is enabled
#define WDA_DL_DATA_AGG_QMAP_V3_ENABLED (0x07) // DL QMAP V3 is enabled
#define WDA_DL_DATA_AGG_QMAP_V4_ENABLED (0x08) // DL QMAP V4 is enabled
#define WDA_DL_DATA_AGG_QMAP_V5_ENABLED (0x09) // DL QMAP V5 is enabled
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;
#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);
};
#ifdef CONFIG_QRTR
extern const struct qmi_device_ops qrtr_qmidev_ops;
#endif
extern const struct qmi_device_ops gobi_qmidev_ops;
extern const struct qmi_device_ops qmiwwan_qmidev_ops;
extern const struct qmi_device_ops mbim_dev_ops;
extern const struct qmi_device_ops atc_dev_ops;
extern int (*qmidev_send)(PQCQMIMSG pRequest);
struct usb_device_info {
int idVendor;
int idProduct;
int busnum;
int devnum;
int bNumInterfaces;
};
struct usb_interface_info {
int bNumEndpoints;
int bInterfaceClass;
int bInterfaceSubClass;
int bInterfaceProtocol;
char driver[32];
};
#define LIBQMI_PROXY "qmi-proxy" //src/libqmi-glib/qmi-proxy.h
#define LIBMBIM_PROXY "mbim-proxy"
#define QUECTEL_QMI_PROXY "quectel-qmi-proxy"
#define QUECTEL_MBIM_PROXY "quectel-mbim-proxy"
#define QUECTEL_ATC_PROXY "quectel-atc-proxy"
#define QUECTEL_QRTR_PROXY "quectel-qrtr-proxy"
#ifndef bool
#define bool uint8_t
#endif
struct request_ops;
typedef struct __PROFILE {
//user input start
const char *apn;
const char *user;
const char *password;
int auth;
int iptype;
const char *pincode;
char proxy[32];
int pdp;//pdp_context
int profile_index;//profile_index
int enable_bridge;
bool enable_ipv4;
bool enable_ipv6;
bool no_dhcp;
const char *logfile;
const char *usblogfile;
char expect_adapter[32];
int kill_pdp;
int replication_factor;
//user input end
char qmichannel[32];
char usbnet_adapter[32];
char qmapnet_adapter[32];
char driver_name[32];
int qmap_mode;
int qmap_size;
int qmap_version;
int curIpFamily;
int rawIP;
int muxid;
#ifdef CONFIG_ENABLE_QOS
UINT qos_id;
#endif
int wda_client;
uint32_t udhcpc_ip;
IPV4_T ipv4;
IPV6_T ipv6;
UINT PCSCFIpv4Addr1;
UINT PCSCFIpv4Addr2;
UCHAR PCSCFIpv6Addr1[16];
UCHAR PCSCFIpv6Addr2[16];
bool reattach_flag;
int hardware_interface;
int software_interface;
struct usb_device_info usb_dev;
struct usb_interface_info usb_intf;
int usbmon_fd;
FILE *usbmon_logfile_fp;
bool loopback_state;
char BaseBandVersion[64];
char old_apn[64];
char old_user[64];
char old_password[64];
int old_auth;
int old_iptype;
const struct qmi_device_ops *qmi_ops;
const struct request_ops *request_ops;
RMNET_INFO rmnet_info;
} PROFILE_T;
#ifdef QUECTEL_QMI_MERGE
#define MERGE_PACKET_IDENTITY 0x2c7c
#define MERGE_PACKET_VERSION 0x0001
#define MERGE_PACKET_MAX_PAYLOAD_SIZE 56
typedef struct __QMI_MSG_HEADER {
uint16_t idenity;
uint16_t version;
uint16_t cur_len;
uint16_t total_len;
} QMI_MSG_HEADER;
typedef struct __QMI_MSG_PACKET {
QMI_MSG_HEADER header;
uint16_t len;
char buf[4096];
} QMI_MSG_PACKET;
#endif
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;
#pragma pack(pop)
#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
#define MODEM_REPORT_RESET_EVENT 0x1006
#define RIL_UNSOL_LOOPBACK_CONFIG_IND 0x1007
#ifdef CONFIG_REG_QOS_IND
#define RIL_UNSOL_GLOBAL_QOS_FLOW_IND_QOS_ID 0x1008
#endif
extern pthread_mutex_t cm_command_mutex;
extern pthread_cond_t cm_command_cond;
extern unsigned int cm_recv_buf[1024];
extern int cm_open_dev(const char *dev);
extern int cm_open_proxy(const char *name);
extern int pthread_cond_timeout_np(pthread_cond_t *cond, pthread_mutex_t * mutex, unsigned msecs);
extern int QmiThreadSendQMITimeout(PQCQMIMSG pRequest, PQCQMIMSG *ppResponse, unsigned msecs, const char *funcname);
#define QmiThreadSendQMI(pRequest, ppResponse) QmiThreadSendQMITimeout(pRequest, ppResponse, 30 * 1000, __func__)
extern void QmiThreadRecvQMI(PQCQMIMSG pResponse);
extern void udhcpc_start(PROFILE_T *profile);
extern void udhcpc_stop(PROFILE_T *profile);
extern void ql_set_driver_link_state(PROFILE_T *profile, int link_state);
extern void ql_set_driver_qmap_setting(PROFILE_T *profile, QMAP_SETTING *qmap_settings);
extern void ql_get_driver_rmnet_info(PROFILE_T *profile, RMNET_INFO *rmnet_info);
extern void dump_qmi(void *dataBuffer, int dataLen);
extern void qmidevice_send_event_to_main(int triger_event);
extern void qmidevice_send_event_to_main_ext(int triger_event, void *data, unsigned len);
extern uint8_t qmi_over_mbim_get_client_id(uint8_t QMIType);
extern uint8_t qmi_over_mbim_release_client_id(uint8_t QMIType, uint8_t ClientId);
#ifdef CONFIG_REG_QOS_IND
extern UCHAR ql_get_global_qos_flow_ind_qos_id(PQCQMIMSG pResponse, UINT *qos_id);
#endif
#ifdef CONFIG_GET_QOS_DATA_RATE
extern UCHAR ql_get_global_qos_flow_ind_data_rate(PQCQMIMSG pResponse, void *max_data_rate);
#endif
struct request_ops {
int (*requestBaseBandVersion)(PROFILE_T *profile);
int (*requestSetEthMode)(PROFILE_T *profile);
int (*requestSetLoopBackState)(UCHAR loopback_state, ULONG replication_factor);
int (*requestGetSIMStatus)(SIM_Status *pSIMStatus);
int (*requestEnterSimPin)(const char *pPinCode);
int (*requestSetProfile)(PROFILE_T *profile); // 1 ~ success and apn change, 0 ~ success and no apn change, -1 ~ fail
int (*requestGetProfile)(PROFILE_T *profile);
int (*requestRegistrationState)(UCHAR *pPSAttachedState);
int (*requestSetupDataCall)(PROFILE_T *profile, int curIpFamily);
int (*requestQueryDataCall)(UCHAR *pConnectionStatus, int curIpFamily);
int (*requestDeactivateDefaultPDP)(PROFILE_T *profile, int curIpFamily);
int (*requestGetIPAddress)(PROFILE_T *profile, int curIpFamily);
int (*requestGetSignalInfo)(void);
int (*requestGetCellInfoList)(void);
int (*requestGetICCID)(void);
int (*requestGetIMSI)(void);
int (*requestRadioPower)(int state);
int (*requestRegisterQos)(PROFILE_T *profile);
int (*requestGetQosInfo)(PROFILE_T *profile);
int (*requestGetCoexWWANState)(void);
};
extern const struct request_ops qmi_request_ops;
extern const struct request_ops mbim_request_ops;
extern const struct request_ops atc_request_ops;
extern int get_driver_type(PROFILE_T *profile);
extern BOOL qmidevice_detect(char *qmichannel, char *usbnet_adapter, unsigned bufsize, PROFILE_T *profile);
int mhidevice_detect(char *qmichannel, char *usbnet_adapter, PROFILE_T *profile);
int atdevice_detect(char *atchannel, char *usbnet_adapter, PROFILE_T *profile);
extern int ql_bridge_mode_detect(PROFILE_T *profile);
extern int ql_enable_qmi_wwan_rawip_mode(PROFILE_T *profile);
extern int ql_qmap_mode_detect(PROFILE_T *profile);
#ifdef CONFIG_QRTR
extern int rtrmnet_ctl_create_vnd(char *devname, char *vndname, uint8_t muxid,
uint32_t qmap_version, uint32_t ul_agg_cnt, uint32_t ul_agg_size);
#endif
#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 int qmidevice_control_fd[2];
extern int g_donot_exit_when_modem_hangup;
extern void update_resolv_conf(int iptype, const char *ifname, const char *dns1, const char *dns2);
void update_ipv4_address(const char *ifname, const char *ip, const char *gw, unsigned prefix);
void update_ipv6_address(const char *ifname, const char *ip, const char *gw, unsigned prefix);
int reattach_driver(PROFILE_T *profile);
extern void no_trunc_strncpy(char *dest, const char *src, size_t dest_size);
enum
{
DRV_INVALID,
SOFTWARE_QMI,
SOFTWARE_MBIM,
SOFTWARE_ECM_RNDIS_NCM,
SOFTWARE_QRTR,
HARDWARE_PCIE,
HARDWARE_USB,
};
enum
{
SIG_EVENT_START,
SIG_EVENT_CHECK,
SIG_EVENT_STOP,
};
typedef enum
{
DMS_OP_MODE_ONLINE,
DMS_OP_MODE_LOW_POWER,
DMS_OP_MODE_FACTORY_TEST_MODE,
DMS_OP_MODE_OFFLINE,
DMS_OP_MODE_RESETTING,
DMS_OP_MODE_SHUTTING_DOWN,
DMS_OP_MODE_PERSISTENT_LOW_POWER,
DMS_OP_MODE_MODE_ONLY_LOW_POWER,
DMS_OP_MODE_NET_TEST_GW,
}Device_operating_mode;
#ifdef CM_DEBUG
#define dbg_time(fmt, args...) do { \
fprintf(stdout, "[%15s-%04d: %s] " fmt "\n", __FILE__, __LINE__, get_time(), ##args); \
fflush(stdout);\
if (logfilefp) fprintf(logfilefp, "[%s-%04d: %s] " fmt "\n", __FILE__, __LINE__, get_time(), ##args); \
} while(0)
#else
#define dbg_time(fmt, args...) do { \
fprintf(stdout, "[%s] " fmt "\n", get_time(), ##args); \
fflush(stdout);\
if (logfilefp) fprintf(logfilefp, "[%s] " fmt "\n", get_time(), ##args); \
} while(0)
#endif
#endif

View File

@ -1,459 +0,0 @@
/******************************************************************************
@file QmiWwanCM.c
@brief QMI WWAN connectivity manager.
DESCRIPTION
Connectivity Management Tool for USB network adapter of Quectel wireless cellular modules.
INITIALIZATION AND SEQUENCING REQUIREMENTS
None.
---------------------------------------------------------------------------
Copyright (c) 2016 - 2023 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
Quectel Wireless Solution Proprietary and Confidential.
---------------------------------------------------------------------------
******************************************************************************/
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <stdio.h>
#include <ctype.h>
#include "QMIThread.h"
#ifdef CONFIG_QMIWWAN
static int cdc_wdm_fd = -1;
static UCHAR qmiclientId[QMUX_TYPE_ALL];
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)
{
(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 USHORT CtlLibQmiProxyOpenReq(PQMICTL_MSG QCTLMsg, void *arg)
{
(void)arg;
const char *device_path = (const char *)(arg);
QCTLMsg->LibQmiProxyOpenReq.TLVType = 0x01;
QCTLMsg->LibQmiProxyOpenReq.TLVLength = cpu_to_le16(strlen(device_path));
//strcpy(QCTLMsg->LibQmiProxyOpenReq.device_path, device_path);
//__builtin___strcpy_chk
memcpy(QCTLMsg->LibQmiProxyOpenReq.device_path, device_path, strlen(device_path));
return sizeof(QMICTL_LIBQMI_PROXY_OPEN_MSG) + (strlen(device_path));
}
static int libqmi_proxy_open(const char *cdc_wdm) {
int ret;
PQCQMIMSG pResponse;
ret = QmiThreadSendQMI(ComposeQCTLMsg(QMI_MESSAGE_CTL_INTERNAL_PROXY_OPEN,
CtlLibQmiProxyOpenReq, (void *)cdc_wdm), &pResponse);
if (!ret && pResponse
&& pResponse->CTLMsg.QMICTLMsgHdrRsp.QMUXResult == 0
&& pResponse->CTLMsg.QMICTLMsgHdrRsp.QMUXError == 0) {
ret = 0;
}
else {
return -1;
}
if (pResponse)
free(pResponse);
return ret;
}
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_CTL) {
pRequest->QMIHdr.ClientId = qmiclientId[pRequest->QMIHdr.QMIType];
if (pRequest->QMIHdr.ClientId == 0) {
dbg_time("QMIType %d has no clientID", pRequest->QMIHdr.QMIType);
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 UCHAR 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;
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_COEX: dbg_time("Get clientCOEX = %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->proxy[0] && !strcmp(profile->proxy, LIBQMI_PROXY)) {
ret = libqmi_proxy_open(profile->qmichannel);
if (ret)
return ret;
}
if (!profile->proxy[0]) {
for (i = 0; i < 10; i++) {
ret = QmiThreadSendQMITimeout(ComposeQCTLMsg(QMICTL_SYNC_REQ, NULL, NULL), NULL, 1 * 1000, __func__);
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 0
dbg_time("QMUXType = %02x Version = %d.%d",
pResponse->CTLMsg.GetVersionRsp.TypeVersion[NumElements].QMUXType,
pResponse->CTLMsg.GetVersionRsp.TypeVersion[NumElements].MajorVersion,
pResponse->CTLMsg.GetVersionRsp.TypeVersion[NumElements].MinorVersion);
#endif
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);
qmiclientId[QMUX_TYPE_WDS] = QmiWwanGetClientID(QMUX_TYPE_WDS);
if (profile->enable_ipv6)
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);
qmiclientId[QMUX_TYPE_WDS_ADMIN] = QmiWwanGetClientID(QMUX_TYPE_WDS_ADMIN);
#ifdef CONFIG_COEX_WWAN_STATE
qmiclientId[QMUX_TYPE_COEX] = QmiWwanGetClientID(QMUX_TYPE_COEX);
#endif
#ifdef CONFIG_ENABLE_QOS
qmiclientId[QMUX_TYPE_QOS] = QmiWwanGetClientID(QMUX_TYPE_QOS);
#endif
profile->wda_client = qmiclientId[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((QMUX_TYPE_WDS_IPV6 == i ? QMUX_TYPE_WDS : i), qmiclientId[i]);
qmiclientId[i] = 0;
}
}
return 0;
}
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) && le16_to_cpu(pHdr->Length) < size) {
nreads += read(fd, pHdr+1, le16_to_cpu(pHdr->Length) + 1 - sizeof(QCQMI_HDR));
}
return nreads;
}
#ifdef QUECTEL_QMI_MERGE
static int QmiWwanMergeQmiRsp(void *buf, ssize_t *src_size) {
static QMI_MSG_PACKET s_QMIPacket;
QMI_MSG_HEADER *header = NULL;
ssize_t size = *src_size;
if((uint16_t)size < sizeof(QMI_MSG_HEADER))
return -1;
header = (QMI_MSG_HEADER *)buf;
if(le16_to_cpu(header->idenity) != MERGE_PACKET_IDENTITY || le16_to_cpu(header->version) != MERGE_PACKET_VERSION || le16_to_cpu(header->cur_len) > le16_to_cpu(header->total_len))
return -1;
if(le16_to_cpu(header->cur_len) == le16_to_cpu(header->total_len)) {
*src_size = le16_to_cpu(header->total_len);
memcpy(buf, buf + sizeof(QMI_MSG_HEADER), *src_size);
s_QMIPacket.len = 0;
return 0;
}
memcpy(s_QMIPacket.buf + s_QMIPacket.len, buf + sizeof(QMI_MSG_HEADER), le16_to_cpu(header->cur_len));
s_QMIPacket.len += le16_to_cpu(header->cur_len);
if (le16_to_cpu(header->cur_len) < MERGE_PACKET_MAX_PAYLOAD_SIZE || s_QMIPacket.len >= le16_to_cpu(header->total_len)) {
memcpy(buf, s_QMIPacket.buf, s_QMIPacket.len);
*src_size = s_QMIPacket.len;
s_QMIPacket.len = 0;
return 0;
}
return -1;
}
#endif
static void * QmiWwanThread(void *pData) {
PROFILE_T *profile = (PROFILE_T *)pData;
const char *cdc_wdm = (const char *)profile->qmichannel;
int wait_for_request_quit = 0;
char num = cdc_wdm[strlen(cdc_wdm)-1];
if (profile->proxy[0]) {
if (!strncmp(profile->proxy, QUECTEL_QMI_PROXY, strlen(QUECTEL_QMI_PROXY))) {
snprintf(profile->proxy, sizeof(profile->proxy), "%s%c", QUECTEL_QMI_PROXY, num);
}
}
else if (!strncmp(cdc_wdm, "/dev/mhi_IPCR", strlen("/dev/mhi_IPCR"))) {
snprintf(profile->proxy, sizeof(profile->proxy), "%s%c", QUECTEL_QRTR_PROXY, num);
}
else if (profile->qmap_mode > 1) {
snprintf(profile->proxy, sizeof(profile->proxy), "%s%c", QUECTEL_QMI_PROXY, num);
}
if (profile->proxy[0])
cdc_wdm_fd = cm_open_proxy(profile->proxy);
else
cdc_wdm_fd = cm_open_dev(cdc_wdm);
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;
}
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, wait_for_request_quit ? 1000 : -1);
} while ((ret < 0) && (errno == EINTR));
if (ret == 0 && wait_for_request_quit) {
QmiThreadRecvQMI(NULL);
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;
//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 SIG_EVENT_STOP:
wait_for_request_quit = 1;
break;
default:
break;
}
}
}
if (fd == cdc_wdm_fd) {
ssize_t nreads;
PQCQMIMSG pResponse = (PQCQMIMSG)cm_recv_buf;
if (!profile->proxy[0])
nreads = read(fd, cm_recv_buf, sizeof(cm_recv_buf));
else
nreads = qmi_proxy_read(fd, cm_recv_buf, sizeof(cm_recv_buf));
//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;
}
#ifdef QUECTEL_QMI_MERGE
if((profile->qmap_mode == 0 || profile->qmap_mode == 1) && QmiWwanMergeQmiRsp(cm_recv_buf, &nreads))
continue;
#endif
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;
}
const struct qmi_device_ops qmiwwan_qmidev_ops = {
.init = QmiWwanInit,
.deinit = QmiWwanDeInit,
.send = QmiWwanSendQMI,
.read = QmiWwanThread,
};
uint8_t qmi_over_mbim_get_client_id(uint8_t QMIType) {
return QmiWwanGetClientID(QMIType);
}
uint8_t qmi_over_mbim_release_client_id(uint8_t QMIType, uint8_t ClientId) {
return QmiWwanReleaseClientID(QMIType, ClientId);
}
#endif

View File

@ -1,339 +0,0 @@
Release Notes
[V1.6.5]
Date: 7/3/2023
enhancement:
1. Fix the issue of qmi client id leakage caused by kill 9 killing the client of quectel-qmi-proxy
2. Fix wds_ipv6 client ID can't be released issue
3. Fix wds_ipv6 client ID can't be released issue
4. Resolve PDP_ Context&Profile_ The issue of index mixing
5. Add parameter - d to obtain IP and DNS information through qmi
6. Fix mbim dialing. When the user does not specify apn through - s, prompt the user and exit the dialing program
7. Prioritize the use of IP commands for optimization, and use ifconfig if not available
8. Optimize and add/remove copyright
fix:
[V1.6.4]
Date: 9/7/2022
enhancement:
1. set cflags as -Wall -Wextra -Werror -O1, and fix compile errors
2. some code refactoring
3. add quectel-qrtr-proxy
fix:
1. netmask error when use ifconfig on little endian cpu
[V1.6.2]
Date: 11/18/2021
enhancement:
1. support 'LTE && WiFi Coexistence Solution via QMI'.
If customer want use this feature, need enable CONFIG_COEX_WWAN_STATE in QMIThread.h
[V1.6.1]
Date: 7/20/2021
enhancement:
1. add requestGetCellInfoList requestRadioPower
2. add QMI OVER MBIM
3. support qrtr and rmnet
4. support RG500U PCIE
5. add qos service && get qos flow data_rate_max func
fix:
1. mbim: increase mbim open timeout to 3 seconds. some modem take long time for open cmd.
2. support MsChapV2
3. mbim: invalid memory access when only get one DNS
4. some bug fix for use AT Command to setup data call
[V1.6.0.26]
Date: 4/22/2021
enhancement:
1. add lots of log file to show how to use this tool
2. support pcie mhi multiple call
3. at command: support EC200U/EC200T/EC200S/RG801H/RG500U/
fix:
1. mbim-proxy: fix errors on big endian cpu, ignore mbim open/close cmd from quectel-cm
[V1.6.0.25]
Date: 4/8/2021
enhancement:
fix:
1. fix compile error when use gcc 9.3.0
2. fix yocto 'QA Issue: No GNU_HASH in the ELF binary'
[V1.6.0.24]
Date: 3/9/2021
enhancement:
1. '-p [quectel-][qmi|mbim]-proxy', can connect to quectel/libqmi/libmbim's proxy, even only one data
2. set variable s_9x07 as 1 (from 0), most of modems are base on MDM90x7 and later QCOM chip.
fix:
1. define CHAR as signed char
2. mofidy Makefile to generate more compile warnnings and fix them
[V1.6.0.23]
Date: 2/26/2021
enhancement:
1. support 'AT+QNETDEVCTL' (not release)
fix:
1. modify help/usage
2. fix some memroy access error in mbim-cm.c
[V1.6.0.22]
Date: 2/4/2021
enhancement:
1. support connect to libqmi's qmi-proxy
2. only allow ' 0/1/2/none/pap/chap' for auth of '-s'
3. '-m iface-idx' bind QMAP data call to wwan0_<iface_idx>
fix:
[V1.6.0.21]
Date: 1/28/2021
enhancement:
1. print 5G signal
fix:
1. fix compile errors: -Werror=format-truncation=
[V1.6.0.20]
Date: 12/29/2020
enhancement:
1. Code refactoring
2. support 'AT+QNETDEVCTL' (not release)
fix:
[V1.6.0.19]
Date: 12/4/2020
enhancement:
1. if 'udhcpc's default.script' missed, directy set ip/dns/route by 'ip' co,mand
fix:
[V1.6.0.18]
Date: 12/4/2020
enhancement:
1. Code refactoring
fix:
[V1.6.0.17]
Date: 8/25/2020
enhancement:
1. support MBIM multi-call
2. support unisoc RG500U mbim
3. QUECTEL_QMI_MERGE: some SOC can not read more then 64 bytes (QMI)data via USB Endpoint 0
fix:
[V1.6.0.15]
Date: 7/24/2020
enhancement:
fix:
1. QMAP multi-call, AT+CFUN=4 then AT+CFUN=1, only one call can obtain IP by DHCP
[V1.6.0.14]
Date: 6/10/2020
enhancement:
1. support X55's GobiNet LOOPBACK
fix:
1. very old uclib do not support htole32 and pthread_condattr_setclock
2. pthread_cond_wait tv_nsec >= 1000000000U is wrong
3. do not close socket in udhcpc.c ifc_get_addr()
[V1.6.0.13]
Date: 6/9/2020
enhancement:
1. add some example for openwrt, marco 'QL_OPENWER_NETWORK_SETUP'
fix:
[V1.6.0.12]
Date: 5/29/2020
enhancement:
fix:
1. some EM12's usb-net-qmi/mbim interface is at 8 (not 4)
[V1.6.0.11]
Date: 5/28/2020
enhancement:
fix:
1. fix mbim debug on Big Endian CPU
[V1.6.0.10]
Date: 5/25/2020
enhancement:
fix:
1. set QMAP .ul_data_aggregation_max_datagrams to 11 (from 16)
[V1.6.0.9]
Date: 5/22/2020
enhancement:
fix:
1. dial fail when register to 5G-SA
[V1.6.0.8]
Date: 4/30/2020
enhancement:
1. support '-b' to seletc brige mode
fix:
[V1.6.0.7]
Date: 4/29/2020
enhancement:
1. support QMAP multi-call for qmi_wwan_q and pcie_mhi 's rmnet driver
fix:
[V1.6.0.6]
Date: 4/20/2020
enhancement:
1. support '-k pdn_idx' to hangup call '-n pdn_idx'
fix:
1. fix set dl_minimum_padding as 0, modems do not support this featrue
[V1.6.0.5]
Date: 4/10/2020
enhancement:
1. support X55's QMAPV5 for PCIE
fix:
[V1.6.0.3]
Date: 4/8/2020
enhancement:
1. support multi-modems all use multi-data-calls
fix:
[V1.6.0.2]
Date: 4/7/2020
enhancement:
1. support X55's QMAPV5 for USB
fix:
[V1.6.0.1]
Date: 4/1/2020
enhancement:
1. support QMAP UL AGG (multi data call)
fix:
1. some EM12's usb-net-qmi/mbim interface is at 8 (not 4)
[V1.5.9]
Date: 3/4/2020
enhancement:
1. support pcie mhi multi-APN data call
3. support QMAP UL AGG (single data call)
fix:
1. set 4 bytes aligned for mbim parameters, or cause dial mbim call fail
[V1.5.8]
Date: 2/18/2020
enhancement:
1. support '-l 14' X55's loopback function
fix:
[V1.5.7]
Date: 2/6/2020
enhancement:
1. support '-u usbmon_log_file' to catch usbmon log
fix:
[V1.5.6]
Date: 1/20/202
enhancement:
1. show driver name and version
2. support PCSCF
3. support bridge in mbim
fix:
[V1.5.5]
Date: 12/31/2019
enhancement:
fix:
1. fix some memory access bug in mbim-cm.c
[WCDMA&LTE_QConnectManager_Linux&Android_V1.5.4]
Date: 12/17/2019
enhancement:
1. Add copyright
2. auto detect pcie mhi /dev/mhi*
fix:
[WCDMA&LTE_QConnectManager_Linux&Android_V1.5.3]
Date: 2019/12/11
enhancement:
1. support show SignalInfo, controlled by macro CONFIG_SIGNALINFO
2. support show 5G_NSA/5G_NA
3. support Microsoft Extend MBIM message
fix:
1. quectel-qmi-proxy bugs on Big-Endian CPU
[WCDMA&LTE_QConnectManager_Linux&Android_V1.5.2]
Date: 12/2/2019
enhancement:
1. support requestGetSignalInfo()
fix:
[WCDMA&LTE_QConnectManager_Linux&Android_V1.4.1]
Date: 10/23/2019
enhancement:
1. support QMI_CTL_REVOKE_CLIENT_ID_IND (Quectel define QMI)
2. add copyright
fix:
1. remove SIGUSR
[WCDMA&LTE_QConnectManager_Linux&Android_V1.3.10]
Date: 10/14/2019
enhancement:
1. increase retry interval
fix:
[WCDMA&LTE_QConnectManager_Linux&Android_V1.2.1]
Date: 2019/02/26
enhancement:
1. Implement help message.
root@ubuntu:# ./quectel-CM -h
[02-26_10:39:21:353] Usage: ./quectel-CM [options]
[02-26_10:39:21:353] -s [apn [user password auth]] Set apn/user/password/auth get from your network provider
[02-26_10:39:21:353] -p pincode Verify sim card pin if sim card is locked
[02-26_10:39:21:353] -f logfilename Save log message of this program to file
[02-26_10:39:21:353] -i interface Specify network interface(default auto-detect)
[02-26_10:39:21:353] -4 IPv4 protocol
[02-26_10:39:21:353] -6 IPv6 protocol
[02-26_10:39:21:353] -m muxID Specify muxid when set multi-pdn data connection.
[02-26_10:39:21:353] -n channelID Specify channelID when set multi-pdn data connection(default 1).
[02-26_10:39:21:353] [Examples]
[02-26_10:39:21:353] Example 1: ./quectel-CM
[02-26_10:39:21:353] Example 2: ./quectel-CM -s 3gnet
[02-26_10:39:21:353] Example 3: ./quectel-CM -s 3gnet carl 1234 0 -p 1234 -f gobinet_log.txt
root@ubuntu:#
2. Support bridge mode when set multi-pdn data connections.
3. Host device can access network in bridge mode.
[WCDMA&LTE_QConnectManager_Linux&Android_V1.1.46]
Date: 2019/02/18
enhancement:
1. support only IPV6 data call. quectel-CM now support three dialing methods: IPV4 only, IPV6 only, IPV4V6.
./quectel-CM -4(or no argument) only IPV4
-6 only IPV6
-4 -6 IPV4 && IPV6
[WCDMA&LTE_QConnectManager_Linux&Android_V1.1.45]
Date: 2018/09/13
enhancement:
1. support EG12 PCIE interface
[WCDMA&LTE_QConnectManager_Linux&Android_V1.1.44]
Date: 2018/09/10
enhancement:
1. support setup IPV4&IPV6 data call.
[WCDMA&LTE_QConnectManager_Linux&Android_V1.1.43]
[WCDMA&LTE_QConnectManager_Linux&Android_V1.1.42]
Date: 2018/08/29
enhancement:
1. support QMI_WWAN's QMAP fucntion and bridge mode, please contact Quectel FAE to get qmi_wwan.c patch.
when enable QMI_WWAN's QMAP IP Mux function, must run 'quectel-qmi-proxy -d /dev/cdc-wdmX' before quectel-CM
[WCDMA&LTE_QConnectManager_Linux&Android_V1.1.41]
Date: 2018/05/24
enhancement:
1. fix a cdma data call error
[WCDMA&LTE_QConnectManager_Linux&Android_V1.1.40]
Date: 2018/05/12
enhancement:
1. support GobiNet's QMAP fucntion and bridge mode.
'Quectel_WCDMA&LTE_Linux&Android_GobiNet_Driver_V1.3.5' and later version is required to use QMAP and bridge mode.
for detail, please refer to GobiNet Driver

View File

@ -1,283 +0,0 @@
/* //device/system/reference-ril/at_tok.c
**
** Copyright 2006, 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 "at_tok.h"
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdarg.h>
/**
* Starts tokenizing an AT response string
* returns -1 if this is not a valid response string, 0 on success.
* updates *p_cur with current position
*/
int at_tok_start(char **p_cur)
{
if (*p_cur == NULL) {
return -1;
}
// skip prefix
// consume "^[^:]:"
*p_cur = strchr(*p_cur, ':');
if (*p_cur == NULL) {
return -1;
}
(*p_cur)++;
return 0;
}
static void skipWhiteSpace(char **p_cur)
{
if (*p_cur == NULL) return;
while (**p_cur != '\0' && isspace(**p_cur)) {
(*p_cur)++;
}
}
static void skipNextComma(char **p_cur)
{
if (*p_cur == NULL) return;
while (**p_cur != '\0' && **p_cur != ',') {
(*p_cur)++;
}
if (**p_cur == ',') {
(*p_cur)++;
}
}
static char * nextTok(char **p_cur)
{
char *ret = NULL;
skipWhiteSpace(p_cur);
if (*p_cur == NULL) {
ret = NULL;
} else if (**p_cur == '"') {
(*p_cur)++;
ret = strsep(p_cur, "\"");
skipNextComma(p_cur);
} else {
ret = strsep(p_cur, ",");
}
return ret;
}
/**
* Parses the next integer in the AT response line and places it in *p_out
* returns 0 on success and -1 on fail
* updates *p_cur
* "base" is the same as the base param in strtol
*/
static int at_tok_nextint_base(char **p_cur, int *p_out, int base, int uns)
{
char *ret;
if (*p_cur == NULL) {
return -1;
}
ret = nextTok(p_cur);
if (ret == NULL) {
return -1;
} else {
long l;
char *end;
if (uns)
l = strtoul(ret, &end, base);
else
l = strtol(ret, &end, base);
*p_out = (int)l;
if (end == ret) {
return -1;
}
}
return 0;
}
/**
* Parses the next base 10 integer in the AT response line
* and places it in *p_out
* returns 0 on success and -1 on fail
* updates *p_cur
*/
int at_tok_nextint(char **p_cur, int *p_out)
{
return at_tok_nextint_base(p_cur, p_out, 10, 0);
}
/**
* Parses the next base 16 integer in the AT response line
* and places it in *p_out
* returns 0 on success and -1 on fail
* updates *p_cur
*/
int at_tok_nexthexint(char **p_cur, int *p_out)
{
return at_tok_nextint_base(p_cur, p_out, 16, 1);
}
int at_tok_nextbool(char **p_cur, char *p_out)
{
int ret;
int result;
ret = at_tok_nextint(p_cur, &result);
if (ret < 0) {
return -1;
}
// booleans should be 0 or 1
if (!(result == 0 || result == 1)) {
return -1;
}
if (p_out != NULL) {
*p_out = (char)result;
}
return ret;
}
int at_tok_nextstr(char **p_cur, char **p_out)
{
if (*p_cur == NULL) {
return -1;
}
*p_out = nextTok(p_cur);
return 0;
}
/** returns 1 on "has more tokens" and 0 if no */
int at_tok_hasmore(char **p_cur)
{
return ! (*p_cur == NULL || **p_cur == '\0');
}
int at_tok_count(const char *in_line)
{
int commas = 0;
const char *p;
if (!in_line)
return 0;
for (p = in_line; *p != '\0' ; p++) {
if (*p == ',') commas++;
}
return commas;
}
//fmt: d ~ int, x ~ hexint, b ~ bool, s ~ str
int at_tok_scanf(const char *in_line, const char *fmt, ...)
{
int n = 0;
int err;
va_list ap;
const char *p = fmt;
void *d;
void *dump;
static char s_line[1024];
char *line = s_line;
if (!in_line)
return 0;
strncpy(s_line, in_line, sizeof(s_line) - 1);
va_start(ap, fmt);
err = at_tok_start(&line);
if (err < 0) goto error;
for (; *p; p++) {
if (*p == ',' || *p == ' ')
continue;
if (*p != '%') {
goto error;
}
p++;
d = va_arg(ap, void *);
if (!d)
d = &dump;
if (!at_tok_hasmore(&line))
break;
if (*line == '-' && *(line + 1) == ',') {
line += 2;
n++;
if (*p == 'd')
*(int *)d = -1;
continue;
}
switch(*p) {
case 'd':
err = at_tok_nextint(&line, (int *)d);
if (err < 0) goto error;
break;
case 'x':
err = at_tok_nexthexint(&line, (int *)d);
if (err < 0) goto error;
break;
case 'b':
err = at_tok_nextbool(&line, (char *)d);
if (err < 0) goto error;
break;
case 's':
err = at_tok_nextstr(&line, (char **)d); //if strdup(line), here return free memory to caller
if (err < 0) goto error;
break;
default:
goto error;
break;
}
n++;
}
va_end(ap);
error:
//free(line);
return n;
}

View File

@ -1,33 +0,0 @@
/* //device/system/reference-ril/at_tok.h
**
** Copyright 2006, 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 AT_TOK_H
#define AT_TOK_H 1
int at_tok_start(char **p_cur);
int at_tok_nextint(char **p_cur, int *p_out);
int at_tok_nexthexint(char **p_cur, int *p_out);
int at_tok_nextbool(char **p_cur, char *p_out);
int at_tok_nextstr(char **p_cur, char **out);
int at_tok_hasmore(char **p_cur);
int at_tok_count(const char *in_line);
int at_tok_scanf(const char *line, const char *fmt, ...);
#endif /*AT_TOK_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,152 +0,0 @@
/* //device/system/reference-ril/atchannel.h
**
** Copyright 2006, 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 ATCHANNEL_H
#define ATCHANNEL_H 1
#ifdef __cplusplus
extern "C" {
#endif
/* define AT_DEBUG to send AT traffic to /tmp/radio-at.log" */
#define AT_DEBUG 0
#if AT_DEBUG
extern void AT_DUMP(const char* prefix, const char* buff, int len);
#else
#define AT_DUMP(prefix,buff,len) do{}while(0)
#endif
#define AT_ERROR_GENERIC -1
#define AT_ERROR_COMMAND_PENDING -2
#define AT_ERROR_CHANNEL_CLOSED -3
#define AT_ERROR_TIMEOUT -4
#define AT_ERROR_INVALID_THREAD -5 /* AT commands may not be issued from
reader thread (or unsolicited response
callback */
#define AT_ERROR_INVALID_RESPONSE -6 /* eg an at_send_command_singleline that
did not get back an intermediate
response */
typedef enum {
NO_RESULT, /* no intermediate response expected */
NUMERIC, /* a single intermediate response starting with a 0-9 */
SINGLELINE, /* a single intermediate response starting with a prefix */
MULTILINE /* multiple line intermediate response
starting with a prefix */
} ATCommandType;
/** a singly-lined list of intermediate responses */
typedef struct ATLine {
struct ATLine *p_next;
char *line;
} ATLine;
/** Free this with at_response_free() */
typedef struct {
int success; /* true if final response indicates
success (eg "OK") */
char *finalResponse; /* eg OK, ERROR */
ATLine *p_intermediates; /* any intermediate responses */
} ATResponse;
/**
* a user-provided unsolicited response handler function
* this will be called from the reader thread, so do not block
* "s" is the line, and "sms_pdu" is either NULL or the PDU response
* for multi-line TS 27.005 SMS PDU responses (eg +CMT:)
*/
typedef void (*ATUnsolHandler)(const char *s, const char *sms_pdu);
int at_open(int fd, ATUnsolHandler h, int proxy);
void at_close();
/* This callback is invoked on the command thread.
You should reset or handshake here to avoid getting out of sync */
void at_set_on_timeout(void (*onTimeout)(void));
/* This callback is invoked on the reader thread (like ATUnsolHandler)
when the input stream closes before you call at_close
(not when you call at_close())
You should still call at_close()
It may also be invoked immediately from the current thread if the read
channel is already closed */
void at_set_on_reader_closed(void (*onClose)(void));
int at_send_command_singleline (const char *command,
const char *responsePrefix,
ATResponse **pp_outResponse);
int at_send_command_numeric (const char *command,
ATResponse **pp_outResponse);
int at_send_command_multiline (const char *command,
const char *responsePrefix,
ATResponse **pp_outResponse);
int at_send_command_raw (const char *command,
const char *raw_data, unsigned int raw_len,
const char *responsePrefix,
ATResponse **pp_outResponse);
int at_handshake();
int at_send_command (const char *command, ATResponse **pp_outResponse);
int at_send_command_sms (const char *command, const char *pdu,
const char *responsePrefix,
ATResponse **pp_outResponse);
void at_response_free(ATResponse *p_response);
int strStartsWith(const char *line, const char *prefix);
typedef enum {
CME_ERROR_NON_CME = -1,
CME_SUCCESS = 0,
CME_OPERATION_NOT_ALLOWED = 3,
CME_OPERATION_NOT_SUPPORTED = 4,
CME_PH_SIM_PIN= 5,
CME_PH_FSIM_PIN = 6,
CME_PH_FSIM_PUK = 7,
CME_SIM_NOT_INSERTED =10,
CME_SIM_PIN_REQUIRED = 11,
CME_SIM_PUK_REQUIRED = 12,
CME_FAILURE = 13,
CME_SIM_BUSY = 14,
CME_SIM_WRONG = 15,
CME_INCORRECT_PASSWORD = 16,
CME_SIM_PIN2_REQUIRED = 17,
CME_SIM_PUK2_REQUIRED = 18,
CME_MEMORY_FULL = 20,
CME_INVALID_INDEX = 21,
CME_NOT_FOUND = 22,
CME_MEMORY_FAILURE = 23,
CME_STRING_TO_LONG = 24,
CME_INVALID_CHAR = 25,
CME_DIALSTR_TO_LONG = 26,
CME_INVALID_DIALCHAR = 27,
} AT_CME_Error;
AT_CME_Error at_get_cme_error(const ATResponse *p_response);
#ifdef __cplusplus
}
#endif
#endif /*ATCHANNEL_H*/

View File

@ -1,48 +0,0 @@
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.61])
AC_INIT([quectel-CM], [1.0], [fae-support@quectel.com])
AC_CONFIG_HEADERS([config.h])
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
AC_ARG_WITH(sanitized-headers,
AS_HELP_STRING([--with-sanitized-headers=DIR],
[Specify the location of the sanitized Linux headers]),
[CPPFLAGS="$CPPFLAGS -idirafter $withval"])
AC_ARG_WITH([qrtr],
AC_HELP_STRING([--with-qrtr],
[enable qrtr, building which use qrtr]))
if (test "x${with_qrtr}" = "xyes"); then
#AC_DEFINE(ENABLE_USEQTRT, 1, [Define if uses qrtr])
AC_CHECK_HEADERS([linux/qrtr.h linux/rmnet_data.h])
fi
AM_CONDITIONAL(USE_QRTR, test "x${with_qrtr}" = "xyes")
AC_ARG_WITH([msm-ipc],
AC_HELP_STRING([--with-msm-ipc],
[enable msm-ipc, building which use qrtr]))
if (test "x${with_msm_ipc}" = "xyes"); then
#AC_DEFINE(ENABLE_USEQTRT, 1, [Define if uses qrtr])
AC_CHECK_HEADERS([linux/msm_ipc.h linux/rmnet_data.h])
fi
AM_CONDITIONAL(USE_MSM_IPC, test "x${with_msm_ipc}" = "xyes")
# Checks for library functions.
# Does not strictly follow GNU Coding standards
AM_INIT_AUTOMAKE([foreign subdir-objects])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

View File

@ -1,63 +0,0 @@
#!/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

View File

@ -1,61 +0,0 @@
#!/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"
IPCMD=`which ip`
case $1 in
bound|renew)
$IPCMD address add broadcast $broadcast $ip/$subnet dev $interface
if [ -n "$router" ]; then
echo "$0: Resetting default routes"
while $IPCMD route del default dev $interface; do :; done
metric=0
for i in $router; do
$IPCMD route add default dev $interface via $router 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
$IPCMD address flush dev $interface
;;
leasefail)
echo "$0: Lease failed: $message"
;;
nak)
echo "$0: Received a NAK: $message"
;;
*)
echo "$0: Unknown udhcpc command: $1";
exit 1;
;;
esac

View File

@ -1,746 +0,0 @@
/******************************************************************************
@file device.c
@brief QMI device dirver.
DESCRIPTION
Connectivity Management Tool for USB network adapter of Quectel wireless cellular modules.
INITIALIZATION AND SEQUENCING REQUIREMENTS
None.
---------------------------------------------------------------------------
Copyright (c) 2016 - 2023 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
Quectel Wireless Solution Proprietary and Confidential.
---------------------------------------------------------------------------
******************************************************************************/
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <strings.h>
#include <stdlib.h>
#include <limits.h>
#include <linux/usbdevice_fs.h>
#include <linux/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <time.h>
#include <pthread.h>
#include "QMIThread.h"
#include "ethtool-copy.h"
#define USB_CLASS_VENDOR_SPEC 0xff
#define USB_CLASS_COMM 2
#define USB_CDC_SUBCLASS_ACM 0x02
#define USB_CDC_SUBCLASS_ETHERNET 0x06
#define USB_CDC_SUBCLASS_NCM 0x0d
#define USB_CDC_SUBCLASS_MBIM 0x0e
#define USB_CLASS_WIRELESS_CONTROLLER 0xe0
#define CM_MAX_PATHLEN 256
#define CM_INVALID_VAL (~((int)0))
/* get first line from file 'fname'
* And convert the content into a hex number, then return this number */
static int file_get_value(const char *fname, int base)
{
FILE *fp = NULL;
long num;
char buff[32 + 1] = {'\0'};
char *endptr = NULL;
fp = fopen(fname, "r");
if (!fp) goto error;
if (fgets(buff, sizeof(buff), fp) == NULL)
goto error;
fclose(fp);
num = (int)strtol(buff, &endptr, base);
if (errno == ERANGE && (num == LONG_MAX || num == LONG_MIN))
goto error;
/* if there is no digit in buff */
if (endptr == buff)
goto error;
if (debug_qmi)
dbg_time("(%s) = %lx", fname, num);
return (int)num;
error:
if (fp) fclose(fp);
return CM_INVALID_VAL;
}
/*
* This function will search the directory 'dirname' and return the first child.
* '.' and '..' is ignored by default
*/
static int dir_get_child(const char *dirname, char *buff, unsigned bufsize, const char *prefix)
{
struct dirent *entptr = NULL;
DIR *dirptr;
buff[0] = 0;
dirptr = opendir(dirname);
if (!dirptr)
return -1;
while ((entptr = readdir(dirptr))) {
if (entptr->d_name[0] == '.')
continue;
if (prefix && strlen(prefix) && strncmp(entptr->d_name, prefix, strlen(prefix)))
continue;
snprintf(buff, bufsize, "%.31s", entptr->d_name);
break;
}
closedir(dirptr);
return 0;
}
static int conf_get_val(const char *fname, const char *key)
{
char buff[128] = {'\0'};
FILE *fp = fopen(fname, "r");
if (!fp)
return CM_INVALID_VAL;
while (fgets(buff, sizeof(buff)-1, fp)) {
char prefix[128] = {'\0'};
char tail[128] = {'\0'};
/* To eliminate cppcheck warnning: Assume string length is no more than 15 */
sscanf(buff, "%15[^=]=%15s", prefix, tail);
if (!strncasecmp(prefix, key, strlen(key))) {
fclose(fp);
return atoi(tail);
}
}
fclose(fp);
return CM_INVALID_VAL;
}
static void query_usb_device_info(char *path, struct usb_device_info *p) {
size_t offset = strlen(path);
memset(p, 0, sizeof(*p));
path[offset] = '\0';
strcat(path, "/idVendor");
p->idVendor = file_get_value(path, 16);
if (p->idVendor == CM_INVALID_VAL)
return;
path[offset] = '\0';
strcat(path, "/idProduct");
p->idProduct = file_get_value(path, 16);
path[offset] = '\0';
strcat(path, "/busnum");
p->busnum = file_get_value(path, 10);
path[offset] = '\0';
strcat(path, "/devnum");
p->devnum = file_get_value(path, 10);
path[offset] = '\0';
strcat(path, "/bNumInterfaces");
p->bNumInterfaces = file_get_value(path, 10);
path[offset] = '\0';
}
static void query_usb_interface_info(char *path, struct usb_interface_info *p) {
char driver[128];
size_t offset = strlen(path);
int n;
memset(p, 0, sizeof(*p));
path[offset] = '\0';
strcat(path, "/bNumEndpoints");
p->bInterfaceClass = file_get_value(path, 16);
path[offset] = '\0';
strcat(path, "/bInterfaceClass");
p->bInterfaceClass = file_get_value(path, 16);
path[offset] = '\0';
strcat(path, "/bInterfaceSubClass");
p->bInterfaceSubClass = file_get_value(path, 16);
path[offset] = '\0';
strcat(path, "/bInterfaceProtocol");
p->bInterfaceProtocol = file_get_value(path, 16);
path[offset] = '\0';
strcat(path, "/driver");
n = readlink(path, driver, sizeof(driver));
if (n > 0) {
driver[n] = 0;
if (debug_qmi) dbg_time("driver -> %s", driver);
n = strlen(driver);
while (n > 0) {
if (driver[n] == '/')
break;
n--;
}
strncpy(p->driver, &driver[n+1], sizeof(p->driver) - 1);
}
path[offset] = '\0';
}
static int detect_path_cdc_wdm_or_qcqmi(char *path, char *devname, size_t bufsize)
{
size_t offset = strlen(path);
char tmp[32];
devname[0] = 0;
if (access(path, R_OK))
return -1;
path[offset] = '\0';
strcat(path, "/GobiQMI");
if (!access(path, R_OK))
goto step_1;
path[offset] = '\0';
strcat(path, "/usbmisc");
if (!access(path, R_OK))
goto step_1;
path[offset] = '\0';
strcat(path, "/usb");
if (!access(path, R_OK))
goto step_1;
return -1;
step_1:
/* get device(qcqmiX|cdc-wdmX) */
if (debug_qmi) dbg_time("%s", path);
dir_get_child(path, tmp, sizeof(tmp), NULL);
if (tmp[0] == '\0')
return -1;
/* There is a chance that, no device(qcqmiX|cdc-wdmX) is generated. We should warn user about that! */
snprintf(devname, bufsize, "/dev/%s", tmp);
if (access(devname, R_OK | F_OK) && errno == ENOENT)
{
int major, minor;
dbg_time("access %s failed, errno: %d (%s)", devname, errno, strerror(errno));
strcat(path, "/");
strcat(path, tmp);
strcat(path, "/uevent");
major = conf_get_val(path, "MAJOR");
minor = conf_get_val(path, "MINOR");
if(major == CM_INVALID_VAL || minor == CM_INVALID_VAL)
dbg_time("get major and minor failed");
else if (mknod(devname, S_IFCHR|0666, (((major & 0xfff) << 8) | (minor & 0xff) | ((minor & 0xfff00) << 12))))
dbg_time("please mknod %s c %d %d", devname, major, minor);
}
return 0;
}
/* To detect the device info of the modem.
* return:
* FALSE -> fail
* TRUE -> ok
*/
BOOL qmidevice_detect(char *qmichannel, char *usbnet_adapter, unsigned bufsize, PROFILE_T *profile) {
struct dirent* ent = NULL;
DIR *pDir;
const char *rootdir = "/sys/bus/usb/devices";
struct {
char path[255*2];
} *pl;
pl = (typeof(pl)) malloc(sizeof(*pl));
memset(pl, 0x00, sizeof(*pl));
pDir = opendir(rootdir);
if (!pDir) {
dbg_time("opendir %s failed: %s", rootdir, strerror(errno));
goto error;
}
while ((ent = readdir(pDir)) != NULL) {
char netcard[32+1] = {'\0'};
char devname[32+5] = {'\0'}; //+strlen("/dev/")
int netIntf;
int driver_type;
if (ent->d_name[0] == 'u')
continue;
snprintf(pl->path, sizeof(pl->path), "%s/%s", rootdir, ent->d_name);
query_usb_device_info(pl->path, &profile->usb_dev);
if (profile->usb_dev.idVendor == CM_INVALID_VAL)
continue;
if (profile->usb_dev.idVendor == 0x2c7c || profile->usb_dev.idVendor == 0x05c6) {
dbg_time("Find %s/%s idVendor=0x%x idProduct=0x%x, bus=0x%03x, dev=0x%03x",
rootdir, ent->d_name, profile->usb_dev.idVendor, profile->usb_dev.idProduct,
profile->usb_dev.busnum, profile->usb_dev.devnum);
}
/* get network interface */
/* NOTICE: there is a case that, bNumberInterface=6, but the net interface is 8 */
/* toolchain-mips_24kc_gcc-5.4.0_musl donot support GLOB_BRACE */
/* RG500U's MBIM is at inteface 0 */
for (netIntf = 0; netIntf < (profile->usb_dev.bNumInterfaces + 8); netIntf++) {
snprintf(pl->path, sizeof(pl->path), "%s/%s:1.%d/net", rootdir, ent->d_name, netIntf);
dir_get_child(pl->path, netcard, sizeof(netcard), NULL);
if (netcard[0])
break;
}
if (netcard[0] == '\0') { //for centos 2.6.x
const char *n= "usb0";
const char *c = "qcqmi0";
snprintf(pl->path, sizeof(pl->path), "%s/%s:1.4/net:%s", rootdir, ent->d_name, n);
if (!access(pl->path, F_OK)) {
snprintf(pl->path, sizeof(pl->path), "%s/%s:1.4/GobiQMI:%s", rootdir, ent->d_name, c);
if (!access(pl->path, F_OK)) {
snprintf(qmichannel, bufsize, "/dev/%s", c);
snprintf(usbnet_adapter, bufsize, "%s", n);
snprintf(pl->path, sizeof(pl->path), "%s/%s:1.4", rootdir, ent->d_name);
query_usb_interface_info(pl->path, &profile->usb_intf);
break;
}
}
}
if (netcard[0] == '\0')
continue;
/* not '-i iface' */
if (usbnet_adapter[0] && strcmp(usbnet_adapter, netcard))
continue;
snprintf(pl->path, sizeof(pl->path), "%s/%s:1.%d", rootdir, ent->d_name, netIntf);
query_usb_interface_info(pl->path, &profile->usb_intf);
driver_type = get_driver_type(profile);
if (driver_type == SOFTWARE_QMI || driver_type == SOFTWARE_MBIM) {
detect_path_cdc_wdm_or_qcqmi(pl->path, devname, sizeof(devname));
}
else if (driver_type == SOFTWARE_ECM_RNDIS_NCM)
{
int atIntf = -1;
if (profile->usb_dev.idVendor == 0x2c7c) { //Quectel
switch (profile->usb_dev.idProduct) { //EC200U
case 0x0901: //EC200U
case 0x8101: //RG801H
atIntf = 2;
break;
case 0x0900: //RG500U
atIntf = 4;
break;
case 0x6026: //EC200T
case 0x6005: //EC200A
case 0x6002: //EC200S
case 0x6001: //EC100Y
atIntf = 3;
break;
default:
dbg_time("unknow at interface for USB idProduct:%04x\n", profile->usb_dev.idProduct);
break;
}
}
if (atIntf != -1) {
snprintf(pl->path, sizeof(pl->path), "%s/%s:1.%d", rootdir, ent->d_name, atIntf);
dir_get_child(pl->path, devname, sizeof(devname), "tty");
if (devname[0] && !strcmp(devname, "tty")) {
snprintf(pl->path, sizeof(pl->path), "%s/%s:1.%d/tty", rootdir, ent->d_name, atIntf);
dir_get_child(pl->path, devname, sizeof(devname), "tty");
}
}
}
if (netcard[0] && devname[0]) {
if (devname[0] == '/')
snprintf(qmichannel, bufsize, "%s", devname);
else
snprintf(qmichannel, bufsize, "/dev/%s", devname);
snprintf(usbnet_adapter, bufsize, "%s", netcard);
dbg_time("Auto find qmichannel = %s", qmichannel);
dbg_time("Auto find usbnet_adapter = %s", usbnet_adapter);
break;
}
}
closedir(pDir);
if (qmichannel[0] == '\0' || usbnet_adapter[0] == '\0') {
dbg_time("network interface '%s' or qmidev '%s' is not exist", usbnet_adapter, qmichannel);
goto error;
}
free(pl);
return TRUE;
error:
free(pl);
return FALSE;
}
int mhidevice_detect(char *qmichannel, char *usbnet_adapter, PROFILE_T *profile) {
struct dirent* ent = NULL;
DIR *pDir;
const char *rootdir_mhi[] = {"/sys/bus/mhi_q/devices", "/sys/bus/mhi/devices", NULL};
int i = 0;
char path[256];
int find = 0;
while (rootdir_mhi[i]) {
const char *rootdir = rootdir_mhi[i++];
pDir = opendir(rootdir);
if (!pDir) {
if (errno != ENOENT)
dbg_time("opendir %s failed: %s", rootdir, strerror(errno));
continue;
}
while ((ent = readdir(pDir)) != NULL) {
char netcard[32] = {'\0'};
char devname[32] = {'\0'};
int software_interface = SOFTWARE_QMI;
char *pNode = NULL;
pNode = strstr(ent->d_name, "_IP_HW0"); //0306_00.01.00_IP_HW0
if (!pNode)
continue;
snprintf(path, sizeof(path), "%s/%.32s/net", rootdir, ent->d_name);
dir_get_child(path, netcard, sizeof(netcard), NULL);
if (!netcard[0])
continue;
if (usbnet_adapter[0] && strcmp(netcard, usbnet_adapter)) //not '-i x'
continue;
if (!strcmp(rootdir, "/sys/bus/mhi/devices")) {
snprintf(path, sizeof(path), "%s/%.13s_IPCR", rootdir, ent->d_name); // 13 is sizeof(0306_00.01.00)
if (!access(path, F_OK)) {
/* we also need 'cat /dev/mhi_0306_00.01.00_pipe_14' to enable rmnet as like USB's DTR
or will get error 'requestSetEthMode QMUXResult = 0x1, QMUXError = 0x46' */
sprintf(usbnet_adapter, "%s", netcard);
sprintf(qmichannel, "qrtr-%d", 3); // 3 is sdx modem's node id
profile->software_interface = SOFTWARE_QRTR;
find = 1;
break;
}
continue;
}
snprintf(path, sizeof(path), "%s/%.13s_IPCR", rootdir, ent->d_name);
if (access(path, F_OK)) {
snprintf(path, sizeof(path), "%s/%.13s_QMI0", rootdir, ent->d_name);
if (access(path, F_OK)) {
snprintf(path, sizeof(path), "%s/%.13s_MBIM", rootdir, ent->d_name);
if (!access(path, F_OK))
software_interface = SOFTWARE_MBIM;
}
}
if (access(path, F_OK))
continue;
strncat(path, "/mhi_uci_q", sizeof(path)-1);
dir_get_child(path, devname, sizeof(devname), NULL);
if (!devname[0])
continue;
sprintf(usbnet_adapter, "%s", netcard);
sprintf(qmichannel, "/dev/%s", devname);
profile->software_interface = software_interface;
find = 1;
break;
}
closedir(pDir);
}
return find;
}
int atdevice_detect(char *atchannel, char *usbnet_adapter, PROFILE_T *profile) {
if (!access("/sys/class/net/sipa_dummy0", F_OK)) {
strcpy(usbnet_adapter, "sipa_dummy0");
snprintf(profile->qmapnet_adapter, sizeof(profile->qmapnet_adapter), "%s%d", "pcie", profile->pdp - 1);
}
else {
dbg_time("atdevice_detect failed");
goto error;
}
if (!access("/dev/stty_nr31", F_OK)) {
strcpy(atchannel, "/dev/stty_nr31");
profile->software_interface = SOFTWARE_ECM_RNDIS_NCM;
}
else {
goto error;
}
return 1;
error:
return 0;
}
int get_driver_type(PROFILE_T *profile)
{
/* QMI_WWAN */
if (profile->usb_intf.bInterfaceClass == USB_CLASS_VENDOR_SPEC) {
return SOFTWARE_QMI;
}
else if (profile->usb_intf.bInterfaceClass == USB_CLASS_COMM) {
switch (profile->usb_intf.bInterfaceSubClass) {
case USB_CDC_SUBCLASS_MBIM:
return SOFTWARE_MBIM;
break;
case USB_CDC_SUBCLASS_ETHERNET:
case USB_CDC_SUBCLASS_NCM:
return SOFTWARE_ECM_RNDIS_NCM;
break;
default:
break;
}
}
else if (profile->usb_intf.bInterfaceClass == USB_CLASS_WIRELESS_CONTROLLER) {
if (profile->usb_intf.bInterfaceSubClass == 1 && profile->usb_intf.bInterfaceProtocol == 3)
return SOFTWARE_ECM_RNDIS_NCM;
}
dbg_time("%s unknow bInterfaceClass=%d, bInterfaceSubClass=%d", __func__,
profile->usb_intf.bInterfaceClass, profile->usb_intf.bInterfaceSubClass);
return DRV_INVALID;
}
struct usbfs_getdriver
{
unsigned int interface;
char driver[255 + 1];
};
struct usbfs_ioctl
{
int ifno; /* interface 0..N ; negative numbers reserved */
int ioctl_code; /* MUST encode size + direction of data so the
* macros in <asm/ioctl.h> give correct values */
void *data; /* param buffer (in, or out) */
};
#define IOCTL_USBFS_DISCONNECT _IO('U', 22)
#define IOCTL_USBFS_CONNECT _IO('U', 23)
int usbfs_is_kernel_driver_alive(int fd, int ifnum)
{
struct usbfs_getdriver getdrv;
getdrv.interface = ifnum;
if (ioctl(fd, USBDEVFS_GETDRIVER, &getdrv) < 0) {
dbg_time("%s ioctl USBDEVFS_GETDRIVER failed, kernel driver may be inactive", __func__);
return 0;
}
dbg_time("%s find interface %d has match the driver %s", __func__, ifnum, getdrv.driver);
return 1;
}
void usbfs_detach_kernel_driver(int fd, int ifnum)
{
struct usbfs_ioctl operate;
operate.data = NULL;
operate.ifno = ifnum;
operate.ioctl_code = IOCTL_USBFS_DISCONNECT;
if (ioctl(fd, USBDEVFS_IOCTL, &operate) < 0) {
dbg_time("%s detach kernel driver failed", __func__);
} else {
dbg_time("%s detach kernel driver success", __func__);
}
}
void usbfs_attach_kernel_driver(int fd, int ifnum)
{
struct usbfs_ioctl operate;
operate.data = NULL;
operate.ifno = ifnum;
operate.ioctl_code = IOCTL_USBFS_CONNECT;
if (ioctl(fd, USBDEVFS_IOCTL, &operate) < 0) {
dbg_time("%s detach kernel driver failed", __func__);
} else {
dbg_time("%s detach kernel driver success", __func__);
}
}
int reattach_driver(PROFILE_T *profile)
{
int ifnum = 4;
int fd;
char devpath[128] = {'\0'};
snprintf(devpath, sizeof(devpath), "/dev/bus/usb/%03d/%03d", profile->usb_dev.busnum, profile->usb_dev.devnum);
fd = open(devpath, O_RDWR | O_NOCTTY);
if (fd < 0)
{
dbg_time("%s fail to open %s", __func__, devpath);
return -1;
}
usbfs_detach_kernel_driver(fd, ifnum);
usbfs_attach_kernel_driver(fd, ifnum);
close(fd);
return 0;
}
#define SIOCETHTOOL 0x8946
int ql_get_netcard_driver_info(const char *devname)
{
int fd = -1;
struct ethtool_drvinfo drvinfo;
struct ifreq ifr; /* ifreq suitable for ethtool ioctl */
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, devname);
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
dbg_time("Cannot get control socket: errno(%d)(%s)", errno, strerror(errno));
return -1;
}
drvinfo.cmd = ETHTOOL_GDRVINFO;
ifr.ifr_data = (void *)&drvinfo;
if (ioctl(fd, SIOCETHTOOL, &ifr) < 0) {
dbg_time("ioctl() error: errno(%d)(%s)", errno, strerror(errno));
close(fd);
return -1;
}
dbg_time("netcard driver = %s, driver version = %s", drvinfo.driver, drvinfo.version);
close(fd);
return 0;
}
int ql_get_netcard_carrier_state(const char *devname)
{
int fd = -1;
struct ethtool_value edata;
struct ifreq ifr; /* ifreq suitable for ethtool ioctl */
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, devname);
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
dbg_time("Cannot get control socket: errno(%d)(%s)", errno, strerror(errno));
return -1;
}
edata.cmd = ETHTOOL_GLINK;
edata.data = 0;
ifr.ifr_data = (void *)&edata;
if (ioctl(fd, SIOCETHTOOL, &ifr) < 0) {
dbg_time("ioctl('%s') error: errno(%d)(%s)", devname, errno, strerror(errno));
return -1;
}
if (!edata.data)
dbg_time("netcard carrier = %d", edata.data);
close(fd);
return edata.data;
}
static void *catch_log(void *arg)
{
PROFILE_T *profile = (PROFILE_T *)arg;
int nreads = 0;
char tbuff[256+32];
char filter[32];
size_t tsize = strlen(get_time()) + 1;
snprintf(filter, sizeof(filter), ":%d:%03d:", profile->usb_dev.busnum, profile->usb_dev.devnum);
while(1) {
nreads = read(profile->usbmon_fd, tbuff + tsize, sizeof(tbuff) - tsize - 1);
if (nreads <= 0) {
if (nreads == -1 && errno == EINTR)
continue;
break;
}
tbuff[tsize+nreads] = '\0'; // printf("%s", buff);
if (!strstr(tbuff+tsize, filter))
continue;
snprintf(tbuff, sizeof(tbuff), "%s", get_time());
tbuff[tsize-1] = ' ';
fwrite(tbuff, strlen(tbuff), 1, profile->usbmon_logfile_fp);
}
return NULL;
}
int ql_capture_usbmon_log(PROFILE_T *profile, const char *log_path)
{
char usbmon_path[256];
pthread_t pt;
pthread_attr_t attr;
if (access("/sys/module/usbmon", F_OK)) {
dbg_time("usbmon is not load, please execute \"modprobe usbmon\" or \"insmod usbmon.ko\"");
return -1;
}
if (access("/sys/kernel/debug/usb", F_OK)) {
dbg_time("debugfs is not mount, please execute \"mount -t debugfs none_debugs /sys/kernel/debug\"");
return -1;
}
snprintf(usbmon_path, sizeof(usbmon_path), "/sys/kernel/debug/usb/usbmon/%du", profile->usb_dev.busnum);
profile->usbmon_fd = open(usbmon_path, O_RDONLY);
if (profile->usbmon_fd < 0) {
dbg_time("open %s error(%d) (%s)", usbmon_path, errno, strerror(errno));
return -1;
}
snprintf(usbmon_path, sizeof(usbmon_path), "cat /sys/kernel/debug/usb/devices >> %s", log_path);
if (system(usbmon_path) == -1) {};
profile->usbmon_logfile_fp = fopen(log_path, "wb");
if (!profile->usbmon_logfile_fp) {
dbg_time("open %s error(%d) (%s)", log_path, errno, strerror(errno));
close(profile->usbmon_fd);
profile->usbmon_fd = -1;
return -1;
}
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&pt, &attr, catch_log, (void *)profile);
return 0;
}
void ql_stop_usbmon_log(PROFILE_T *profile) {
if (profile->usbmon_fd > 0)
close(profile->usbmon_fd);
if (profile->usbmon_logfile_fp)
fclose(profile->usbmon_logfile_fp);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,71 +0,0 @@
root@ZhuoTK:/# dmesg
[ 788.920000] usb 1-1.3: new high-speed USB device number 4 using ehci-platform
[ 789.160000] cdc_mbim 1-1.3:1.4: cdc-wdm0: USB WDM device
[ 789.170000] cdc_mbim 1-1.3:1.4 wwan0: register 'cdc_mbim' at usb-101c0000.ehci-1.3, CDC MBIM, a2:58:dc:4d:dd:ca
root@ZhuoTK:/# quectel-CM -s cmnet &
[04-13_05:24:38:767] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_05:24:38:769] Find /sys/bus/usb/devices/1-1.3 idVendor=0x2c7c idProduct=0x125, bus=0x001, dev=0x004
[04-13_05:24:38:771] Auto find qmichannel = /dev/cdc-wdm0
[04-13_05:24:38:771] Auto find usbnet_adapter = wwan0
[04-13_05:24:38:771] netcard driver = cdc_mbim, driver version = 22-Aug-2005
[04-13_05:24:38:771] Modem works in MBIM mode
[04-13_05:24:38:779] cdc_wdm_fd = 7
[04-13_05:24:38:779] mbim_open_device()
[04-13_05:24:39:624] mbim_device_caps_query()
[04-13_05:24:39:656] DeviceId: 866758045439136
[04-13_05:24:39:656] FirmwareInfo: EC25EFAR06A11M4G
[04-13_05:24:39:656] HardwareInfo: QUECTEL Mobile Broadband Modul
[04-13_05:24:39:657] mbim_device_services_query()
[04-13_05:24:39:688] mbim_set_radio_state( 1 )
[04-13_05:24:39:721] HwRadioState: 1, SwRadioState: 1
[04-13_05:24:39:721] mbim_subscriber_status_query()
[04-13_05:24:39:784] SubscriberId: 460028563800461
[04-13_05:24:39:784] SimIccId: 89860015120716380461
[04-13_05:24:39:785] SubscriberReadyState NotInitialized -> Initialized
[04-13_05:24:39:785] mbim_register_state_query()
[04-13_05:24:39:816] RegisterState Unknown -> Home
[04-13_05:24:39:816] mbim_packet_service_query()
[04-13_05:24:39:848] PacketServiceState Unknown -> Attached
[04-13_05:24:39:848] mbim_query_connect(sessionID=0)
[04-13_05:24:39:880] ActivationState Unknown -> Deactivated
[04-13_05:24:39:881] ifconfig wwan0 0.0.0.0
[04-13_05:24:39:899] ifconfig wwan0 down
[04-13_05:24:39:913] mbim_set_connect(onoff=1, sessionID=0)
[04-13_05:24:39:976] ActivationState Deactivated -> Activated
[04-13_05:24:39:977] mbim_ip_config(sessionID=0)
[04-13_05:24:40:008] < SessionId = 0
[04-13_05:24:40:008] < IPv4ConfigurationAvailable = 0xf
[04-13_05:24:40:008] < IPv6ConfigurationAvailable = 0x0
[04-13_05:24:40:008] < IPv4AddressCount = 0x1
[04-13_05:24:40:008] < IPv4AddressOffset = 0x3c
[04-13_05:24:40:009] < IPv6AddressCount = 0x0
[04-13_05:24:40:009] < IPv6AddressOffset = 0x0
[04-13_05:24:40:009] < IPv4 = 10.129.90.29/30
[04-13_05:24:40:009] < gw = 10.129.90.30
[04-13_05:24:40:009] < dns1 = 211.138.180.2
[04-13_05:24:40:009 < dns2 = 211.138.180.3
[04-13_05:24:40:009] < ipv4 mtu = 1500
[04-13_05:24:40:041] ifconfig wwan0 up
[04-13_05:24:40:063] ip -4 address flush dev wwan0
[04-13_05:24:40:073] ip -4 address add 10.129.90.29/30 dev wwan0
[04-13_05:24:40:084] ip -4 route add default via 10.129.90.30 dev wwan0
root@ZhuoTK:/# ifconfig wwan0
wwan0 Link encap:Ethernet HWaddr A2:58:DC:4D:DD:CA
inet addr:10.129.90.29 Bcast:0.0.0.0 Mask:255.255.255.252
inet6 addr: fe80::a058:dcff:fe4d:ddca/64 Scope:Link
UP BROADCAST RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:5 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:380 (380.0 B)
root@ZhuoTK:/# ip ro show
default via 10.129.90.30 dev wwan0
10.129.90.28/30 dev wwan0 proto kernel scope link src 10.129.90.29
192.168.1.0/24 dev br-lan proto kernel scope link src 192.168.1.251
root@ZhuoTK:/# ping www.qq.com
PING www.qq.com (183.194.238.117): 56 data bytes
64 bytes from 183.194.238.117: seq=0 ttl=53 time=58.674 ms

View File

@ -1,168 +0,0 @@
root@ZhuoTK:/# dmesg
[ 788.920000] usb 1-1.3: new high-speed USB device number 4 using ehci-platform
[ 789.160000] cdc_mbim 1-1.3:1.4: cdc-wdm0: USB WDM device
[ 789.170000] cdc_mbim 1-1.3:1.4 wwan0: register 'cdc_mbim' at usb-101c0000.ehci-1.3, CDC MBIM, a2:58:dc:4d:dd:ca
root@ZhuoTK:/# ip link add link wwan0 name wwan0.1 type vlan id 1
root@ZhuoTK:/# ip link add link wwan0 name wwan0.2 type vlan id 2
root@ZhuoTK:/# ifconfig wwan0.1
wwan0.1 Link encap:Ethernet HWaddr A2:58:DC:4D:DD:CA
BROADCAST NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
root@ZhuoTK:/# ifconfig wwan0.2
wwan0.2 Link encap:Ethernet HWaddr A2:58:DC:4D:DD:CA
BROADCAST NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
root@ZhuoTK:/# quectel-mbim-proxy &
root@ZhuoTK:/# [04-13_07:04:27:543] mbim_dev_fd=3
[04-13_07:04:27:543] mbim_send_open_msg()
[04-13_07:04:28:321] receive MBIM_OPEN_DONE, status=0
[04-13_07:04:28:321] mbim_server_fd=4
root@ZhuoTK:/# quectel-CM -n 1 -s cmnet &
[04-13_07:04:34:256] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_07:04:34:259] Find /sys/bus/usb/devices/1-1.3 idVendor=0x2c7c idProduct=0x125, bus=0x001, dev=0x004
[04-13_07:04:34:260] Auto find qmichannel = /dev/cdc-wdm0
[04-13_07:04:34:260] Auto find usbnet_adapter = wwan0
[04-13_07:04:34:260] netcard driver = cdc_mbim, driver version = 22-Aug-2005
[04-13_07:04:34:261] mbim_qmap_mode = 4, vlan_id = 0x01, qmap_netcard = wwan0.1
[04-13_07:04:34:261] Modem works in MBIM mode
[04-13_07:04:34:261] handle_client_connect client_fd=5, client_idx=1
[04-13_07:04:34:262] connect to quectel-mbim-proxy sockfd = 7
[04-13_07:04:34:262] cdc_wdm_fd = 7
[04-13_07:04:34:262] mbim_open_device()
[04-13_07:04:35:106] mbim_device_caps_query()
[04-13_07:04:35:139] DeviceId: 866758045439136
[04-13_07:04:35:139] FirmwareInfo: EC25EFAR06A11M4G
[04-13_07:04:35:139] HardwareInfo: QUECTEL Mobile Broadband Modul
[04-13_07:04:35:139] mbim_device_services_query()
[04-13_07:04:35:170] mbim_set_radio_state( 1 )
[04-13_07:04:35:202] HwRadioState: 1, SwRadioState: 1
[04-13_07:04:35:202] mbim_subscriber_status_query()
[04-13_07:04:35:267] SubscriberId: 460028563800461
[04-13_07:04:35:267] SimIccId: 89860015120716380461
[04-13_07:04:35:267] SubscriberReadyState NotInitialized -> Initialized
[04-13_07:04:35:267] mbim_register_state_query()
[04-13_07:04:35:297] RegisterState Unknown -> Home
[04-13_07:04:35:298] mbim_packet_service_query()
[04-13_07:04:35:329] PacketServiceState Unknown -> Attached
[04-13_07:04:35:330] mbim_query_connect(sessionID=1)
[04-13_07:04:35:361] ActivationState Unknown -> Deactivated
[04-13_07:04:35:362] ifconfig wwan0.1 0.0.0.0
[04-13_07:04:35:373] ifconfig wwan0.1 down
[04-13_07:04:35:383] mbim_set_connect(onoff=1, sessionID=1)
[04-13_07:04:35:426] ActivationState Deactivated -> Activated
[04-13_07:04:35:426] mbim_ip_config(sessionID=1)
[04-13_07:04:35:457] < SessionId = 1
[04-13_07:04:35:457] < IPv4ConfigurationAvailable = 0xf
[04-13_07:04:35:457] < IPv6ConfigurationAvailable = 0x0
[04-13_07:04:35:457] < IPv4AddressCount = 0x1
[04-13_07:04:35:458] < IPv4AddressOffset = 0x3c
[04-13_07:04:35:458] < IPv6AddressCount = 0x0
[04-13_07:04:35:458] < IPv6AddressOffset = 0x0
[04-13_07:04:35:458] < IPv4 = 10.129.90.29/30
[04-13_07:04:35:458] < gw = 10.129.90.30
[04-13_07:04:35:458] < dns1 = 211.138.180.2
[04-13_07:04:35:458] < dns2 = 211.138.180.3
[04-13_07:04:35:458] < ipv4 mtu = 1500
[04-13_07:04:35:489] ifconfig wwan0 up
[04-13_07:04:35:509] ifconfig wwan0.1 down
[04-13_07:04:35:522] ifconfig wwan0.1 up
[04-13_07:04:35:535] ip -4 address flush dev wwan0.1
[04-13_07:04:35:545] ip -4 address add 10.129.90.29/30 dev wwan0.1
[04-13_07:04:35:556] ip -4 route add default via 10.129.90.30 dev wwan0.1
root@ZhuoTK:/# quectel-CM -n 2 -s 4gnet &
[04-13_07:04:45:150] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_07:04:45:152] Find /sys/bus/usb/devices/1-1.3 idVendor=0x2c7c idProduct=0x125, bus=0x001, dev=0x004
[04-13_07:04:45:154] Auto find qmichannel = /dev/cdc-wdm0
[04-13_07:04:45:154] Auto find usbnet_adapter = wwan0
[04-13_07:04:45:154] netcard driver = cdc_mbim, driver version = 22-Aug-2005
[04-13_07:04:45:155] mbim_qmap_mode = 4, vlan_id = 0x02, qmap_netcard = wwan0.2
[04-13_07:04:45:155] Modem works in MBIM mode
[04-13_07:04:45:155] handle_client_connect client_fd=6, client_idx=2
[04-13_07:04:45:156] connect to quectel-mbim-proxy sockfd = 7
[04-13_07:04:45:156] cdc_wdm_fd = 7
[04-13_07:04:45:156] mbim_open_device()
[04-13_07:04:46:025] mbim_device_caps_query()
[04-13_07:04:46:056] DeviceId: 866758045439136
[04-13_07:04:46:056] FirmwareInfo: EC25EFAR06A11M4G
[04-13_07:04:46:056] HardwareInfo: QUECTEL Mobile Broadband Modul
[04-13_07:04:46:056] mbim_device_services_query()
[04-13_07:04:46:088] mbim_set_radio_state( 1 )
[04-13_07:04:46:119] HwRadioState: 1, SwRadioState: 1
[04-13_07:04:46:119] mbim_subscriber_status_query()
[04-13_07:04:46:183] SubscriberId: 460028563800461
[04-13_07:04:46:184] SimIccId: 89860015120716380461
[04-13_07:04:46:184] SubscriberReadyState NotInitialized -> Initialized
[04-13_07:04:46:184] mbim_register_state_query()
[04-13_07:04:46:216] RegisterState Unknown -> Home
[04-13_07:04:46:216] mbim_packet_service_query()
[04-13_07:04:46:248] PacketServiceState Unknown -> Attached
[04-13_07:04:46:248] mbim_query_connect(sessionID=2)
[04-13_07:04:46:280] ActivationState Unknown -> Deactivated
[04-13_07:04:46:280] ifconfig wwan0.2 0.0.0.0
[04-13_07:04:46:291] ifconfig wwan0.2 down
[04-13_07:04:46:304] mbim_set_connect(onoff=1, sessionID=2)
[04-13_07:04:46:504] ActivationState Deactivated -> Activated
[04-13_07:04:46:505] mbim_ip_config(sessionID=2)
[04-13_07:04:46:537] < SessionId = 2
[04-13_07:04:46:537] < IPv4ConfigurationAvailable = 0xf
[04-13_07:04:46:537] < IPv6ConfigurationAvailable = 0x0
[04-13_07:04:46:538] < IPv4AddressCount = 0x1
[04-13_07:04:46:538] < IPv4AddressOffset = 0x3c
[04-13_07:04:46:538] < IPv6AddressCount = 0x0
[04-13_07:04:46:538] < IPv6AddressOffset = 0x0
[04-13_07:04:46:538] < IPv4 = 10.129.37.205/30
[04-13_07:04:46:538] < gw = 10.129.37.206
[04-13_07:04:46:538] < dns1 = 211.138.180.2
[04-13_07:04:46:538] < dns2 = 211.138.180.3
[04-13_07:04:46:538] < ipv4 mtu = 1500
[04-13_07:04:46:569] ifconfig wwan0 up
[04-13_07:04:46:579] ifconfig wwan0.2 up
[04-13_07:04:46:592] ip -4 address flush dev wwan0.2
[04-13_07:04:46:602] ip -4 address add 10.129.37.205/30 dev wwan0.2
[04-13_07:04:46:613] ip -4 route add default via 10.129.37.206 dev wwan0.2
root@ZhuoTK:/# ifconfig wwan0.1
wwan0.1 Link encap:Ethernet HWaddr A2:58:DC:4D:DD:CA
inet addr:10.129.90.29 Bcast:0.0.0.0 Mask:255.255.255.252
inet6 addr: fe80::a058:dcff:fe4d:ddca/64 Scope:Link
UP BROADCAST RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:4 errors:0 dropped:0 overruns:0 frame:0
TX packets:13 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:304 (304.0 B) TX bytes:1170 (1.1 KiB)
root@ZhuoTK:/# ifconfig wwan0.2
wwan0.2 Link encap:Ethernet HWaddr A2:58:DC:4D:DD:CA
inet addr:10.129.37.205 Bcast:0.0.0.0 Mask:255.255.255.252
inet6 addr: fe80::a058:dcff:fe4d:ddca/64 Scope:Link
UP BROADCAST RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:720 (720.0 B)
root@ZhuoTK:/# ip ro del 8.8.8.8/32
RTNETLINK answers: No such process
root@ZhuoTK:/# ip ro add 8.8.8.8/32 dev wwan0.1
root@ZhuoTK:/# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=52 time=98.584 ms
root@ZhuoTK:/# ip ro del 8.8.8.8/32
root@ZhuoTK:/# ip ro del 8.8.8.8/32
RTNETLINK answers: No such process
root@ZhuoTK:/# ip ro add 8.8.8.8/32 dev wwan0.2
root@ZhuoTK:/# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=111 time=101.770 ms

View File

@ -1,129 +0,0 @@
# ./quectel-CM -s cmnet &
[04-21_17:35:14:362] Quectel_QConnectManager_Linux_V1.6.0.26
[04-21_17:35:14:363] Find /sys/bus/usb/devices/2-4 idVendor=0x2c7c idProduct=0x8101, bus=0x002, dev=0x016
[04-21_17:35:14:363] Auto find qmichannel = /dev/ttyUSB0
[04-21_17:35:14:363] Auto find usbnet_adapter = usb0
[04-21_17:35:14:363] netcard driver = cdc_ncm, driver version = 22-Aug-2005
[04-21_17:35:14:363] Modem works in ECM_RNDIS_NCM mode
[04-21_17:35:14:371] atc_fd = 7
[04-21_17:35:14:371] AT> ATE0Q0V1
[04-21_17:35:14:372] AT< RDATE0Q0V1
[04-21_17:35:14:372] AT< COMMAND NOT SUPPORT
[04-21_17:35:15:373] AT> AT+QCFG="usbnet"
[04-21_17:35:15:373] AT< +QCFG: "usbnet",5
[04-21_17:35:15:373] AT< OK
[04-21_17:35:15:373] AT> AT+QNETDEVCTL=?
[04-21_17:35:15:374] AT< +QNETDEVCTL: (1-11),(0,1),(0,1)
[04-21_17:35:15:374] AT< OK
[04-21_17:35:15:374] AT> AT+CGREG=2
[04-21_17:35:15:376] AT< OK
[04-21_17:35:15:376] AT> AT+CEREG=2
[04-21_17:35:15:381] AT< OK
[04-21_17:35:15:381] AT> AT+C5GREG=2
[04-21_17:35:15:384] AT< OK
[04-21_17:35:15:384] AT> AT+QNETDEVSTATUS=?
[04-21_17:35:15:385] AT< +QNETDEVSTATUS: (1-11)
[04-21_17:35:15:385] AT< OK
[04-21_17:35:15:385] AT> AT+QCFG="NAT"
[04-21_17:35:15:385] AT< +QCFG: "nat",0
[04-21_17:35:15:385] AT< OK
[04-21_17:35:15:385] AT> AT+CGMR
[04-21_17:35:15:386] AT< RG801HEAAAR03A01M8G
[04-21_17:35:15:386] AT< OK
[04-21_17:35:15:386] AT> AT+CPIN?
[04-21_17:35:15:388] AT< +CPIN: READY
[04-21_17:35:15:388] AT< OK
[04-21_17:35:15:389] AT> AT+QCCID
[04-21_17:35:15:393] AT< +QCCID: 89860015120716380461
[04-21_17:35:15:393] AT< OK
[04-21_17:35:15:393] requestGetICCID 89860015120716380461
[04-21_17:35:15:393] AT> AT+CIMI
[04-21_17:35:15:409] AT< 460028563800461
[04-21_17:35:15:409] AT< OK
[04-21_17:35:15:409] requestGetIMSI 460028563800461
[04-21_17:35:15:409] AT> AT+QICSGP=1
[04-21_17:35:15:411] AT< +QICSGP: 1,1,"cment","","",0,,0,
[04-21_17:35:15:411] AT< OK
[04-21_17:35:15:411] AT> AT+QICSGP=1
[04-21_17:35:15:415] AT< +QICSGP: 1,1,"cment","","",0,,0,
[04-21_17:35:15:415] AT< OK
[04-21_17:35:15:415] AT> AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?
[04-21_17:35:15:421] AT< +COPS: 0,0,"CHINA MOBILE",12
[04-21_17:35:15:421] AT< +COPS: 0,1,"CMCC",12
[04-21_17:35:15:421] AT< +COPS: 0,2,"46000",12
[04-21_17:35:15:421] AT< OK
[04-21_17:35:15:421] AT> AT+C5GREG?
[04-21_17:35:15:424] AT< +C5GREG: 2,1,"46550B","0000000170C23000",11,1,"01"
[04-21_17:35:15:424] AT< OK
[04-21_17:35:15:424] AT> at+cops?
[04-21_17:35:15:427] AT< +COPS: 0,2,"46000",12
[04-21_17:35:15:427] AT< OK
[04-21_17:35:15:427] AT> at+qeng="servingcell"
[04-21_17:35:15:441] AT< +QENG: "servingcell","NOCONN","NR5G-SA","TDD",460,00,170C23000,901,46550B,504990,41,-,-54,-10,16,-,-
[04-21_17:35:15:441] AT< OK
[04-21_17:35:15:441] AT> AT+QNETDEVSTATUS=1
[04-21_17:35:15:445] AT< ERROR
[04-21_17:35:15:445] ifconfig usb0 0.0.0.0
[04-21_17:35:15:446] ifconfig usb0 down
[04-21_17:35:15:448] AT> AT+QNETDEVCTL=1,1,0
[04-21_17:35:15:454] AT< OK
[04-21_17:35:15:456] AT> AT+QNETDEVSTATUS=1
[04-21_17:35:15:458] AT< ERROR
[04-21_17:35:15:989] AT< +QNETDEVSTATUS:1,1,"IPV4"
[04-21_17:35:16:459] AT> AT+QNETDEVSTATUS=1
[04-21_17:35:16:461] AT< +QNETDEVSTATUS: 4F10190A,E0FFFFFF,4110190A,4110190A,02B48AD3,03B48AD3, 85600, 85600
[04-21_17:35:16:461] AT< OK
[04-21_17:35:16:461] AT> AT+QNETDEVSTATUS=1
[04-21_17:35:16:462] AT< +QNETDEVSTATUS: 4F10190A,E0FFFFFF,4110190A,4110190A,02B48AD3,03B48AD3, 85600, 85600
[04-21_17:35:16:462] AT< OK
[04-21_17:35:16:462] requestGetIPAddress 10.25.16.79
[04-21_17:35:16:462] AT> at+cops?
[04-21_17:35:16:463] AT< +COPS: 0,2,"46000",12
[04-21_17:35:16:463] AT< OK
[04-21_17:35:16:463] AT> at+qeng="servingcell"
[04-21_17:35:16:465] AT< +QENG: "servingcell","CONNECT","NR5G-SA","TDD",460,00,170C23000,901,46550B,504990,41,-,-52,-11,15,-,-
[04-21_17:35:16:465] AT< OK
[04-21_17:35:16:465] AT> AT+QNETDEVSTATUS=1
[04-21_17:35:16:466] AT< +QNETDEVSTATUS: 4F10190A,E0FFFFFF,4110190A,4110190A,02B48AD3,03B48AD3, 85600, 85600
[04-21_17:35:16:466] AT< OK
[04-21_17:35:16:466] ifconfig usb0 up
[04-21_17:35:16:470] busybox udhcpc -f -n -q -t 5 -i usb0
udhcpc: started, v1.30.1
udhcpc: sending discover
udhcpc: sending select for 10.25.16.79
udhcpc: lease of 10.25.16.79 obtained, lease time 518400
[04-21_17:35:16:602] /etc/udhcpc/default.script: Resetting default routes
SIOCDELRT: No such process
SIOCADDRT: Network is unreachable
[04-21_17:35:16:606] /etc/udhcpc/default.script: Adding DNS 211.138.180.2
[04-21_17:35:16:606] /etc/udhcpc/default.script: Adding DNS 211.138.180.3
[04-21_17:35:16:655] AT> at+cops?
[04-21_17:35:16:656] AT< +COPS: 0,2,"46000",12
[04-21_17:35:16:656] AT< OK
[04-21_17:35:16:656] AT> at+qeng="servingcell"
[04-21_17:35:16:657] AT< +QENG: "servingcell","CONNECT","NR5G-SA","TDD",460,00,170C23000,901,46550B,504990,41,-,-50,-11,17,-,-
[04-21_17:35:16:658] AT< OK
err = 16
[04-21_17:35:16:658] AT> AT+QNETDEVSTATUS=1
[04-21_17:35:16:659] AT< +QNETDEVSTATUS: 4F10190A,E0FFFFFF,4110190A,4110190A,02B48AD3,03B48AD3, 85600, 85600
[04-21_17:35:16:659] AT< OK
root@carl-ThinkPad-X1-Carbon-7th:/home/carl/q/quectel-CM# ifconfig usb0
usb0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.25.16.79 netmask 255.255.255.224 broadcast 10.25.16.95
inet6 fe80::5c98:e9d4:c82d:5f prefixlen 64 scopeid 0x20<link>
ether 0c:5b:8f:27:9a:64 txqueuelen 1000 (Ethernet)
RX packets 7 bytes 1656 (1.6 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 32 bytes 5112 (5.1 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
root@carl-ThinkPad-X1-Carbon-7th:/home/carl/q/quectel-CM# [04-21_17:35:31:670] AT> at+cops?
[04-21_17:35:31:671] AT< +COPS: 0,2,"46000",12
[04-21_17:35:31:671] AT< OK
[04-21_17:35:31:671] AT> at+qeng="servingcell"
[04-21_17:35:31:673] AT< +QENG: "servingcell","CONNECT","NR5G-SA","TDD",460,00,170C23000,901,46550B,504990,41,-,-48,-10,17,-,-
[04-21_17:35:31:673] AT< OK
[04-21_17:35:31:673] AT> AT+QNETDEVSTATUS=1
[04-21_17:35:31:674] AT< +QNETDEVSTATUS: 4F10190A,E0FFFFFF,4110190A,4110190A,02B48AD3,03B48AD3, 85600, 85600
[04-21_17:35:31:674] AT< OK

View File

@ -1,62 +0,0 @@
root@ZhuoTK:/# dmesg
[ 230.590000] GobiNet 1-1.3:1.4 usb0: register 'GobiNet' at usb-101c0000.ehci-1.3, GobiNet Ethernet Device, 02:50:f4:00:00:00
[ 230.600000] creating qcqmi0
root@ZhuoTK:/# quectel-CM -s cmnet &
[04-13_03:24:58:213] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_03:24:58:216] Find /sys/bus/usb/devices/1-1.3 idVendor=0x2c7c idProduct=0x125, bus=0x001, dev=0x004
[04-13_03:24:58:218] Auto find qmichannel = /dev/qcqmi0
[04-13_03:24:58:218] Auto find usbnet_adapter = usb0
[04-13_03:24:58:218] netcard driver = GobiNet, driver version = V1.6.2.13
[04-13_03:24:58:219] Modem works in QMI mode
[04-13_03:24:58:260] Get clientWDS = 7
[04-13_03:24:58:292] Get clientDMS = 8
[04-13_03:24:58:324] Get clientNAS = 9
[04-13_03:24:58:355] Get clientUIM = 10
[04-13_03:24:58:388] Get clientWDA = 11
[04-13_03:24:58:420] requestBaseBandVersion EC25EFAR06A11M4G
[04-13_03:24:58:548] requestGetSIMStatus SIMStatus: SIM_READY
[04-13_03:24:58:549] requestSetProfile[1] cmnet///0
[04-13_03:24:58:613] requestGetProfile[1] cmnet///0
[04-13_03:24:58:645] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: LTE
[04-13_03:24:58:677] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED
[04-13_03:24:58:677] ifconfig usb0 0.0.0.0
[04-13_03:24:58:696] ifconfig usb0 down
[04-13_03:24:59:028] requestSetupDataCall WdsConnectionIPv4Handle: 0x87245bd0
[04-13_03:24:59:189] ifconfig usb0 up
[04-13_03:24:59:214] you are use OpenWrt?
[04-13_03:24:59:215] should not calling udhcpc manually?
[04-13_03:24:59:215] should modify /etc/config/network as below?
[04-13_03:24:59:215] config interface wan
[04-13_03:24:59:215] option ifname usb0
[04-13_03:24:59:215] option proto dhcp
[04-13_03:24:59:215] should use "/sbin/ifstaus wan" to check usb0 's status?
[04-13_03:24:59:216] busybox udhcpc -f -n -q -t 5 -i usb0
[04-13_03:24:59:226] udhcpc (v1.23.2) started
[04-13_03:24:59:238] Sending discover...
[04-13_03:24:59:248] Sending select for 10.198.78.154...
[04-13_03:24:59:251] Lease of 10.198.78.154 obtained, lease time 7200
[04-13_03:24:59:257] udhcpc: ifconfig usb0 10.198.78.154 netmask 255.255.255.252 broadcast +
[04-13_03:24:59:266] udhcpc: setting default routers: 10.198.78.153
root@ZhuoTK:/# ifconfig usb0
usb0 Link encap:Ethernet HWaddr 02:50:F4:00:00:00
inet addr:10.198.78.154 Mask:255.255.255.252
inet6 addr: fe80::50:f4ff:fe00:0/64 Scope:Link
UP RUNNING NOARP MTU:1500 Metric:1
RX packets:6 errors:0 dropped:0 overruns:0 frame:0
TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:916 (916.0 B) TX bytes:960 (960.0 B)
root@ZhuoTK:/# ip ro show
default via 10.198.78.153 dev usb0
10.198.78.152/30 dev usb0 proto kernel scope link src 10.198.78.154
192.168.1.0/24 dev br-lan proto kernel scope link src 192.168.1.251
root@ZhuoTK:/# killall quectel-CM
[04-13_03:25:38:779] requestDeactivateDefaultPDP WdsConnectionIPv4Handle
[04-13_03:25:39:061] ifconfig usb0 0.0.0.0
[04-13_03:25:39:072] ifconfig usb0 down
[04-13_03:25:39:284] GobiNetThread exit
[04-13_03:25:39:285] qmi_main exit

View File

@ -1,60 +0,0 @@
root@ZhuoTK:/# insmod GobiNet.ko
[ 80.460000] GobiNet: Quectel_Linux&Android_GobiNet_Driver_V1.6.2.13
[ 80.460000] usbcore: registered new interface driver GobiNet
[ 97.710000] usb 1-1.3: new high-speed USB device number 3 using ehci-platform
[ 97.930000] usb 1-1.3: GSM modem (1-port) converter now attached to ttyUSB103
[ 97.950000] GobiNet 1-1.3:1.4 usb0: register 'GobiNet' at usb-101c0000.ehci-1.3, GobiNet Ethernet Device, 02:50:f4:00:00:00
[ 97.960000] creating qcqmi0
root@ZhuoTK:/# brctl addbr br0
root@ZhuoTK:/# brctl addif br0 eth0.1
root@ZhuoTK:/# brctl addif br0 usb0
root@ZhuoTK:/# brctl show
bridge name bridge id STP enabled interfaces
br0 8000.00ca019197b9 no eth0.1
usb0
root@ZhuoTK:/# quectel-CM -s cment -b &
[04-13_05:13:18:213] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_05:13:18:216] Find /sys/bus/usb/devices/1-1.3 idVendor=0x2c7c idProduct=0x125, bus=0x001, dev=0x003
[ 122.270000] net usb0: bridge_mode change to 0x1
[04-13_05:13:18:218] Auto find qmichannel = /dev/qcqmi0
[04-13_05:13:18:218] Auto find usbnet_adapter = usb0
[04-13_05:13:18:218] netcard driver = GobiNet, driver version = V1.6.2.13
[04-13_05:13:18:224] Modem works in QMI mode
[04-13_05:13:18:251] Get clientWDS = 7
[04-13_05:13:18:282] Get clientDMS = 8
[04-13_05:13:18:316] Get clientNAS = 9
[04-13_05:13:18:347] Get clientUIM = 10
[04-13_05:13:18:379] Get clientWDA = 11
[04-13_05:13:18:411] requestBaseBandVersion EC25EFAR06A11M4G
[04-13_05:13:18:539] requestGetSIMStatus SIMStatus: SIM_READY
[04-13_05:13:18:540] requestSetProfile[1] cment///0
[04-13_05:13:18:603] requestGetProfile[1] cment///0
[04-13_05:13:18:637] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: LTE
[04-13_05:13:18:666] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED
[04-13_05:13:18:667] ifconfig usb0 0.0.0.0
[04-13_05:13:18:687] ifconfig usb0 down
[04-13_05:13:19:083] requestSetupDataCall WdsConnectionIPv4Handle: 0x8724d220
[04-13_05:13:19:243] ifconfig usb0 up
[04-13_05:13:19:270] echo '0xa218480' > /sys/class/net/usb0/bridge_ipv4
root@ZhuoTK:/# ifconfig br0 up
[ 135.530000] usb0 PC Mac Address: 00:0e:c6:a6:6c:f1
[ 135.570000] usb0 PC Mac Address: 00:0e:c6:a6:6c:f1
[ 135.580000] usb0 PC Mac Address: 00:0e:c6:a6:6c:f1
[ 135.610000] usb0 sip = 10.33.132.128, tip=10.33.132.129, ipv4=10.33.132.128
[ 135.620000] usb0 sip = 10.33.132.128, tip=10.33.132.129, ipv4=10.33.132.128
[ 135.910000] usb0 sip = 0.0.0.0, tip=10.33.132.128, ipv4=10.33.132.128
[ 136.000000] usb0 sip = 10.33.132.128, tip=10.33.132.129, ipv4=10.33.132.128
[ 136.910000] usb0 sip = 0.0.0.0, tip=10.33.132.128, ipv4=10.33.132.128
[ 137.910000] usb0 sip = 0.0.0.0, tip=10.33.132.128, ipv4=10.33.132.128
[ 138.740000] usb0 sip = 10.33.132.128, tip=10.33.132.129, ipv4=10.33.132.128
[ 138.910000] usb0 sip = 10.33.132.128, tip=10.33.132.128, ipv4=10.33.132.128
[ 139.000000] usb0 sip = 10.33.132.128, tip=10.33.132.129, ipv4=10.33.132.128
[ 140.860000] usb0 sip = 10.33.132.128, tip=10.33.132.129, ipv4=10.33.132.128
[ 143.160000] br0: port 2(usb0) entered forwarding state
[ 143.160000] br0: port 1(eth0.1) entered forwarding state
[ 148.870000] usb0 sip = 10.33.132.128, tip=10.33.132.129, ipv4=10.33.132.128
[ 149.010000] usb0 sip = 10.33.132.128, tip=10.33.132.129, ipv4=10.33.132.128
[ 165.630000] usb0 sip = 10.33.132.128, tip=10.33.132.129, ipv4=10.33.132.128

View File

@ -1,45 +0,0 @@
root@ZhuoTK:/# insmod GobiNet.ko qmap_mode=1
[ 798.480000] GobiNet: Quectel_Linux&Android_GobiNet_Driver_V1.6.2.13
[ 798.490000] GobiNet 1-1.3:1.4 usb0: register 'GobiNet' at usb-101c0000.ehci-1.3, GobiNet Ethernet Device, 02:50:f4:00:00:00
[ 798.510000] creating qcqmi0
[ 798.510000] usbcore: registered new interface driver GobiNet
[ 799.620000] GobiNet::QMIWDASetDataFormat qmap settings qmap_version=5, rx_size=4096, tx_size=4096
[ 799.630000] GobiNet::QMIWDASetDataFormat qmap settings ul_data_aggregation_max_size=4096, ul_data_aggregation_max_datagrams=16
root@ZhuoTK:/# quectel-CM -s cmnet &
[04-13_03:32:31:248] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_03:32:31:251] Find /sys/bus/usb/devices/1-1.3 idVendor=0x2c7c idProduct=0x125, bus=0x001, dev=0x005
[04-13_03:32:31:253] Auto find qmichannel = /dev/qcqmi0
[04-13_03:32:31:253] Auto find usbnet_adapter = usb0
[04-13_03:32:31:253] netcard driver = GobiNet, driver version = V1.6.2.13
[04-13_03:32:31:253] qmap_mode = 1, qmap_version = 5, qmap_size = 4096, muxid = 0x81, qmap_netcard = usb0
[04-13_03:32:31:254] Modem works in QMI mode
[04-13_03:32:31:289] Get clientWDS = 7
[04-13_03:32:31:320] Get clientDMS = 8
[04-13_03:32:31:353] Get clientNAS = 9
[04-13_03:32:31:385] Get clientUIM = 10
[04-13_03:32:31:417] requestBaseBandVersion EC25EFAR06A11M4G
[04-13_03:32:31:545] requestGetSIMStatus SIMStatus: SIM_READY
[04-13_03:32:31:545] requestSetProfile[1] cmnet///0
[04-13_03:32:31:609] requestGetProfile[1] cmnet///0
[04-13_03:32:31:641] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: LTE
[04-13_03:32:31:673] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED
[04-13_03:32:31:674] ifconfig usb0 0.0.0.0
[04-13_03:32:31:698] ifconfig usb0 down
[04-13_03:32:31:770] requestSetupDataCall WdsConnectionIPv4Handle: 0x872481a0
[ 857.000000] net usb0: link_state 0x0 -> 0x1
[04-13_03:32:31:902] ifconfig usb0 up
[04-13_03:32:31:928] you are use OpenWrt?
[04-13_03:32:31:928] should not calling udhcpc manually?
[04-13_03:32:31:928] should modify /etc/config/network as below?
[04-13_03:32:31:928] config interface wan
[04-13_03:32:31:928] option ifname usb0
[04-13_03:32:31:929] option proto dhcp
[04-13_03:32:31:929] should use "/sbin/ifstaus wan" to check usb0 's status?
[04-13_03:32:31:929] busybox udhcpc -f -n -q -t 5 -i usb0
[04-13_03:32:31:939] udhcpc (v1.23.2) started
[04-13_03:32:31:951] Sending discover...
[04-13_03:32:31:956] Sending select for 10.199.102.71...
[04-13_03:32:31:959] Lease of 10.199.102.71 obtained, lease time 7200
[04-13_03:32:31:964] udhcpc: ifconfig usb0 10.199.102.71 netmask 255.255.255.240 broadcast +
[04-13_03:32:31:974] udhcpc: setting default routers: 10.199.102.72

View File

@ -1,62 +0,0 @@
root@ZhuoTK:/# insmod GobiNet.ko qmap_mode=1
[ 41.540000] GobiNet: Quectel_Linux&Android_GobiNet_Driver_V1.6.2.13
[ 41.550000] GobiNet 1-1.3:1.4 usb0: register 'GobiNet' at usb-101c0000.ehci-1.3, GobiNet Ethernet Device, 02:50:f4:00:00:00
[ 41.570000] creating qcqmi0
[ 41.570000] usbcore: registered new interface driver GobiNet
[ 42.700000] GobiNet::QMIWDASetDataFormat qmap settings qmap_version=5, rx_size=4096, tx_size=4096
[ 42.710000] GobiNet::QMIWDASetDataFormat qmap settings ul_data_aggregation_max_size=4096, ul_data_aggregation_max_datagrams=16
root@ZhuoTK:/# brctl addbr br0
root@ZhuoTK:/# brctl addif br0 eth0.1
root@ZhuoTK:/# brctl addif br0 usb0
root@ZhuoTK:/# brctl show
bridge name bridge id STP enabled interfaces
br0 8000.00ca019197b9 no eth0.1
usb0
root@ZhuoTK:/# quectel-CM -s cmnet -b &
# [04-13_05:12:29:338] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_05:12:29:340] Find /sys/bus/usb/devices/1-1.3 idVendor=0x2c7c idProduct=0x125, bus=0x001, dev=0x003
[ 73.380000] net usb0: bridge_mode change to 0x1
[04-13_05:12:29:342] Auto find qmichannel = /dev/qcqmi0
[04-13_05:12:29:342] Auto find usbnet_adapter = usb0
[04-13_05:12:29:342] netcard driver = GobiNet, driver version = V1.6.2.13
[04-13_05:12:29:343] qmap_mode = 1, qmap_version = 5, qmap_size = 4096, muxid = 0x81, qmap_netcard = usb0
[04-13_05:12:29:348] Modem works in QMI mode
[04-13_05:12:29:382] Get clientWDS = 7
[04-13_05:12:29:414] Get clientDMS = 8
[04-13_05:12:29:447] Get clientNAS = 9
[04-13_05:12:29:479] Get clientUIM = 10
[04-13_05:12:29:512] requestBaseBandVersion EC25EFAR06A11M4G
[04-13_05:12:29:640] requestGetSIMStatus SIMStatus: SIM_READY
[04-13_05:12:29:640] requestSetProfile[1] cmnet///0
[04-13_05:12:29:704] requestGetProfile[1] cmnet///0
[04-13_05:12:29:735] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: LTE
[04-13_05:12:29:767] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED
[04-13_05:12:29:768] ifconfig usb0 0.0.0.0
[04-13_05:12:29:792] ifconfig usb0 down
[04-13_05:12:29:863] requestSetupDataCall WdsConnectionIPv4Handle: 0x8724d820
[ 74.030000] net usb0: link_state 0x0 -> 0x1
[04-13_05:12:29:996] ifconfig usb0 up
[04-13_05:12:30:022] echo '0xa16b769' > /sys/class/net/usb0/bridge_ipv4
root@ZhuoTK:/# ifconfig br0 up
[ 82.210000] br0: port 2(usb0) entered forwarding state
[ 82.210000] br0: port 2(usb0) entered forwarding state
[ 82.220000] br0: port 1(eth0.1) entered forwarding state
[ 82.220000] br0: port 1(eth0.1) entered forwarding state
[ 88.830000] rt305x-esw 10110000.esw: link changed 0x01
[ 89.010000] usb0 PC Mac Address: 00:0e:c6:a6:6c:f1
[ 89.040000] usb0 PC Mac Address: 00:0e:c6:a6:6c:f1
[ 89.050000] usb0 PC Mac Address: 00:0e:c6:a6:6c:f1
[ 89.120000] usb0 sip = 10.22.183.105, tip=10.22.183.106, ipv4=10.22.183.105
[ 89.350000] usb0 sip = 0.0.0.0, tip=10.22.183.105, ipv4=10.22.183.105
[ 89.400000] usb0 sip = 10.22.183.105, tip=10.22.183.106, ipv4=10.22.183.105
[ 89.520000] usb0 sip = 10.22.183.105, tip=10.22.183.106, ipv4=10.22.183.105
[ 90.350000] usb0 sip = 0.0.0.0, tip=10.22.183.105, ipv4=10.22.183.105
[ 91.350000] usb0 sip = 0.0.0.0, tip=10.22.183.105, ipv4=10.22.183.105
[ 92.350000] usb0 sip = 10.22.183.105, tip=10.22.183.105, ipv4=10.22.183.105
[ 92.430000] usb0 sip = 10.22.183.105, tip=10.22.183.106, ipv4=10.22.183.105
[ 92.660000] usb0 sip = 10.22.183.105, tip=10.22.183.106, ipv4=10.22.183.105
[ 97.240000] br0: port 2(usb0) entered forwarding state
[ 97.240000] br0: port 1(eth0.1) entered forwarding state

View File

@ -1,146 +0,0 @@
root@ZhuoTK:/# insmod GobiNet.ko qmap_mode=4
[ 970.380000] GobiNet: Quectel_Linux&Android_GobiNet_Driver_V1.6.2.13
[ 970.380000] usbcore: registered new interface driver GobiNet
[ 989.620000] usb 1-1.3: new high-speed USB device number 6 using ehci-platform
[ 989.860000] GobiNet 1-1.3:1.4 usb0: register 'GobiNet' at usb-101c0000.ehci-1.3, GobiNet Ethernet Device, 02:50:f4:00:00:00
[ 989.870000] creating qcqmi0
[ 989.880000] GobiNet::qmap_register_device usb0.1
[ 989.880000] GobiNet::qmap_register_device usb0.2
[ 989.890000] GobiNet::qmap_register_device usb0.3
[ 989.890000] GobiNet::qmap_register_device usb0.4
[ 994.820000] GobiNet::QMIWDASetDataFormat qmap settings qmap_version=5, rx_size=4096, tx_size=4096
[ 994.830000] GobiNet::QMIWDASetDataFormat qmap settings ul_data_aggregation_max_size=4096, ul_data_aggregation_max_datagrams=16
root@ZhuoTK:/# quectel-CM -n 1 -s cmnet &
[04-13_03:35:31:878] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_03:35:31:881] Find /sys/bus/usb/devices/1-1.3 idVendor=0x2c7c idProduct=0x125, bus=0x001, dev=0x006
[04-13_03:35:31:882] Auto find qmichannel = /dev/qcqmi0
[04-13_03:35:31:882] Auto find usbnet_adapter = usb0
[04-13_03:35:31:883] netcard driver = GobiNet, driver version = V1.6.2.13
[04-13_03:35:31:883] qmap_mode = 4, qmap_version = 5, qmap_size = 4096, muxid = 0x81, qmap_netcard = usb0.1
[04-13_03:35:31:883] Modem works in QMI mode
[04-13_03:35:31:896] Get clientWDS = 7
[04-13_03:35:31:927] Get clientDMS = 8
[04-13_03:35:31:959] Get clientNAS = 9
[04-13_03:35:31:992] Get clientUIM = 10
[04-13_03:35:32:024] requestBaseBandVersion EC25EFAR06A11M4G
[04-13_03:35:32:152] requestGetSIMStatus SIMStatus: SIM_READY
[04-13_03:35:32:152] requestSetProfile[1] cmnet///0
[04-13_03:35:32:216] requestGetProfile[1] cmnet///0
[04-13_03:35:32:248] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: LTE
[04-13_03:35:32:279] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED
[04-13_03:35:32:280] ifconfig usb0 down
[04-13_03:35:32:290] ifconfig usb0.1 0.0.0.0
[04-13_03:35:32:301] ifconfig usb0.1 down
[04-13_03:35:32:344] requestSetupDataCall WdsConnectionIPv4Handle: 0x8723eef0
[ 1037.570000] net usb0: link_state 0x0 -> 0x1
[04-13_03:35:32:477] ifconfig usb0 up
[04-13_03:35:32:496] ifconfig usb0.1 up
[04-13_03:35:32:508] you are use OpenWrt?
[04-13_03:35:32:509] should not calling udhcpc manually?
[04-13_03:35:32:509] should modify /etc/config/network as below?
[04-13_03:35:32:509] config interface wan
[04-13_03:35:32:509] option ifname usb0.1
[04-13_03:35:32:509] option proto dhcp
[04-13_03:35:32:509] should use "/sbin/ifstaus wan" to check usb0.1 's status?
[04-13_03:35:32:510] busybox udhcpc -f -n -q -t 5 -i usb0.1
[04-13_03:35:32:520] udhcpc (v1.23.2) started
[04-13_03:35:32:532] Sending discover...
[04-13_03:35:32:540] Sending select for 10.187.142.20...
[04-13_03:35:32:545] Lease of 10.187.142.20 obtained, lease time 7200
[04-13_03:35:32:550] udhcpc: ifconfig usb0.1 10.187.142.20 netmask 255.255.255.248 broadcast +
[04-13_03:35:32:560] udhcpc: setting default routers: 10.187.142.21
root@ZhuoTK:/# quectel-CM -n 2 -s 4gnet &
[04-13_03:35:38:766] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_03:35:38:769] Find /sys/bus/usb/devices/1-1.3 idVendor=0x2c7c idProduct=0x125, bus=0x001, dev=0x006
[04-13_03:35:38:770] Auto find qmichannel = /dev/qcqmi0
[04-13_03:35:38:770] Auto find usbnet_adapter = usb0
[04-13_03:35:38:771] netcard driver = GobiNet, driver version = V1.6.2.13
[04-13_03:35:38:771] qmap_mode = 4, qmap_version = 5, qmap_size = 4096, muxid = 0x82, qmap_netcard = usb0.2
[04-13_03:35:38:771] Modem works in QMI mode
[04-13_03:35:38:809] Get clientWDS = 7
[04-13_03:35:38:841] Get clientDMS = 8
[04-13_03:35:38:873] Get clientNAS = 9
[04-13_03:35:38:905] Get clientUIM = 10
[04-13_03:35:38:937] requestBaseBandVersion EC25EFAR06A11M4G
[04-13_03:35:39:065] requestGetSIMStatus SIMStatus: SIM_READY
[04-13_03:35:39:065] requestSetProfile[2] 4gnet///0
[04-13_03:35:39:129] requestGetProfile[2] 4gnet///0
[04-13_03:35:39:161] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: LTE
[04-13_03:35:39:193] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED
[04-13_03:35:39:193] ifconfig usb0.2 0.0.0.0
[04-13_03:35:39:206] ifconfig usb0.2 down
[04-13_03:35:39:417] requestSetupDataCall WdsConnectionIPv4Handle: 0x87252eb0
[ 1044.650000] net usb0: link_state 0x1 -> 0x3
[04-13_03:35:39:550] ifconfig usb0 up
[04-13_03:35:39:560] ifconfig usb0.2 up
[04-13_03:35:39:573] you are use OpenWrt?
[04-13_03:35:39:573] should not calling udhcpc manually?
[04-13_03:35:39:573] should modify /etc/config/network as below?
[04-13_03:35:39:573] config interface wan
[04-13_03:35:39:573] option ifname usb0.2
[04-13_03:35:39:573] option proto dhcp
[04-13_03:35:39:573] should use "/sbin/ifstaus wan" to check usb0.2 's status?
[04-13_03:35:39:574] busybox udhcpc -f -n -q -t 5 -i usb0.2
[04-13_03:35:39:585] udhcpc (v1.23.2) started
[04-13_03:35:39:597] Sending discover...
[04-13_03:35:39:601] Sending select for 10.197.125.183...
[04-13_03:35:39:606] Lease of 10.197.125.183 obtained, lease time 7200
[04-13_03:35:39:611] udhcpc: ifconfig usb0.2 10.197.125.183 netmask 255.255.255.240 broadcast +
[04-13_03:35:39:621] udhcpc: setting default routers: 10.197.125.184
root@ZhuoTK:/# ifconfig usb0.1
usb0.1 Link encap:Ethernet HWaddr 02:50:F4:00:00:00
inet addr:10.187.142.20 Mask:255.255.255.248
inet6 addr: fe80::50:f4ff:fe00:0/64 Scope:Link
UP RUNNING NOARP MTU:1500 Metric:1
RX packets:4 errors:0 dropped:0 overruns:0 frame:0
TX packets:10 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:764 (764.0 B) TX bytes:1824 (1.7 KiB)
root@ZhuoTK:/# ifconfig usb0.2
usb0.2 Link encap:Ethernet HWaddr 02:50:F4:00:00:00
inet addr:10.197.125.183 Mask:255.255.255.240
inet6 addr: fe80::50:f4ff:fe00:0/64 Scope:Link
UP RUNNING NOARP MTU:1500 Metric:1
RX packets:3 errors:0 dropped:0 overruns:0 frame:0
TX packets:9 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:688 (688.0 B) TX bytes:1224 (1.1 KiB)
root@ZhuoTK:/# ip ro add 8.8.8.8/32 dev usb0.1
root@ZhuoTK:/# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=52 time=74.450 ms
root@ZhuoTK:/# ip ro del 8.8.8.8/32
root@ZhuoTK:/# ip ro del 8.8.8.8/32
RTNETLINK answers: No such process
root@ZhuoTK:/# ip ro add 8.8.8.8/32 dev usb0.2
root@ZhuoTK:/# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=52 time=257.851 ms
root@ZhuoTK:/# quectel-CM -k 2
[04-13_03:39:16:986] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_03:39:16:988] /proc/2294/cmdline: quectel-CM -n 2 -s 4gnet
[04-13_03:39:16:988] send SIGINT to process 2294
[04-13_03:39:16:989] requestDeactivateDefaultPDP WdsConnectionIPv4Handle
[ 1262.310000] net usb0: link_state 0x3 -> 0x1
[04-13_03:39:17:216] ifconfig usb0.2 0.0.0.0
[04-13_03:39:17:228] ifconfig usb0.2 down
[04-13_03:39:17:370] GobiNetThread exit
[04-13_03:39:17:371] qmi_main exit
[2]+ Done quectel-CM -n 2 -s 4gnet
root@ZhuoTK:/# ifconfig usb0.2
usb0.2 Link encap:Ethernet HWaddr 02:50:F4:00:00:00
NOARP MTU:1500 Metric:1
RX packets:30 errors:0 dropped:0 overruns:0 frame:0
TX packets:35 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:2816 (2.7 KiB) TX bytes:3408 (3.3 KiB)

View File

@ -1,114 +0,0 @@
root@ZhuoTK:/# insmod GobiNet.ko qmap_mode=4
[ 42.120000] GobiNet: Quectel_Linux&Android_GobiNet_Driver_V1.6.2.13
[ 42.130000] GobiNet 1-1.3:1.4 usb0: register 'GobiNet' at usb-101c0000.ehci-1.3, GobiNet Ethernet Device, 02:50:f4:00:00:00
[ 42.140000] creating qcqmi0
[ 42.150000] GobiNet::qmap_register_device usb0.1
[ 42.150000] GobiNet::qmap_register_device usb0.2
[ 42.160000] GobiNet::qmap_register_device usb0.3
[ 42.160000] GobiNet::qmap_register_device usb0.4
[ 42.170000] usbcore: registered new interface driver GobiNet
[ 43.270000] GobiNet::QMIWDASetDataFormat qmap settings qmap_version=5, rx_size=4096, tx_size=4096
[ 43.280000] GobiNet::QMIWDASetDataFormat qmap settings ul_data_aggregation_max_size=4096, ul_data_aggregation_max_datagrams=16
root@ZhuoTK:/# brctl addbr br0
root@ZhuoTK:/# brctl addif br0 eth0.1
root@ZhuoTK:/# brctl addif br0 usb0.1
root@ZhuoTK:/# brctl show
bridge name bridge id STP enabled interfaces
br0 8000.00ca019197b9 no eth0.1
usb0.1
root@ZhuoTK:/# quectel-CM -n 1 -s cmnet -b &
[04-13_05:12:42:155] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_05:12:42:158] Find /sys/bus/usb/devices/1-1.3 idVendor=0x2c7c idProduct=0x125, bus=0x001, dev=0x003
[ 86.130000] net usb0.1: bridge_mode change to 0x1
[04-13_05:12:42:159] Auto find qmichannel = /dev/qcqmi0
[04-13_05:12:42:160] Auto find usbnet_adapter = usb0
[04-13_05:12:42:160] netcard driver = GobiNet, driver version = V1.6.2.13
[04-13_05:12:42:160] qmap_mode = 4, qmap_version = 5, qmap_size = 4096, muxid = 0x81, qmap_netcard = usb0.1
[04-13_05:12:42:166] Modem works in QMI mode
[04-13_05:12:42:181] Get clientWDS = 7
[04-13_05:12:42:213] Get clientDMS = 8
[04-13_05:12:42:246] Get clientNAS = 9
[04-13_05:12:42:278] Get clientUIM = 10
[04-13_05:12:42:310] requestBaseBandVersion EC25EFAR06A11M4G
[04-13_05:12:42:438] requestGetSIMStatus SIMStatus: SIM_READY
[04-13_05:12:42:439] requestSetProfile[1] cmnet///0
[04-13_05:12:42:502] requestGetProfile[1] cmnet///0
[04-13_05:12:42:534] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: LTE
[04-13_05:12:42:565] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED
[04-13_05:12:42:566] ifconfig usb0 down
[04-13_05:12:42:576] ifconfig usb0.1 0.0.0.0
[04-13_05:12:42:587] ifconfig usb0.1 down
[04-13_05:12:42:629] requestSetupDataCall WdsConnectionIPv4Handle: 0x8724d740
[ 86.730000] net usb0: link_state 0x0 -> 0x1
[04-13_05:12:42:762] ifconfig usb0 up
[04-13_05:12:42:782] ifconfig usb0.1 up
[04-13_05:12:42:794] echo '0xa16b769' > /sys/class/net/usb0.1/bridge_ipv4
root@ZhuoTK:/# ifconfig br0 up
[ 98.270000] usb0.1 PC Mac Address: 00:0e:c6:a6:6c:f1
[ 98.360000] usb0.1 sip = 0.0.0.0, tip=10.22.183.105, ipv4=10.22.183.105
[ 98.370000] usb0.1 sip = 10.22.183.105, tip=10.22.183.106, ipv4=10.22.183.105
[ 99.360000] usb0.1 sip = 0.0.0.0, tip=10.22.183.105, ipv4=10.22.183.105
[ 100.360000] usb0.1 sip = 0.0.0.0, tip=10.22.183.105, ipv4=10.22.183.105
[ 100.500000] usb0.1 sip = 10.22.183.105, tip=10.22.183.106, ipv4=10.22.183.105
root@ZhuoTK:/# quectel-CM -n 2 -s 4gnet &
[04-13_05:13:05:715] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_05:13:05:717] Find /sys/bus/usb/devices/1-1.3 idVendor=0x2c7c idProduct=0x125, bus=0x001, dev=0x003
[04-13_05:13:05:719] Auto find qmichannel = /dev/qcqmi0
[04-13_05:13:05:719] Auto find usbnet_adapter = usb0
[04-13_05:13:05:719] netcard driver = GobiNet, driver version = V1.6.2.13
[04-13_05:13:05:719] qmap_mode = 4, qmap_version = 5, qmap_size = 4096, muxid = 0x82, qmap_netcard = usb0.2
[04-13_05:13:05:720] Modem works in QMI mode
[04-13_05:13:05:734] Get clientWDS = 7
[04-13_05:13:05:766] Get clientDMS = 8
[04-13_05:13:05:798] Get clientNAS = 9
[04-13_05:13:05:830] Get clientUIM = 10
[04-13_05:13:05:861] requestBaseBandVersion EC25EFAR06A11M4G
[04-13_05:13:05:990] requestGetSIMStatus SIMStatus: SIM_READY
[04-13_05:13:05:991] requestSetProfile[2] 4gnet///0
[04-13_05:13:06:054] requestGetProfile[2] 4gnet///0
[04-13_05:13:06:086] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: LTE
[04-13_05:13:06:118] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED
[04-13_05:13:06:119] ifconfig usb0.2 0.0.0.0
[04-13_05:13:06:131] ifconfig usb0.2 down
[04-13_05:13:06:375] requestSetupDataCall WdsConnectionIPv4Handle: 0x872b8c50
[ 110.470000] net usb0: link_state 0x1 -> 0x3
[04-13_05:13:06:507] ifconfig usb0 up
[04-13_05:13:06:518] ifconfig usb0.2 up
[04-13_05:13:06:539] you are use OpenWrt?
[04-13_05:13:06:540] should not calling udhcpc manually?
[04-13_05:13:06:540] should modify /etc/config/network as below?
[04-13_05:13:06:540] config interface wan
[04-13_05:13:06:540] option ifname usb0.2
[04-13_05:13:06:540] option proto dhcp
[04-13_05:13:06:540] should use "/sbin/ifstaus wan" to check usb0.2 's status?
[04-13_05:13:06:540] busybox udhcpc -f -n -q -t 5 -i usb0.2
[04-13_05:13:06:554] udhcpc (v1.23.2) started
[04-13_05:13:06:614] Sending discover...
[04-13_05:13:06:619] Sending select for 10.22.58.141...
[04-13_05:13:06:623] Lease of 10.22.58.141 obtained, lease time 7200
[04-13_05:13:06:629] udhcpc: ifconfig usb0.2 10.22.58.141 netmask 255.255.255.252 broadcast +
[04-13_05:13:06:638] udhcpc: setting default routers: 10.22.58.142
root@ZhuoTK:/# ifconfig usb0.2
usb0.2 Link encap:Ethernet HWaddr 02:50:F4:00:00:00
inet addr:10.22.58.141 Mask:255.255.255.252
inet6 addr: fe80::50:f4ff:fe00:0/64 Scope:Link
UP RUNNING NOARP MTU:1500 Metric:1
RX packets:2 errors:0 dropped:0 overruns:0 frame:0
TX packets:7 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:612 (612.0 B) TX bytes:1064 (1.0 KiB)
root@ZhuoTK:/# ip ro show
default via 10.22.58.142 dev usb0.2
10.22.58.140/30 dev usb0.2 proto kernel scope link src 10.22.58.141
192.168.1.0/24 dev br-lan proto kernel scope link src 192.168.1.251
root@ZhuoTK:/# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=52 time=69.822 ms

View File

@ -1,80 +0,0 @@
root@OpenWrt:/# lspci
00:00.0 Class 0604: 17cb:1001
01:00.0 Class ff00: 17cb:0306
root@OpenWrt:/# insmod pcie_mhi.ko mhi_mbim_enabled=1
[ 63.094154] mhi_init Quectel_Linux_PCIE_MHI_Driver_V1.3.0.17
[ 63.094739] mhi_pci_probe pci_dev->name = 0000:01:00.0, domain=0, bus=1, slot=0, vendor=17CB, device=0306
[ 63.099373] mhi_q 0000:01:00.0: BAR 0: assigned [mem 0x48000000-0x48000fff 64bit]
[ 63.108476] mhi_q 0000:01:00.0: enabling device (0140 -> 0142)
[ 63.293451] [I][mhi_netdev_enable_iface] Prepare the channels for transfer
[ 63.324757] [I][mhi_netdev_enable_iface] Exited.
[ 63.326265] rmnet_vnd_register_device(rmnet_mhi0.1)=0
root@OpenWrt:/# quectel-CM -s cment &
[04-13_09:25:23:910] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_09:25:23:912] network interface '' or qmidev '' is not exist
[04-13_09:25:23:912] netcard driver = pcie_mhi, driver version = V1.3.0.17
[04-13_09:25:23:913] mbim_qmap_mode = 1, vlan_id = 0x00, qmap_netcard = rmnet_mhi0.1
[04-13_09:25:23:913] Modem works in MBIM mode
[04-13_09:25:23:965] cdc_wdm_fd = 7
[04-13_09:25:23:965] mbim_open_device()
[04-13_09:25:24:549] mbim_device_caps_query()
[04-13_09:25:24:575] DeviceId: 869710030002905
[04-13_09:25:24:575] FirmwareInfo: RM500QGLABR10A03M4G_01.001.03
[04-13_09:25:24:575] HardwareInfo: RM500QGL_VH
[04-13_09:25:24:576] mbim_device_services_query()
[04-13_09:25:24:585] mbim_set_radio_state( 1 )
[04-13_09:25:24:588] HwRadioState: 1, SwRadioState: 1
[04-13_09:25:24:588] mbim_subscriber_status_query()
[04-13_09:25:24:612] SubscriberId: 460028563800461
[04-13_09:25:24:612] SimIccId: 89860015120716380461
[04-13_09:25:24:613] SubscriberReadyState NotInitialized -> Initialized
[04-13_09:25:24:613] mbim_register_state_query()
[04-13_09:25:24:617] RegisterState Unknown -> Home
[04-13_09:25:24:617] mbim_packet_service_query()
[04-13_09:25:24:619] PacketServiceState Unknown -> Attached
[04-13_09:25:24:619] CurrentDataClass = 5G_NSA
[04-13_09:25:24:620] mbim_query_connect(sessionID=0)
[04-13_09:25:24:631] ActivationState Unknown -> Deactivated
[04-13_09:25:24:631] ifconfig rmnet_mhi0 down
[04-13_09:25:24:657] ifconfig rmnet_mhi0.1 0.0.0.0
ifconfig: SIOCSIFFLAGS: Network is down
[04-13_09:25:24:681] ifconfig rmnet_mhi0.1 down
[04-13_09:25:24:705] mbim_register_state_query()
[04-13_09:25:24:709] mbim_packet_service_query()
[04-13_09:25:24:713] CurrentDataClass = 5G_NSA
[04-13_09:25:24:713] mbim_set_connect(onoff=1, sessionID=0)
[04-13_09:25:25:096] ActivationState Deactivated -> Activated
[04-13_09:25:25:097] mbim_ip_config(sessionID=0)
[04-13_09:25:25:100] < SessionId = 0
[04-13_09:25:25:100] < IPv4ConfigurationAvailable = 0xf
[04-13_09:25:25:100] < IPv6ConfigurationAvailable = 0x0
[04-13_09:25:25:101] < IPv4AddressCount = 0x1
[04-13_09:25:25:101] < IPv4AddressOffset = 0x3c
[04-13_09:25:25:101] < IPv6AddressCount = 0x0
[04-13_09:25:25:102] < IPv6AddressOffset = 0x0
[04-13_09:25:25:102] < IPv4 = 10.190.166.229/30
[04-13_09:25:25:103] < gw = 10.190.166.230
[04-13_09:25:25:103] < dns1 = 211.138.180.2
[04-13_09:25:25:103] < dns2 = 211.138.180.3
[04-13_09:25:25:104] < ipv4 mtu = 1500
[04-13_09:25:25:112] ifconfig rmnet_mhi0 up
[04-13_09:25:25:141] ifconfig rmnet_mhi0.1 up
[04-13_09:25:25:170] ip -4 address flush dev rmnet_mhi0.1
[04-13_09:25:25:190] ip -4 address add 10.190.166.229/30 dev rmnet_mhi0.1
[04-13_09:25:25:213] ip -4 route add default via 10.190.166.230 dev rmnet_mhi0.1
root@OpenWrt:/# ifconfig rmnet_mhi0.1
rmnet_mhi0.1 Link encap:Ethernet HWaddr 02:50:F4:00:00:00
inet addr:10.190.166.229 Mask:255.255.255.252
inet6 addr: fe80::50:f4ff:fe00:0/64 Scope:Link
UP RUNNING NOARP MTU:1500 Metric:1
RX packets:19 errors:0 dropped:0 overruns:0 frame:0
TX packets:29 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:2326 (2.2 KiB) TX bytes:2991 (2.9 KiB)
root@OpenWrt:/# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=52 time=278.561 ms

View File

@ -1,170 +0,0 @@
root@OpenWrt:/# lspci
00:00.0 Class 0604: 17cb:1001
01:00.0 Class ff00: 17cb:0304
root@OpenWrt:/# insmod pcie_mhi.ko mhi_mbim_enabled=1 qmap_mode=4
[ 76.596827] mhi_init Quectel_Linux_PCIE_MHI_Driver_V1.3.0.17
[ 76.598596] mhi_pci_probe pci_dev->name = 0000:01:00.0, domain=0, bus=1, slot=0, vendor=17CB, device=0304
[ 76.602863] mhi_q 0000:01:00.0: BAR 0: assigned [mem 0x48000000-0x48000fff 64bit]
[ 76.611323] mhi_q 0000:01:00.0: enabling device (0140 -> 0142)
[ 76.760239] [I][mhi_netdev_enable_iface] Prepare the channels for transfer
[ 76.828699] [I][mhi_netdev_enable_iface] Exited.
[ 76.832727] rmnet_vnd_register_device(rmnet_mhi0.1)=0
[ 76.836596] rmnet_vnd_register_device(rmnet_mhi0.2)=0
[ 76.841170] rmnet_vnd_register_device(rmnet_mhi0.3)=0
[ 76.846373] rmnet_vnd_register_device(rmnet_mhi0.4)=0
root@OpenWrt:~# quectel-mbim-proxy -d /dev/mhi_MBIM &
root@OpenWrt:~# [04-14_03:05:36:296] mbim_dev_fd=3
[04-14_03:05:36:297] mbim_send_open_msg()
[04-14_03:05:36:669] receive MBIM_OPEN_DONE, status=0
[04-14_03:05:36:670] mbim_server_fd=4
root@OpenWrt:~# quectel-CM -n 1 -s cmnet &
[04-14_03:05:45:955] Quectel_QConnectManager_Linux_V1.6.0.25
[04-14_03:05:45:956] network interface '' or qmidev '' is not exist
[04-14_03:05:45:957] netcard driver = pcie_mhi, driver version = V1.3.0.17
[04-14_03:05:45:957] mbim_qmap_mode = 4, vlan_id = 0x01, qmap_netcard = rmnet_mhi0.1
[04-14_03:05:45:958] Modem works in MBIM mode
[04-14_03:05:45:959] connect to quectel-mbim-proxy sockfd = 7
[04-14_03:05:45:959] handle_client_connect client_fd=5, client_idx=1
[04-14_03:05:45:959] cdc_wdm_fd = 7
[04-14_03:05:45:960] mbim_open_device()
[04-14_03:05:45:961] mbim_device_caps_query()
[04-14_03:05:45:967] DeviceId: 860459050041596
[04-14_03:05:45:968] FirmwareInfo: EM120RGLAPR02A03M4G_01.001.07
[04-14_03:05:45:968] HardwareInfo: EM120R_GL
[04-14_03:05:45:968] mbim_device_services_query()
[04-14_03:05:45:972] mbim_set_radio_state( 1 )
[04-14_03:05:45:976] HwRadioState: 1, SwRadioState: 1
[04-14_03:05:45:976] mbim_subscriber_status_query()
[04-14_03:05:45:985] SubscriberId: 460028563800461
[04-14_03:05:45:985] SimIccId: 89860015120716380461
[04-14_03:05:45:986] SubscriberReadyState NotInitialized -> Initialized
[04-14_03:05:45:986] mbim_register_state_query()
[04-14_03:05:45:991] RegisterState Unknown -> Home
[04-14_03:05:45:991] mbim_packet_service_query()
[04-14_03:05:45:995] PacketServiceState Unknown -> Attached
[04-14_03:05:45:996] mbim_query_connect(sessionID=1)
[04-14_03:05:46:000] ActivationState Unknown -> Deactivated
[04-14_03:05:46:000] ifconfig rmnet_mhi0 down
[04-14_03:05:46:024] ifconfig rmnet_mhi0.1 0.0.0.0
ifconfig: SIOCSIFFLAGS: Network is down
[04-14_03:05:46:049] ifconfig rmnet_mhi0.1 down
[04-14_03:05:46:072] mbim_set_connect(onoff=1, sessionID=1)
[04-14_03:05:46:099] ActivationState Deactivated -> Activated
[04-14_03:05:46:099] mbim_ip_config(sessionID=1)
[ 222.484298] net rmnet_mhi0: link_state 0x0 -> 0x1
[04-14_03:05:46:103] < SessionId = 1
[04-14_03:05:46:104] < IPv4ConfigurationAvailable = 0xf
[04-14_03:05:46:104] < IPv6ConfigurationAvailable = 0x0
[04-14_03:05:46:104] < IPv4AddressCount = 0x1
[04-14_03:05:46:105] < IPv4AddressOffset = 0x3c
[ 222.507775] [I][mhi_netdev_open] Opened net dev interface
[04-14_03:05:46:105] < IPv6AddressCount = 0x0
[04-14_03:05:46:105] < IPv6AddressOffset = 0x0
[04-14_03:05:46:106] < IPv4 = 10.38.21.158/30
[04-14_03:05:46:106] < gw = 10.38.21.157
[04-14_03:05:46:106] < dns1 = 211.138.180.2
[04-14_03:05:46:107] < dns2 = 211.138.180.3
[04-14_03:05:46:107] < ipv4 mtu = 1500
[04-14_03:05:46:112] ifconfig rmnet_mhi0 up
[04-14_03:05:46:140] ifconfig rmnet_mhi0.1 up
[04-14_03:05:46:168] ip -4 address flush dev rmnet_mhi0.1
[04-14_03:05:46:190] ip -4 address add 10.38.21.158/30 dev rmnet_mhi0.1
[04-14_03:05:46:212] ip -4 route add default via 10.38.21.157 dev rmnet_mhi0.1
[04-14_03:05:50:730] handle_client_connect client_fd=6, client_idx=2
[ 227.558631] net rmnet_mhi0: link_state 0x1 -> 0x3
root@OpenWrt:~# quectel-CM -n 2 -s 4gnet
[04-14_03:05:50:725] Quectel_QConnectManager_Linux_V1.6.0.25
[04-14_03:05:50:726] network interface '' or qmidev '' is not exist
[04-14_03:05:50:727] netcard driver = pcie_mhi, driver version = V1.3.0.17
[04-14_03:05:50:728] mbim_qmap_mode = 4, vlan_id = 0x02, qmap_netcard = rmnet_mhi0.2
[04-14_03:05:50:729] Modem works in MBIM mode
[04-14_03:05:50:730] connect to quectel-mbim-proxy sockfd = 8
[04-14_03:05:50:730] cdc_wdm_fd = 8
[04-14_03:05:50:731] mbim_open_device()
[04-14_03:05:50:732] mbim_device_caps_query()
[04-14_03:05:50:738] DeviceId: 860459050041596
[04-14_03:05:50:739] FirmwareInfo: EM120RGLAPR02A03M4G_01.001.07
[04-14_03:05:50:739] HardwareInfo: EM120R_GL
[04-14_03:05:50:740] mbim_device_services_query()
[04-14_03:05:50:744] mbim_set_radio_state( 1 )
[04-14_03:05:50:747] HwRadioState: 1, SwRadioState: 1
[04-14_03:05:50:747] mbim_subscriber_status_query()
[04-14_03:05:50:757] SubscriberId: 460028563800461
[04-14_03:05:50:758] SimIccId: 89860015120716380461
[04-14_03:05:50:758] SubscriberReadyState NotInitialized -> Initialized
[04-14_03:05:50:759] mbim_register_state_query()
[04-14_03:05:50:763] RegisterState Unknown -> Home
[04-14_03:05:50:764] mbim_packet_service_query()
[04-14_03:05:50:768] PacketServiceState Unknown -> Attached
[04-14_03:05:50:769] mbim_query_connect(sessionID=2)
[04-14_03:05:50:772] ActivationState Unknown -> Deactivated
[04-14_03:05:50:773] ifconfig rmnet_mhi0.2 0.0.0.0
[04-14_03:05:50:799] ifconfig rmnet_mhi0.2 down
[04-14_03:05:50:834] mbim_set_connect(onoff=1, sessionID=2)
[04-14_03:05:51:170] ActivationState Deactivated -> Activated
[04-14_03:05:51:171] mbim_ip_config(sessionID=2)
[04-14_03:05:51:174] < SessionId = 2
[04-14_03:05:51:174] < IPv4ConfigurationAvailable = 0xf
[04-14_03:05:51:175] < IPv6ConfigurationAvailable = 0x0
[04-14_03:05:51:175] < IPv4AddressCount = 0x1
[04-14_03:05:51:175] < IPv4AddressOffset = 0x3c
[04-14_03:05:51:176] < IPv6AddressCount = 0x0
[04-14_03:05:51:176] < IPv6AddressOffset = 0x0
[04-14_03:05:51:176] < IPv4 = 10.36.109.217/30
[04-14_03:05:51:177] < gw = 10.36.109.218
[04-14_03:05:51:177] < dns1 = 211.138.180.2
[04-14_03:05:51:178] < dns2 = 211.138.180.3
[04-14_03:05:51:178] < ipv4 mtu = 1500
[04-14_03:05:51:182] ifconfig rmnet_mhi0 up
[04-14_03:05:51:206] ifconfig rmnet_mhi0.2 up
[04-14_03:05:51:233] ip -4 address flush dev rmnet_mhi0.2
[04-14_03:05:51:254] ip -4 address add 10.36.109.217/30 dev rmnet_mhi0.2
[04-14_03:05:51:277] ip -4 route add default via 10.36.109.218 dev rmnet_mhi0.2
root@OpenWrt:~# ifconfig rmnet_mhi0.1
rmnet_mhi0.1 Link encap:Ethernet HWaddr 02:50:F4:00:00:00
inet addr:10.38.21.158 Mask:255.255.255.252
inet6 addr: fe80::50:f4ff:fe00:0/64 Scope:Link
UP RUNNING NOARP MTU:1500 Metric:1
RX packets:37 errors:0 dropped:0 overruns:0 frame:0
TX packets:29 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:9907 (9.6 KiB) TX bytes:2764 (2.6 KiB)
root@OpenWrt:~# ifconfig rmnet_mhi0.2
rmnet_mhi0.2 Link encap:Ethernet HWaddr 02:50:F4:00:00:00
inet addr:10.36.109.217 Mask:255.255.255.252
inet6 addr: fe80::50:f4ff:fe00:0/64 Scope:Link
UP RUNNING NOARP MTU:1500 Metric:1
RX packets:5 errors:0 dropped:0 overruns:0 frame:0
TX packets:18 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:344 (344.0 B) TX bytes:1152 (1.1 KiB)
root@OpenWrt:~# ip ro del 8.8.8.8/32
RTNETLINK answers: No such process
root@OpenWrt:~# ip ro add 8.8.8.8/32 dev rmnet_mhi0.1
root@OpenWrt:~# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=52 time=73.248 ms
root@OpenWrt:~# ip ro del 8.8.8.8/32
root@OpenWrt:~# ip ro del 8.8.8.8/32
RTNETLINK answers: No such process
root@OpenWrt:~# ip ro add 8.8.8.8/32 dev rmnet_mhi0.2
root@OpenWrt:~# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=52 time=99.637 ms
root@OpenWrt:~# quectel-CM -k 2
[04-14_03:06:58:912] Quectel_QConnectManager_Linux_V1.6.0.25
[04-14_03:06:59:063] /proc/3565/cmdline: quectel-CM -n 2 -s 4gnet
[04-14_03:06:59:064] send SIGINT to process 3565
[ 295.719442] net rmnet_mhi0: link_state 0x3 -> 0x1
[04-14_03:06:59:407] proxy_loop poll fd = 6, revents = 0011
[04-14_03:06:59:408] handle_client_disconnect client_fd=6, client_idx=2

View File

@ -1,127 +0,0 @@
root@OpenWrt:/# cat /sys/class/net/rmnet_mhi0/qmap_mode
1
root@OpenWrt:/# cat /sys/module/pcie_mhi/parameters/mhi_mbim_enabled
0
root@OpenWrt:/# dmesg | grep mhi
[ 18.442226] mhi_init Quectel_Linux_PCIE_MHI_Driver_V1.3.0.17
[ 18.443032] mhi_pci_probe pci_dev->name = 0000:01:00.0, domain=0, bus=1, slot=0, vendor=17CB, device=0306
[ 18.447488] mhi_q 0000:01:00.0: BAR 0: assigned [mem 0x48000000-0x48000fff 64bit]
[ 18.456563] mhi_q 0000:01:00.0: enabling device (0140 -> 0142)
[ 18.464184] [I][mhi_init_pci_dev] msi_required = 5, msi_allocated = 5, msi_irq = 197
[ 18.464215] [I][mhi_power_up] dev_state:RESET
[ 18.464225] [I][mhi_async_power_up] Requested to power on
[ 18.464432] [I][mhi_alloc_coherent] size = 114688, dma_handle = 8d400000
[ 18.464445] [I][mhi_init_dev_ctxt] mhi_ctxt->ctrl_seg = d1766000
[ 18.466003] [I][mhi_async_power_up] dev_state:RESET ee:AMSS
[ 18.466080] [I][mhi_pm_st_worker] Transition to state:READY
[ 18.466109] [I][mhi_pm_st_worker] INVALID_EE -> AMSS
[ 18.466135] [I][mhi_ready_state_transition] Waiting to enter READY state
[ 18.466224] [I][mhi_async_power_up] Power on setup success
[ 18.466265] [I][mhi_pci_probe] Return successful
[ 18.577299] [I][mhi_intvec_threaded_handlr] device ee:AMSS dev_state:READY, pm_state:POR
[ 18.577312] [I][mhi_ready_state_transition] Device in READY State
[ 18.577325] [I][mhi_intvec_threaded_handlr] device ee:AMSS dev_state:READY, INVALID_EE
[ 18.577329] [I][mhi_tryset_pm_state] Transition to pm state from:POR to:POR
[ 18.577337] [I][mhi_init_mmio] Initializing MMIO
[ 18.577344] [I][mhi_init_mmio] CHDBOFF:0x300
[ 18.577361] [I][mhi_init_mmio] ERDBOFF:0x700
[ 18.577372] [I][mhi_init_mmio] Programming all MMIO values.
[ 18.690834] [I][mhi_dump_tre] carl_ev evt_state_change mhistate=2
[ 18.690854] [I][mhi_process_ctrl_ev_ring] MHI state change event to state:M0
[ 18.690866] [I][mhi_pm_m0_transition] Entered With State:READY PM_STATE:POR
[ 18.690879] [I][mhi_tryset_pm_state] Transition to pm state from:POR to:M0
[ 18.694229] [I][mhi_dump_tre] carl_ev evt_ee_state execenv=2
[ 18.694241] [I][mhi_process_ctrl_ev_ring] MHI EE received event:AMSS
[ 18.694293] [I][mhi_pm_st_worker] Transition to state:MISSION MODE
[ 18.694310] [I][mhi_pm_st_worker] INVALID_EE -> AMSS
[ 18.694319] [I][mhi_pm_mission_mode_transition] Processing Mission Mode Transition
[ 18.694341] [I][mhi_init_timesync] No timesync capability found
[ 18.694350] [I][mhi_pm_mission_mode_transition] Adding new devices
[ 18.696365] [I][mhi_dtr_probe] Enter for DTR control channel
[ 18.696383] [I][__mhi_prepare_channel] Entered: preparing channel:18
[ 18.703113] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1, type=33
[ 18.703164] [I][__mhi_prepare_channel] Chan:18 successfully moved to start state
[ 18.703174] [I][__mhi_prepare_channel] Entered: preparing channel:19
[ 18.710681] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1, type=33
[ 18.710734] [I][__mhi_prepare_channel] Chan:19 successfully moved to start state
[ 18.710804] [I][mhi_dtr_probe] Exit with ret:0
[ 18.711774] [I][mhi_netdev_enable_iface] Prepare the channels for transfer
[ 18.711811] [I][__mhi_prepare_channel] Entered: preparing channel:100
[ 18.732097] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1, type=33
[ 18.732151] [I][__mhi_prepare_channel] Chan:100 successfully moved to start state
[ 18.732162] [I][__mhi_prepare_channel] Entered: preparing channel:101
[ 18.744170] [I][mhi_dump_tre] carl_ev evt_cmd_comp code=1, type=33
[ 18.744219] [I][__mhi_prepare_channel] Chan:101 successfully moved to start state
[ 18.749132] [I][mhi_netdev_enable_iface] Exited.
[ 18.750306] rmnet_vnd_register_device(rmnet_mhi0.1)=0
[ 18.752927] [I][mhi_pm_mission_mode_transition] Exit with ret:0
root@OpenWrt:/# busybox microcom /dev/mhi_DUN
at+cpin?
+CPIN: READY
OK
at+cops?
+COPS: 0,0,"CHINA MOBILE",13
OK
at+csq
+csq: 23,99
OK
root@OpenWrt:/# quectel-CM -s cmnet &
[04-13_09:26:58:077] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_09:26:58:078] network interface '' or qmidev '' is not exist
[04-13_09:26:58:079] netcard driver = pcie_mhi, driver version = V1.3.0.17
[04-13_09:26:58:080] qmap_mode = 1, qmap_version = 9, qmap_size = 16384, muxid = 0x81, qmap_netcard = rmnet_mhi0.1
[04-13_09:26:58:080] Modem works in QMI mode
[04-13_09:26:58:131] cdc_wdm_fd = 7
[04-13_09:26:59:132] QmiWwanInit message timeout
[04-13_09:27:00:140] Get clientWDS = 15
[04-13_09:27:00:144] Get clientDMS = 1
[04-13_09:27:00:147] Get clientNAS = 4
[04-13_09:27:00:151] Get clientUIM = 1
[04-13_09:27:00:155] Get clientWDA = 1
[04-13_09:27:00:158] requestBaseBandVersion RM500QGLABR10A03M4G
[04-13_09:27:00:161] qmap_settings.rx_urb_size = 16384
[04-13_09:27:00:162] qmap_settings.ul_data_aggregation_max_datagrams = 11
[04-13_09:27:00:162] qmap_settings.ul_data_aggregation_max_size = 8192
[04-13_09:27:00:163] qmap_settings.dl_minimum_padding = 0
[04-13_09:27:00:176] requestGetSIMStatus SIMStatus: SIM_READY
[04-13_09:27:00:177] requestSetProfile[1] cmnet///0
[04-13_09:27:00:190] requestGetProfile[1] cmnet///0
[04-13_09:27:00:193] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: 5G_NSA
[04-13_09:27:00:197] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED
[04-13_09:27:00:198] ifconfig rmnet_mhi0 down
[04-13_09:27:00:222] ifconfig rmnet_mhi0.1 0.0.0.0
[04-13_09:27:00:247] ifconfig rmnet_mhi0.1 down
[04-13_09:27:00:281] requestSetupDataCall WdsConnectionIPv4Handle: 0x1228bb20
[ 245.284909] net rmnet_mhi0: link_state 0x0 -> 0x1
[04-13_09:27:00:293] ifconfig rmnet_mhi0 up
[ 245.308696] [I][mhi_netdev_open] Opened net dev interface
[04-13_09:27:00:318] ifconfig rmnet_mhi0.1 up
[04-13_09:27:00:353] you are use OpenWrt?
[04-13_09:27:00:354] should not calling udhcpc manually?
[04-13_09:27:00:354] should modify /etc/config/network as below?
[04-13_09:27:00:355] config interface wan
[04-13_09:27:00:355] option ifname rmnet_mhi0.1
[04-13_09:27:00:355] option proto dhcp
[04-13_09:27:00:356] should use "/sbin/ifstaus wan" to check rmnet_mhi0.1 's status?
[04-13_09:27:00:356] busybox udhcpc -f -n -q -t 5 -i rmnet_mhi0.1
udhcpc: started, v1.28.3
udhcpc: sending discover
udhcpc: sending select for 10.128.73.23
udhcpc: lease of 10.128.73.23 obtained, lease time 7200
[04-13_09:27:00:710] udhcpc: ifconfig rmnet_mhi0.1 10.128.73.23 netmask 255.255.255.240 broadcast +
[04-13_09:27:00:742] udhcpc: setting default routers: 10.128.73.24
root@OpenWrt:/# ifconfig rmnet_mhi0.1
rmnet_mhi0.1 Link encap:Ethernet HWaddr 02:50:F4:00:00:00
inet addr:10.128.73.23 Mask:255.255.255.240
inet6 addr: fe80::50:f4ff:fe00:0/64 Scope:Link
UP RUNNING NOARP MTU:1500 Metric:1
RX packets:2 errors:0 dropped:0 overruns:0 frame:0
TX packets:2 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:612 (612.0 B) TX bytes:684 (684.0 B)

View File

@ -1,76 +0,0 @@
root@OpenWrt:/# lspci
00:00.0 Class 0604: 17cb:1001
01:00.0 Class ff00: 17cb:0306
root@OpenWrt:~# insmod pcie_mhi.ko
[ 77.949271] mhi_init Quectel_Linux_PCIE_MHI_Driver_V1.3.0.17
[ 77.950949] mhi_pci_probe pci_dev->name = 0000:01:00.0, domain=0, bus=1, slot=0, vendor=17CB, device=0306
[ 77.955331] mhi_q 0000:01:00.0: BAR 0: assigned [mem 0x48000000-0x48000fff 64bit]
[ 77.963756] mhi_q 0000:01:00.0: enabling device (0140 -> 0142)
[ 78.048911] [I][mhi_netdev_enable_iface] Prepare the channels for transfer
[ 78.092304] [I][mhi_netdev_enable_iface] Exited.
[ 78.096580] rmnet_vnd_register_device(rmnet_mhi0.1)=0
root@OpenWrt:~# brctl addbr br0
root@OpenWrt:~# brctl addif br0 rmnet_mhi0.1
root@OpenWrt:~# brctl addif br0 eth1
[ 250.017213] device eth1 entered promiscuous mode
root@OpenWrt:~# brctl show
bridge name bridge id STP enabled interfaces
br0 8000.00001c353487 no eth1
rmnet_mhi0.1
root@OpenWrt:~# quectel-CM -s cmnet -b &
[04-14_06:43:28:473] Quectel_QConnectManager_Linux_V1.6.0.25
[04-14_06:43:28:474] network interface '' or qmidev '' is not exist
[04-14_06:43:28:475] netcard driver = pcie_mhi, driver version = V1.3.0.17
[04-14_06:43:28:476] qmap_mode = 1, qmap_version = 9, qmap_size = 16384, muxid = 0x81, qmap_netcard = rmnet_mhi0.1
[04-14_06:43:28:477] Modem works in QMI mode
[04-14_06:43:28:531] cdc_wdm_fd = 7
[04-14_06:43:29:532] QmiWwanInit message timeout
[04-14_06:43:30:540] Get clientWDS = 15
[04-14_06:43:30:543] Get clientDMS = 1
[04-14_06:43:30:546] Get clientNAS = 4
[04-14_06:43:30:550] Get clientUIM = 1
[04-14_06:43:30:553] Get clientWDA = 1
[04-14_06:43:30:557] requestBaseBandVersion RM500QGLABR10A03M4G
[04-14_06:43:30:560] qmap_settings.rx_urb_size = 16384
[04-14_06:43:30:561] qmap_settings.ul_data_aggregation_max_datagrams = 11
[04-14_06:43:30:561] qmap_settings.ul_data_aggregation_max_size = 8192
[04-14_06:43:30:561] qmap_settings.dl_minimum_padding = 0
[04-14_06:43:30:575] requestGetSIMStatus SIMStatus: SIM_READY
[04-14_06:43:30:575] requestSetProfile[1] cmnet///0
[04-14_06:43:30:588] requestGetProfile[1] cmnet///0
[04-14_06:43:30:591] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: 5G_NSA
[04-14_06:43:30:595] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED
[04-14_06:43:30:595] ifconfig rmnet_mhi0 down
[04-14_06:43:30:620] ifconfig rmnet_mhi0.1 0.0.0.0
ifconfig: SIOCSIFFLAGS: Network is down
[04-14_06:43:30:644] ifconfig rmnet_mhi0.1 down
[04-14_06:43:30:679] requestSetupDataCall WdsConnectionIPv4Handle: 0xb41f47d0
[ 263.869899] net rmnet_mhi0: link_state 0x0 -> 0x1
[04-14_06:43:30:693] ifconfig rmnet_mhi0 up
[ 263.892647] [I][mhi_netdev_open] Opened net dev interface
[04-14_06:43:30:718] ifconfig rmnet_mhi0.1 up
[04-14_06:43:30:746] echo '0xa59316b' > /sys/class/net/rmnet_mhi0.1/bridge_ipv4
root@OpenWrt:~# ifconfig br0 up
[ 268.800026] br0: port 2(eth1) entered forwarding state
[ 268.800336] br0: port 2(eth1) entered forwarding state
[ 268.804251] br0: port 1(rmnet_mhi0.1) entered forwarding state
[ 268.809465] br0: port 1(rmnet_mhi0.1) entered forwarding state
[ 283.845790] br0: port 2(eth1) entered forwarding state
[ 296.512489] rmnet_mhi0.1 PC Mac Address: 00:0e:c6:a6:6c:f1
[ 296.515756] rmnet_mhi0.1 PC Mac Address: 00:0e:c6:a6:6c:f1
[ 296.586584] rmnet_mhi0.1 sip = 10.89.49.107, tip=10.89.49.108, ipv4=10.89.49.107
[ 296.672356] rmnet_mhi0.1 sip = 10.89.49.107, tip=10.89.49.108, ipv4=10.89.49.107
[ 296.792061] rmnet_mhi0.1 sip = 10.89.49.107, tip=10.89.49.108, ipv4=10.89.49.107
[ 296.832822] rmnet_mhi0.1 sip = 10.89.49.107, tip=10.89.49.108, ipv4=10.89.49.107
[ 296.941073] rmnet_mhi0.1 sip = 0.0.0.0, tip=10.89.49.107, ipv4=10.89.49.107
[ 297.941310] rmnet_mhi0.1 sip = 0.0.0.0, tip=10.89.49.107, ipv4=10.89.49.107
[ 298.941528] rmnet_mhi0.1 sip = 0.0.0.0, tip=10.89.49.107, ipv4=10.89.49.107
[ 299.941704] rmnet_mhi0.1 sip = 10.89.49.107, tip=10.89.49.107, ipv4=10.89.49.107
[ 300.024484] rmnet_mhi0.1 sip = 10.89.49.107, tip=10.89.49.108, ipv4=10.89.49.107
[ 300.051995] rmnet_mhi0.1 sip = 10.89.49.107, tip=10.89.49.108, ipv4=10.89.49.107
[ 303.915933] rmnet_mhi0.1 sip = 10.89.49.107, tip=10.89.49.108, ipv4=10.89.49.107

View File

@ -1,138 +0,0 @@
root@OpenWrt:/# lspci
00:00.0 Class 0604: 17cb:1001
01:00.0 Class ff00: 17cb:0306
root@OpenWrt:/# insmod pcie_mhi.ko qmap_mode=4
[ 61.988878] mhi_init Quectel_Linux_PCIE_MHI_Driver_V1.3.0.17
[ 61.989484] mhi_pci_probe pci_dev->name = 0000:01:00.0, domain=0, bus=1, slot=0, vendor=17CB, device=0306
[ 61.994039] mhi_q 0000:01:00.0: BAR 0: assigned [mem 0x48000000-0x48000fff 64bit]
[ 62.003208] mhi_q 0000:01:00.0: enabling device (0140 -> 0142)
[ 62.191947] [I][mhi_netdev_enable_iface] Prepare the channels for transfer
[ 62.224065] [I][mhi_netdev_enable_iface] Exited.
[ 62.225619] rmnet_vnd_register_device(rmnet_mhi0.1)=0
[ 62.229289] rmnet_vnd_register_device(rmnet_mhi0.2)=0
[ 62.234378] rmnet_vnd_register_device(rmnet_mhi0.3)=0
[ 62.240039] rmnet_vnd_register_device(rmnet_mhi0.4)=0
root@OpenWrt:/# quectel-qmi-proxy -d /dev/mhi_QMI0 &
[04-13_09:25:12:278] Will use cdc-wdm='/dev/mhi_QMI0', proxy='quectel-qmi-proxy0'
[04-13_09:25:12:297] qmi_proxy_init enter
[04-13_09:25:12:297] qmi_proxy_loop enter thread_id 0xb6e88d44
[04-13_09:25:14:298] qmi_proxy_init succful
[04-13_09:25:14:299] local server: quectel-qmi-proxy0 sockfd = 4
[04-13_09:25:14:299] qmi_proxy_server_fd = 4
root@OpenWrt:/# quectel-CM -n 1 -s cmnet &
[04-13_09:25:32:336] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_09:25:32:337] network interface '' or qmidev '' is not exist
[04-13_09:25:32:338] netcard driver = pcie_mhi, driver version = V1.3.0.17
[04-13_09:25:32:339] qmap_mode = 4, qmap_version = 9, qmap_size = 16384, muxid = 0x81, qmap_netcard = rmnet_mhi0.1
[04-13_09:25:32:340] Modem works in QMI mode
[04-13_09:25:32:341] connect to quectel-qmi-proxy0 sockfd = 7
[04-13_09:25:32:342] cdc_wdm_fd = 7
[04-13_09:25:32:380] requestBaseBandVersion RM500QGLABR10A03M4G
[04-13_09:25:32:382] qmap_settings.rx_urb_size = 16384
[04-13_09:25:32:383] qmap_settings.ul_data_aggregation_max_datagrams = 11
[04-13_09:25:32:383] qmap_settings.ul_data_aggregation_max_size = 8192
[04-13_09:25:32:384] qmap_settings.dl_minimum_padding = 0
[04-13_09:25:32:394] requestGetSIMStatus SIMStatus: SIM_READY
[04-13_09:25:32:395] requestSetProfile[1] cmnet///0
[04-13_09:25:32:409] requestGetProfile[1] cmnet///0
[04-13_09:25:32:414] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: 5G_NSA
[04-13_09:25:32:418] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED
[04-13_09:25:32:419] ifconfig rmnet_mhi0 down
[04-13_09:25:32:448] ifconfig rmnet_mhi0.1 0.0.0.0
[04-13_09:25:32:473] ifconfig rmnet_mhi0.1 down
[04-13_09:25:32:514] requestSetupDataCall WdsConnectionIPv4Handle: 0x2313a2a0
[ 121.648172] net rmnet_mhi0: link_state 0x0 -> 0x1
[04-13_09:25:32:525] ifconfig rmnet_mhi0 up
[ 121.671210] [I][mhi_netdev_open] Opened net dev interface
[04-13_09:25:32:551] ifconfig rmnet_mhi0.1 up
[04-13_09:25:32:586] you are use OpenWrt?
[04-13_09:25:32:587] should not calling udhcpc manually?
[04-13_09:25:32:587] should modify /etc/config/network as below?
[04-13_09:25:32:587] config interface wan
[04-13_09:25:32:588] option ifname rmnet_mhi0.1
[04-13_09:25:32:588] option proto dhcp
[04-13_09:25:32:589] should use "/sbin/ifstaus wan" to check rmnet_mhi0.1 's status?
[04-13_09:25:32:589] busybox udhcpc -f -n -q -t 5 -i rmnet_mhi0.1
udhcpc: started, v1.28.3
udhcpc: sending discover
udhcpc: sending select for 10.174.91.70
udhcpc: lease of 10.174.91.70 obtained, lease time 7200
[04-13_09:25:32:980] udhcpc: ifconfig rmnet_mhi0.1 10.174.91.70 netmask 255.255.255.252 broadcast +
[04-13_09:25:33:007] udhcpc: setting default routers: 10.174.91.69
root@OpenWrt:/# quectel-CM -n 2 -s 4gnet &
[04-13_09:25:42:976] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_09:25:42:977] network interface '' or qmidev '' is not exist
[04-13_09:25:42:978] netcard driver = pcie_mhi, driver version = V1.3.0.17
[04-13_09:25:42:978] qmap_mode = 4, qmap_version = 9, qmap_size = 16384, muxid = 0x82, qmap_netcard = rmnet_mhi0.2
[04-13_09:25:42:979] Modem works in QMI mode
[04-13_09:25:42:981] connect to quectel-qmi-proxy0 sockfd = 7
[04-13_09:25:42:982] cdc_wdm_fd = 7
[04-13_09:25:43:010] requestBaseBandVersion RM500QGLABR10A03M4G
[04-13_09:25:43:013] qmap_settings.rx_urb_size = 16384
[04-13_09:25:43:014] qmap_settings.ul_data_aggregation_max_datagrams = 11
[04-13_09:25:43:014] qmap_settings.ul_data_aggregation_max_size = 8192
[04-13_09:25:43:015] qmap_settings.dl_minimum_padding = 0
[04-13_09:25:43:030] requestGetSIMStatus SIMStatus: SIM_READY
[04-13_09:25:43:030] requestSetProfile[2] 4gnet///0
[04-13_09:25:43:046] requestGetProfile[2] 4gnet///0
[04-13_09:25:43:050] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: 5G_NSA
[04-13_09:25:43:054] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED
[04-13_09:25:43:055] ifconfig rmnet_mhi0.2 0.0.0.0
[04-13_09:25:43:082] ifconfig rmnet_mhi0.2 down
[04-13_09:25:43:507] requestSetupDataCall WdsConnectionIPv4Handle: 0x2332a780
[ 132.641313] net rmnet_mhi0: link_state 0x1 -> 0x3
[04-13_09:25:43:519] ifconfig rmnet_mhi0 up
[04-13_09:25:43:543] ifconfig rmnet_mhi0.2 up
[04-13_09:25:43:570] you are use OpenWrt?
[04-13_09:25:43:570] should not calling udhcpc manually?
[04-13_09:25:43:571] should modify /etc/config/network as below?
[04-13_09:25:43:571] config interface wan
[04-13_09:25:43:571] option ifname rmnet_mhi0.2
[04-13_09:25:43:572] option proto dhcp
[04-13_09:25:43:572] should use "/sbin/ifstaus wan" to check rmnet_mhi0.2 's status?
[04-13_09:25:43:573] busybox udhcpc -f -n -q -t 5 -i rmnet_mhi0.2
udhcpc: started, v1.28.3
udhcpc: sending discover
udhcpc: sending select for 10.163.253.197
udhcpc: lease of 10.163.253.197 obtained, lease time 7200
[04-13_09:25:43:810] udhcpc: ifconfig rmnet_mhi0.2 10.163.253.197 netmask 255.255.255.252 broadcast +
[04-13_09:25:43:836] udhcpc: setting default routers: 10.163.253.198
root@OpenWrt:/# ifconfig rmnet_mhi0.1
rmnet_mhi0.1 Link encap:Ethernet HWaddr 02:50:F4:00:00:00
inet addr:10.174.91.70 Mask:255.255.255.252
inet6 addr: fe80::50:f4ff:fe00:0/64 Scope:Link
UP RUNNING NOARP MTU:1500 Metric:1
RX packets:2 errors:0 dropped:0 overruns:0 frame:0
TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:612 (612.0 B) TX bytes:1380 (1.3 KiB)
root@OpenWrt:/# ifconfig rmnet_mhi0.2
rmnet_mhi0.2 Link encap:Ethernet HWaddr 02:50:F4:00:00:00
inet addr:10.163.253.197 Mask:255.255.255.252
inet6 addr: fe80::50:f4ff:fe00:0/64 Scope:Link
UP RUNNING NOARP MTU:1500 Metric:1
RX packets:2 errors:0 dropped:0 overruns:0 frame:0
TX packets:2 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:612 (612.0 B) TX bytes:684 (684.0 B)
root@OpenWrt:/# ip ro del 8.8.8.8/32
RTNETLINK answers: No such process
root@OpenWrt:/# ip ro add 8.8.8.8/32 dev rmnet_mhi0.1
root@OpenWrt:/# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=52 time=390.869 ms
root@OpenWrt:/# ip ro del 8.8.8.8/32
root@OpenWrt:/# ip ro del 8.8.8.8/32
RTNETLINK answers: No such process
root@OpenWrt:/# ip ro add 8.8.8.8/32 dev rmnet_mhi0.2
root@OpenWrt:/# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=111 time=314.395 ms

View File

@ -1,147 +0,0 @@
root@OpenWrt:~# lspci
00:00.0 Class 0604: 17cb:1001
01:00.0 Class ff00: 17cb:0306
root@OpenWrt:~#
root@OpenWrt:~# insmod pcie_mhi.ko qmap_mode=4
[ 200.906104] mhi_init Quectel_Linux_PCIE_MHI_Driver_V1.3.0.17
[ 200.907913] mhi_pci_probe pci_dev->name = 0000:01:00.0, domain=0, bus=1, slot=0, vendor=17CB, device=0306
[ 200.912164] mhi_q 0000:01:00.0: BAR 0: assigned [mem 0x48000000-0x48000fff 64bit]
[ 200.920593] mhi_q 0000:01:00.0: enabling device (0140 -> 0142)
root@OpenWrt:~# [ 201.112214] [I][mhi_netdev_enable_iface] Prepare the channels for transfer
[ 201.154640] [I][mhi_netdev_enable_iface] Exited.
[ 201.159271] rmnet_vnd_register_device(rmnet_mhi0.1)=0
[ 201.162953] rmnet_vnd_register_device(rmnet_mhi0.2)=0
[ 201.167698] rmnet_vnd_register_device(rmnet_mhi0.3)=0
[ 201.172178] rmnet_vnd_register_device(rmnet_mhi0.4)=0
root@OpenWrt:~# brctl addbr br0
root@OpenWrt:~# brctl addif br0 eth1
root@OpenWrt:~# brctl addif br0 rmnet_mhi0.2
root@OpenWrt:~# brctl show
bridge name bridge id STP enabled interfaces
br0 8000.00001c353487 no eth1
rmnet_mhi0.2
root@OpenWrt:~# quectel-qmi-proxy -d /dev/mhi_QMI0 &
[04-14_06:44:01:556] Will use cdc-wdm='/dev/mhi_QMI0', proxy='quectel-qmi-proxy0'
[04-14_06:44:01:573] qmi_proxy_init enter
[04-14_06:44:01:573] qmi_proxy_loop enter thread_id 0xb6f20d44
[04-14_06:44:03:574] qmi_proxy_init succful
[04-14_06:44:03:574] local server: quectel-qmi-proxy0 sockfd = 4
[04-14_06:44:03:575] qmi_proxy_server_fd = 4
root@OpenWrt:~# quectel-CM -n 1 -s cmnet &
[04-14_06:47:53:303] Quectel_QConnectManager_Linux_V1.6.0.25
[04-14_06:47:53:314] network interface '' or qmidev '' is not exist
[04-14_06:47:53:315] netcard driver = pcie_mhi, driver version = V1.3.0.17
[04-14_06:47:53:316] qmap_mode = 4, qmap_version = 9, qmap_size = 16384, muxid = 0x81, qmap_netcard = rmnet_mhi0.1
[04-14_06:47:53:316] Modem works in QMI mode
[04-14_06:47:53:318] connect to quectel-qmi-proxy0 sockfd = 7
[04-14_06:47:53:318] cdc_wdm_fd = 7
[04-14_06:47:53:326] Get clientWDS = 15
[04-14_06:47:53:329] Get clientDMS = 2
[04-14_06:47:53:334] Get clientNAS = 4
[04-14_06:47:53:338] Get clientUIM = 1
[04-14_06:47:53:343] Get clientWDA = 1
[04-14_06:47:53:347] requestBaseBandVersion RM500QGLABR10A03M4G
[04-14_06:47:53:351] qmap_settings.rx_urb_size = 16384
[04-14_06:47:53:352] qmap_settings.ul_data_aggregation_max_datagrams = 11
[04-14_06:47:53:352] qmap_settings.ul_data_aggregation_max_size = 8192
[04-14_06:47:53:352] qmap_settings.dl_minimum_padding = 0
[04-14_06:47:53:369] requestGetSIMStatus SIMStatus: SIM_READY
[04-14_06:47:53:370] requestSetProfile[1] cmnet///0
[04-14_06:47:53:402] requestGetProfile[1] cmnet///0
[04-14_06:47:53:407] requestRegistrationState2 MCC: 0, MNC: 0, PS: Detached, DataCap: UNKNOW
[04-14_06:47:53:411] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED
[04-14_06:47:53:412] ifconfig rmnet_mhi0 down
[04-14_06:47:53:436] ifconfig rmnet_mhi0.1 0.0.0.0
[04-14_06:47:53:460] ifconfig rmnet_mhi0.1 down
[04-14_06:48:26:399] requestRegistrationState2 MCC: 460, MNC: 0, PS: Detached, DataCap: UNKNOW
[04-14_06:48:26:405] requestRegistrationState2 MCC: 460, MNC: 0, PS: Detached, DataCap: UNKNOW
[04-14_06:48:26:411] requestRegistrationState2 MCC: 460, MNC: 0, PS: Detached, DataCap: UNKNOW
[04-14_06:48:26:970] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: 5G_NSA
[04-14_06:48:26:992] requestSetupDataCall WdsConnectionIPv4Handle: 0x34176710
[04-14_06:48:27:005] ifconfig rmnet_mhi0 up
[04-14_06:48:27:031] ifconfig rmnet_mhi0.1 up
[04-14_06:48:27:057] you are use OpenWrt?
[04-14_06:48:27:057] should not calling udhcpc manually?
[04-14_06:48:27:080] should use "/sbin/ifstaus wan" to check rmnet_mhi0.1 's status?
[04-14_06:48:27:081] busybox udhcpc -f -n -q -t 5 -i rmnet_mhi0.1
[04-14_06:48:27:363] udhcpc: ifconfig rmnet_mhi0.1 10.245.22.3 netmask 255.255.255.248 broadcast +
[04-14_06:48:27:398] udhcpc: setting default routers: 10.245.22.4
[04-14_06:48:27:491] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: 5G_NSA
root@OpenWrt:~# quectel-CM -n 2 -s 4gnet -b &
[04-14_06:48:06:842] Quectel_QConnectManager_Linux_V1.6.0.25
[04-14_06:48:06:853] network interface '' or qmidev '' is not exist
[04-14_06:48:06:854] netcard driver = pcie_mhi, driver version = V1.3.0.17
[04-14_06:48:06:855] qmap_mode = 4, qmap_version = 9, qmap_size = 16384, muxid = 0x82, qmap_netcard = rmnet_mhi0.2
[04-14_06:48:06:855] Modem works in QMI mode
[04-14_06:48:06:857] connect to quectel-qmi-proxy0 sockfd = 7
[04-14_06:48:06:858] cdc_wdm_fd = 7
[04-14_06:48:06:864] Get clientWDS = 16
[04-14_06:48:06:867] Get clientDMS = 3
[04-14_06:48:06:871] Get clientNAS = 5
[04-14_06:48:06:874] Get clientUIM = 2
[04-14_06:48:06:879] Get clientWDA = 2
[04-14_06:48:06:886] requestBaseBandVersion RM500QGLABR10A03M4G
[04-14_06:48:06:891] qmap_settings.rx_urb_size = 16384
[04-14_06:48:06:891] qmap_settings.ul_data_aggregation_max_datagrams = 11
[04-14_06:48:06:892] qmap_settings.ul_data_aggregation_max_size = 8192
[04-14_06:48:06:892] qmap_settings.dl_minimum_padding = 0
[04-14_06:48:06:909] requestGetSIMStatus SIMStatus: SIM_READY
[04-14_06:48:06:909] requestSetProfile[2] 4gnet///0
[04-14_06:48:06:940] requestGetProfile[2] 4gnet///0
[04-14_06:48:06:944] requestRegistrationState2 MCC: 0, MNC: 0, PS: Detached, DataCap: UNKNOW
[04-14_06:48:06:949] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED
[04-14_06:48:06:949] ifconfig rmnet_mhi0 down
[04-14_06:48:06:973] ifconfig rmnet_mhi0.2 0.0.0.0
[04-14_06:48:06:998] ifconfig rmnet_mhi0.2 down
[04-14_06:48:26:400] requestRegistrationState2 MCC: 460, MNC: 0, PS: Detached, DataCap: UNKNOW
[04-14_06:48:26:405] requestRegistrationState2 MCC: 460, MNC: 0, PS: Detached, DataCap: UNKNOW
[04-14_06:48:26:411] requestRegistrationState2 MCC: 460, MNC: 0, PS: Detached, DataCap: UNKNOW
[04-14_06:48:26:970] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: 5G_NSA
[04-14_06:48:27:220] requestSetupDataCall WdsConnectionIPv4Handle: 0x341450a0
[04-14_06:48:27:228] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: 5G_NSA
[04-14_06:48:27:238] ifconfig rmnet_mhi0 up
[04-14_06:48:27:263] ifconfig rmnet_mhi0.2 up
[04-14_06:48:27:313] echo '0xaf51be9' > /sys/class/net/rmnet_mhi0.2/bridge_ipv4
root@OpenWrt:~# ifconfig rmnet_mhi0.1
rmnet_mhi0.1 Link encap:Ethernet HWaddr 02:50:F4:00:00:00
inet addr:10.245.22.3 Mask:255.255.255.248
inet6 addr: fe80::50:f4ff:fe00:0/64 Scope:Link
UP RUNNING NOARP MTU:1500 Metric:1
RX packets:6 errors:0 dropped:0 overruns:0 frame:0
TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1836 (1.7 KiB) TX bytes:2052 (2.0 KiB)
root@OpenWrt:~# ifconfig rmnet_mhi0.2
rmnet_mhi0.2 Link encap:Ethernet HWaddr 02:50:F4:00:00:00
inet6 addr: fe80::50:f4ff:fe00:0/64 Scope:Link
UP RUNNING NOARP MTU:1500 Metric:1
RX packets:347 errors:0 dropped:0 overruns:0 frame:0
TX packets:795 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:119871 (117.0 KiB) TX bytes:121254 (118.4 KiB)
root@OpenWrt:~# ifconfig br0 up
[ 520.005476] rmnet_mhi0.2 PC Mac Address: 00:0e:c6:a6:6c:f1
[ 520.025896] rmnet_mhi0.2 PC Mac Address: 00:0e:c6:a6:6c:f1
[ 520.028002] rmnet_mhi0.2 PC Mac Address: 00:0e:c6:a6:6c:f1
[ 520.144371] rmnet_mhi0.2 sip = 10.245.27.233, tip=10.245.27.234, ipv4=10.245.27.233
[ 520.410052] rmnet_mhi0.2 sip = 0.0.0.0, tip=10.245.27.233, ipv4=10.245.27.233
[ 520.414504] rmnet_mhi0.2 sip = 10.245.27.233, tip=10.245.27.234, ipv4=10.245.27.233
[ 520.847074] rmnet_mhi0.2 sip = 10.245.27.233, tip=10.245.27.234, ipv4=10.245.27.233
[ 521.410241] rmnet_mhi0.2 sip = 0.0.0.0, tip=10.245.27.233, ipv4=10.245.27.233
[ 522.410455] rmnet_mhi0.2 sip = 0.0.0.0, tip=10.245.27.233, ipv4=10.245.27.233
[ 522.822594] rmnet_mhi0.2 sip = 10.245.27.233, tip=10.245.27.234, ipv4=10.245.27.233
[ 523.410638] rmnet_mhi0.2 sip = 10.245.27.233, tip=10.245.27.233, ipv4=10.245.27.233
[ 523.510028] rmnet_mhi0.2 sip = 10.245.27.233, tip=10.245.27.234, ipv4=10.245.27.233
[ 523.997961] rmnet_mhi0.2 sip = 10.245.27.233, tip=10.245.27.234, ipv4=10.245.27.233
[ 543.799483] rmnet_mhi0.2 sip = 10.245.27.233, tip=10.245.27.234, ipv4=10.245.27.233
[ 543.929301] rmnet_mhi0.2 sip = 10.245.27.233, tip=10.245.27.234, ipv4=10.245.27.233

View File

@ -1,65 +0,0 @@
root@ZhuoTK:/# dmesg
[ 15.840000] qmi_wwan_q 1-1.3:1.4: cdc-wdm0: USB WDM device
[ 15.860000] qmi_wwan_q 1-1.3:1.4: Quectel Android work on RawIP mode
[ 15.860000] qmi_wwan_q 1-1.3:1.4: rx_urb_size = 1520
[ 15.870000] qmi_wwan_q 1-1.3:1.4 wwan0: register 'qmi_wwan_q' at usb-101c0000.ehci-1.3, WWAN/QMI device, da:0b:ce:b2:db:21
root@ZhuoTK:/# quectel-CM -s cment &
[04-13_03:20:20:456] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_03:20:20:459] Find /sys/bus/usb/devices/1-1.3 idVendor=0x2c7c idProduct=0x125, bus=0x001, dev=0x003
[04-13_03:20:20:460] Auto find qmichannel = /dev/cdc-wdm0
[04-13_03:20:20:460] Auto find usbnet_adapter = wwan0
[04-13_03:20:20:461] netcard driver = qmi_wwan_q, driver version = V1.2.0.23
[04-13_03:20:20:461] Modem works in QMI mode
[04-13_03:20:20:469] cdc_wdm_fd = 7
[04-13_03:20:20:547] Get clientWDS = 4
[04-13_03:20:20:579] Get clientDMS = 1
[04-13_03:20:20:611] Get clientNAS = 4
[04-13_03:20:20:643] Get clientUIM = 1
[04-13_03:20:20:675] Get clientWDA = 1
[04-13_03:20:20:707] requestBaseBandVersion EC25EFAR06A11M4G
[04-13_03:20:20:836] requestGetSIMStatus SIMStatus: SIM_READY
[04-13_03:20:20:836] requestSetProfile[1] cment///0
[04-13_03:20:20:899] requestGetProfile[1] cment///0
[04-13_03:20:20:931] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: LTE
[04-13_03:20:20:963] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED
[04-13_03:20:20:963] ifconfig wwan0 0.0.0.0
[04-13_03:20:20:976] ifconfig wwan0 down
[04-13_03:20:21:186] requestSetupDataCall WdsConnectionIPv4Handle: 0x8723e780
[04-13_03:20:21:316] ifconfig wwan0 up
[04-13_03:20:21:329] you are use OpenWrt?
[04-13_03:20:21:330] should not calling udhcpc manually?
[04-13_03:20:21:330] should modify /etc/config/network as below?
[04-13_03:20:21:330] config interface wan
[04-13_03:20:21:330] option ifname wwan0
[04-13_03:20:21:330] option proto dhcp
[04-13_03:20:21:330] should use "/sbin/ifstaus wan" to check wwan0 's status?
[04-13_03:20:21:331] busybox udhcpc -f -n -q -t 5 -i wwan0
[04-13_03:20:21:341] udhcpc (v1.23.2) started
[04-13_03:20:21:353] Sending discover...
[04-13_03:20:21:362] Sending select for 10.90.1.113...
[04-13_03:20:21:365] Lease of 10.90.1.113 obtained, lease time 7200
[04-13_03:20:21:370] udhcpc: ifconfig wwan0 10.90.1.113 netmask 255.255.255.252 broadcast +
[04-13_03:20:21:380] udhcpc: setting default routers: 10.90.1.114
root@ZhuoTK:/# ifconfig wwan0
wwan0 Link encap:Ethernet HWaddr 00:CA:01:91:97:BA
inet addr:10.90.1.113 Mask:255.255.255.252
inet6 addr: fe80::2ca:1ff:fe91:97ba/64 Scope:Link
UP RUNNING NOARP MTU:1500 Metric:1
RX packets:38 errors:0 dropped:0 overruns:0 frame:0
TX packets:46 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:5244 (5.1 KiB) TX bytes:6964 (6.8 KiB)
root@ZhuoTK:/# ip ro show
default via 10.90.1.114 dev wwan0
10.90.1.112/30 dev wwan0 proto kernel scope link src 10.90.1.113
192.168.1.0/24 dev br-lan proto kernel scope link src 192.168.1.251
root@ZhuoTK:/# killall quectel-CM
[04-13_03:20:46:130] requestDeactivateDefaultPDP WdsConnectionIPv4Handle
[04-13_03:20:46:406] ifconfig wwan0 0.0.0.0
[04-13_03:20:46:418] ifconfig wwan0 down
[04-13_03:20:46:600] QmiWwanThread exit
[04-13_03:20:46:600] qmi_main exit

View File

@ -1,57 +0,0 @@
root@ZhuoTK:/# insmod qmi_wwan_q.ko
[ 116.910000] qmi_wwan_q 1-1.3:1.4: cdc-wdm0: USB WDM device
[ 116.930000] qmi_wwan_q 1-1.3:1.4: Quectel Android work on RawIP mode
[ 116.930000] qmi_wwan_q 1-1.3:1.4: rx_urb_size = 1520
[ 116.940000] qmi_wwan_q 1-1.3:1.4 wwan0: register 'qmi_wwan_q' at usb-101c0000.ehci-1.3, WWAN/QMI device, 06:fb:51:a3:d6:c5
[ 116.950000] usbcore: registered new interface driver qmi_wwan_q
root@ZhuoTK:/# brctl addbr br0
root@ZhuoTK:/# brctl addif br0 eth0.1
root@ZhuoTK:/# brctl addif br0 wwan0
root@ZhuoTK:/# brctl show
bridge name bridge id STP enabled interfaces
br0 8000.00ca019197b9 no eth0.1
wwan0
root@ZhuoTK:/# quectel-CM -s cmnet -b &
root@ZhuoTK:/# [04-13_05:13:39:369] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_05:13:39:372] Find /sys/bus/usb/devices/1-1.3 idVendor=0x2c7c idProduct=0x125, bus=0x001, dev=0x003
[ 143.340000] net wwan0: bridge_mode change to 0x1
[04-13_05:13:39:373] Auto find qmichannel = /dev/cdc-wdm0
[04-13_05:13:39:374] Auto find usbnet_adapter = wwan0
[04-13_05:13:39:374] netcard driver = qmi_wwan_q, driver version = V1.2.0.23
[04-13_05:13:39:380] Modem works in QMI mode
[04-13_05:13:39:388] cdc_wdm_fd = 7
[04-13_05:13:39:466] Get clientWDS = 5
[04-13_05:13:39:496] Get clientDMS = 2
[04-13_05:13:39:527] Get clientNAS = 4
[04-13_05:13:39:559] Get clientUIM = 1
[04-13_05:13:39:592] Get clientWDA = 1
[04-13_05:13:39:626] requestBaseBandVersion EC25EFAR06A11M4G
[04-13_05:13:39:752] requestGetSIMStatus SIMStatus: SIM_READY
[04-13_05:13:39:752] requestSetProfile[1] cmnet///0
[04-13_05:13:39:816] requestGetProfile[1] cmnet///0
[04-13_05:13:39:848] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: LTE
[04-13_05:13:39:879] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED
[04-13_05:13:39:880] ifconfig wwan0 0.0.0.0
[04-13_05:13:39:893] ifconfig wwan0 down
[04-13_05:13:39:943] requestSetupDataCall WdsConnectionIPv4Handle: 0x872627c0
[04-13_05:13:40:073] ifconfig wwan0 up
[04-13_05:13:40:085] echo '0xa8d9237' > /sys/class/net/wwan0/bridge_ipv4
root@ZhuoTK:/# ifconfig br0 up
[ 165.730000] wwan0 PC Mac Address: 00:0e:c6:a6:6c:f1
[ 165.750000] wwan0 PC Mac Address: 00:0e:c6:a6:6c:f1
[ 165.860000] wwan0 sip = 10.141.146.55, tip=10.141.146.56, ipv4=10.141.146.55
[ 165.870000] wwan0 sip = 10.141.146.55, tip=10.141.146.56, ipv4=10.141.146.55
[ 165.990000] wwan0 sip = 10.141.146.55, tip=10.141.146.56, ipv4=10.141.146.55
[ 166.010000] wwan0 sip = 0.0.0.0, tip=10.141.146.55, ipv4=10.141.146.55
[ 166.070000] wwan0 sip = 10.141.146.55, tip=10.141.146.56, ipv4=10.141.146.55
[ 167.010000] wwan0 sip = 0.0.0.0, tip=10.141.146.55, ipv4=10.141.146.55
[ 167.480000] br0: port 2(wwan0) entered forwarding state
[ 167.520000] br0: port 1(eth0.1) entered forwarding state
[ 168.020000] wwan0 sip = 0.0.0.0, tip=10.141.146.55, ipv4=10.141.146.55
[ 169.010000] wwan0 sip = 10.141.146.55, tip=10.141.146.55, ipv4=10.141.146.55
[ 169.120000] wwan0 sip = 10.141.146.55, tip=10.141.146.56, ipv4=10.141.146.55
[ 169.130000] wwan0 sip = 10.141.146.55, tip=10.141.146.56, ipv4=10.141.146.55
[ 176.620000] wwan0 sip = 10.141.146.55, tip=10.141.146.56, ipv4=10.141.146.55

View File

@ -1,54 +0,0 @@
root@ZhuoTK:/# insmod qmi_wwan_q.ko qmap_mode=1
[ 1367.200000] usbcore: registered new interface driver qmi_wwan_q
[ 1383.840000] usb 1-1.3: new high-speed USB device number 7 using ehci-platform
[ 1384.080000] qmi_wwan_q 1-1.3:1.4: cdc-wdm0: USB WDM device
[ 1384.080000] qmi_wwan_q 1-1.3:1.4: Quectel Android work on RawIP mode
[ 1384.100000] qmi_wwan_q 1-1.3:1.4: rx_urb_size = 4096
[ 1384.100000] qmi_wwan_q 1-1.3:1.4 wwan0: register 'qmi_wwan_q' at usb-101c0000.ehci-1.3, WWAN/QMI device, da:0b:ce:b2:db:21
root@ZhuoTK:/# quectel-CM -s cmnet &
[04-13_03:41:28:144] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_03:41:28:146] Find /sys/bus/usb/devices/1-1.3 idVendor=0x2c7c idProduct=0x125, bus=0x001, dev=0x007
[04-13_03:41:28:148] Auto find qmichannel = /dev/cdc-wdm0
[04-13_03:41:28:148] Auto find usbnet_adapter = wwan0
[04-13_03:41:28:148] netcard driver = qmi_wwan_q, driver version = V1.2.0.23
[04-13_03:41:28:149] qmap_mode = 1, qmap_version = 5, qmap_size = 4096, muxid = 0x81, qmap_netcard = wwan0
[04-13_03:41:28:150] Modem works in QMI mode
[04-13_03:41:28:158] cdc_wdm_fd = 7
[04-13_03:41:28:238] Get clientWDS = 4
[04-13_03:41:28:271] Get clientDMS = 1
[04-13_03:41:28:302] Get clientNAS = 4
[04-13_03:41:28:334] Get clientUIM = 1
[04-13_03:41:28:365] Get clientWDA = 1
[04-13_03:41:28:397] requestBaseBandVersion EC25EFAR06A11M4G
[04-13_03:41:28:430] qmap_settings.rx_urb_size = 4096
[ 1393.530000] net wwan0: ul_data_aggregation_max_datagrams=11, ul_data_aggregation_max_size=4096, dl_minimum_padding=0
[04-13_03:41:28:431] qmap_settings.ul_data_aggregation_max_datagrams = 11
[04-13_03:41:28:431] qmap_settings.ul_data_aggregation_max_size = 4096
[04-13_03:41:28:431] qmap_settings.dl_minimum_padding = 0
[04-13_03:41:28:557] requestGetSIMStatus SIMStatus: SIM_READY
[04-13_03:41:28:558] requestSetProfile[1] cmnet///0
[04-13_03:41:28:622] requestGetProfile[1] cmnet///0
[04-13_03:41:28:654] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: LTE
[04-13_03:41:28:685] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED
[ 1393.790000] net wwan0: link_state 0x1 -> 0x0
[04-13_03:41:28:692] ifconfig wwan0 0.0.0.0
[04-13_03:41:28:703] ifconfig wwan0 down
[04-13_03:41:28:751] requestSetupDataCall WdsConnectionIPv4Handle: 0x8729a6b0
[ 1393.980000] net wwan0: link_state 0x0 -> 0x1
[04-13_03:41:28:882] ifconfig wwan0 up
[04-13_03:41:28:895] you are use OpenWrt?
[04-13_03:41:28:895] should not calling udhcpc manually?
[04-13_03:41:28:895] should modify /etc/config/network as below?
[04-13_03:41:28:896] config interface wan
[04-13_03:41:28:896] option ifname wwan0
[04-13_03:41:28:896] option proto dhcp
[04-13_03:41:28:896] should use "/sbin/ifstaus wan" to check wwan0 's status?
[04-13_03:41:28:896] busybox udhcpc -f -n -q -t 5 -i wwan0
[04-13_03:41:28:907] udhcpc (v1.23.2) started
[04-13_03:41:28:919] Sending discover...
[04-13_03:41:28:925] Sending select for 10.129.198.20...
[04-13_03:41:28:929] Lease of 10.129.198.20 obtained, lease time 7200
[04-13_03:41:28:934] udhcpc: ifconfig wwan0 10.129.198.20 netmask 255.255.255.248 broadcast +
[04-13_03:41:28:949] udhcpc: setting default routers: 10.129.198.21

View File

@ -1,86 +0,0 @@
root@ZhuoTK:/# insmod qmi_wwan_q.ko qmap_mode=1
[ 49.000000] qmi_wwan_q 1-1.3:1.4: cdc-wdm0: USB WDM device
[ 49.000000] qmi_wwan_q 1-1.3:1.4: Quectel Android work on RawIP mode
[ 49.020000] qmi_wwan_q 1-1.3:1.4: rx_urb_size = 4096
[ 49.020000] qmi_wwan_q 1-1.3:1.4 wwan0: register 'qmi_wwan_q' at usb-101c0000.ehci-1.3, WWAN/QMI device, de:ae:5c:82:b5:b2
[ 49.030000] usbcore: registered new interface driver qmi_wwan_q
root@ZhuoTK:/# brctl addbr br0
root@ZhuoTK:/# brctl addif br0 eth0.1
root@ZhuoTK:/# brctl addif br0 wwan0
root@ZhuoTK:/# brctl show
bridge name bridge id STP enabled interfaces
br0 8000.00ca019197b9 no eth0.1
wwan0
root@ZhuoTK:/# quectel-CM -s cmnet -b &
[04-13_05:11:46:442] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_05:11:46:444] Find /sys/bus/usb/devices/1-1.3 idVendor=0x2c7c idProduct=0x125, bus=0x001, dev=0x003
[ 84.340000] net wwan0: bridge_mode change to 0x1
[04-13_05:11:46:446] Auto find qmichannel = /dev/cdc-wdm0
[04-13_05:11:46:446] Auto find usbnet_adapter = wwan0
[04-13_05:11:46:446] netcard driver = qmi_wwan_q, driver version = V1.2.0.23
[04-13_05:11:46:447] qmap_mode = 1, qmap_version = 5, qmap_size = 4096, muxid = 0x81, qmap_netcard = wwan0
[04-13_05:11:46:454] Modem works in QMI mode
[04-13_05:11:46:462] cdc_wdm_fd = 7
[04-13_05:11:46:537] Get clientWDS = 5
[04-13_05:11:46:569] Get clientDMS = 1
[04-13_05:11:46:601] Get clientNAS = 4
[04-13_05:11:46:633] Get clientUIM = 1
[04-13_05:11:46:666] Get clientWDA = 1
[04-13_05:11:46:697] requestBaseBandVersion EC25EFAR06A11M4G
[04-13_05:11:46:730] qmap_settings.rx_urb_size = 4096
[ 84.620000] net wwan0: ul_data_aggregation_max_datagrams=11, ul_data_aggregation_max_size=4096, dl_minimum_padding=0
[04-13_05:11:46:730] qmap_settings.ul_data_aggregation_max_datagrams = 11
[04-13_05:11:46:730] qmap_settings.ul_data_aggregation_max_size = 4096
[04-13_05:11:46:730] qmap_settings.dl_minimum_padding = 0
[04-13_05:11:46:859] requestGetSIMStatus SIMStatus: SIM_READY
[04-13_05:11:46:859] requestSetProfile[1] cmnet///0
[04-13_05:11:46:922] requestGetProfile[1] cmnet///0
[04-13_05:11:46:954] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: LTE
[04-13_05:11:46:986] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED
[ 84.880000] net wwan0: link_state 0x1 -> 0x0
[04-13_05:11:46:992] ifconfig wwan0 0.0.0.0
[04-13_05:11:47:005] ifconfig wwan0 down
[04-13_05:11:47:050] requestSetupDataCall WdsConnectionIPv4Handle: 0x872a5830
[ 85.070000] net wwan0: link_state 0x0 -> 0x1
[04-13_05:11:47:183] ifconfig wwan0 up
[04-13_05:11:47:195] echo '0xa54a78b' > /sys/class/net/wwan0/bridge_ipv4
root@ZhuoTK:/# ifconfig wwan0
wwan0 Link encap:Ethernet HWaddr DE:AE:5C:82:B5:B2
inet6 addr: fe80::dcae:5cff:fe82:b5b2/64 Scope:Link
UP RUNNING NOARP MTU:1500 Metric:1
RX packets:3792 errors:0 dropped:0 overruns:0 frame:0
TX packets:3271 errors:0 dropped:36 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:2271762 (2.1 MiB) TX bytes:565184 (551.9 KiB)
root@ZhuoTK:/# ifconfig br0 up
[ 89.530000] br0: port 2(wwan0) entered forwarding state
[ 89.530000] br0: port 2(wwan0) entered forwarding state
[ 89.540000] br0: port 1(eth0.1) entered forwarding state
[ 89.540000] br0: port 1(eth0.1) entered forwarding state
root@ZhuoTK:/#
[ 93.720000] wwan0 sip = 192.168.1.153, tip=10.84.167.140, ipv4=10.84.167.139
[ 104.560000] br0: port 2(wwan0) entered forwarding state
[ 104.560000] br0: port 1(eth0.1) entered forwarding state
[ 111.750000] rt305x-esw 10110000.esw: link changed 0x00
[ 116.440000] rt305x-esw 10110000.esw: link changed 0x01
[ 116.620000] wwan0 PC Mac Address: 00:0e:c6:a6:6c:f1
[ 116.680000] wwan0 PC Mac Address: 00:0e:c6:a6:6c:f1
[ 116.690000] wwan0 PC Mac Address: 00:0e:c6:a6:6c:f1
[ 116.760000] wwan0 sip = 10.84.167.139, tip=10.84.167.140, ipv4=10.84.167.139
[ 117.050000] wwan0 sip = 10.84.167.139, tip=10.84.167.140, ipv4=10.84.167.139
[ 117.220000] wwan0 sip = 0.0.0.0, tip=10.84.167.139, ipv4=10.84.167.139
[ 117.820000] wwan0 sip = 10.84.167.139, tip=10.84.167.140, ipv4=10.84.167.139
[ 118.220000] wwan0 sip = 0.0.0.0, tip=10.84.167.139, ipv4=10.84.167.139
[ 118.300000] wwan0 sip = 10.84.167.139, tip=10.84.167.140, ipv4=10.84.167.139
[ 119.220000] wwan0 sip = 0.0.0.0, tip=10.84.167.139, ipv4=10.84.167.139
[ 120.220000] wwan0 sip = 10.84.167.139, tip=10.84.167.139, ipv4=10.84.167.139
[ 120.300000] wwan0 sip = 10.84.167.139, tip=10.84.167.140, ipv4=10.84.167.139
[ 121.430000] wwan0 sip = 10.84.167.139, tip=10.84.167.140, ipv4=10.84.167.139
[ 141.730000] wwan0 sip = 10.84.167.139, tip=10.84.167.140, ipv4=10.84.167.139
[ 144.390000] wwan0 sip = 10.84.167.139, tip=10.84.167.140, ipv4=10.84.167.139
[ 144.510000] wwan0 sip = 10.84.167.139, tip=10.84.167.140, ipv4=10.84.167.139

View File

@ -1,185 +0,0 @@
root@ZhuoTK:/# insmod qmi_wwan_q.ko qmap_mode=4
[ 1515.180000] usbcore: registered new interface driver qmi_wwan_q
[ 1530.260000] usb 1-1.3: new high-speed USB device number 8 using ehci-platform
[ 1530.500000] qmi_wwan_q 1-1.3:1.4: cdc-wdm0: USB WDM device
[ 1530.500000] qmi_wwan_q 1-1.3:1.4: Quectel Android work on RawIP mode
[ 1530.520000] qmi_wwan_q 1-1.3:1.4: rx_urb_size = 4096
[ 1530.520000] qmi_wwan_q 1-1.3:1.4 wwan0: register 'qmi_wwan_q' at usb-101c0000.ehci-1.3, RMNET/USB device, da:0b:ce:b2:db:21
[ 1530.530000] net wwan0: qmap_register_device wwan0_1
[ 1530.540000] net wwan0: qmap_register_device wwan0_2
[ 1530.550000] net wwan0: qmap_register_device wwan0_3
[ 1530.550000] net wwan0: qmap_register_device wwan0_4
root@ZhuoTK:~# quectel-qmi-proxy &
[04-13_03:44:53:958] Will use cdc-wdm='/dev/cdc-wdm0', proxy='quectel-qmi-proxy0'
[04-13_03:44:53:959] qmi_proxy_init enter
[04-13_03:44:53:960] qmi_proxy_loop enter thread_id 0x77c07530
[04-13_03:44:54:960] qmi_proxy_init succful
[04-13_03:44:54:960] local server: quectel-qmi-proxy0 sockfd = 4
[04-13_03:44:54:960] qmi_proxy_server_fd = 4
[04-13_03:45:04:346] +++ ClientFd=5
[04-13_03:45:04:410] +++ ClientFd=5 QMIType=1 ClientId=4
[04-13_03:45:04:442] +++ ClientFd=5 QMIType=2 ClientId=1
[04-13_03:45:04:474] +++ ClientFd=5 QMIType=3 ClientId=4
[04-13_03:45:04:506] +++ ClientFd=5 QMIType=11 ClientId=1
[04-13_03:45:04:539] +++ ClientFd=5 QMIType=26 ClientId=1
[04-13_03:45:10:770] +++ ClientFd=6
[04-13_03:45:10:811] +++ ClientFd=6 QMIType=1 ClientId=21
[04-13_03:45:10:843] +++ ClientFd=6 QMIType=2 ClientId=2
[04-13_03:45:10:875] +++ ClientFd=6 QMIType=3 ClientId=5
[04-13_03:45:10:907] +++ ClientFd=6 QMIType=11 ClientId=2
[04-13_03:46:31:419] --- ClientFd=6 QMIType=1 ClientId=21
[04-13_03:46:31:451] --- ClientFd=6 QMIType=2 ClientId=2
[04-13_03:46:31:484] --- ClientFd=6 QMIType=3 ClientId=5
[04-13_03:46:31:517] --- ClientFd=6 QMIType=11 ClientId=2
[04-13_03:46:31:518] qmi_proxy_loop poll fd = 6, revents = 0011
[04-13_03:46:31:519] --- ClientFd=6
root@ZhuoTK:/# quectel-CM -n 1 -s cmnet &
root@ZhuoTK:/# [04-13_03:45:04:340] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_03:45:04:343] Find /sys/bus/usb/devices/1-1.3 idVendor=0x2c7c idProduct=0x125, bus=0x001, dev=0x008
[04-13_03:45:04:344] Auto find qmichannel = /dev/cdc-wdm0
[04-13_03:45:04:344] Auto find usbnet_adapter = wwan0
[04-13_03:45:04:345] netcard driver = qmi_wwan_q, driver version = V1.2.0.23
[04-13_03:45:04:345] qmap_mode = 4, qmap_version = 5, qmap_size = 4096, muxid = 0x81, qmap_netcard = wwan0_1
[04-13_03:45:04:345] Modem works in QMI mode
[04-13_03:45:04:347] connect to quectel-qmi-proxy0 sockfd = 7
[04-13_03:45:04:347] cdc_wdm_fd = 7
[04-13_03:45:04:411] Get clientWDS = 4
[04-13_03:45:04:443] Get clientDMS = 1
[04-13_03:45:04:475] Get clientNAS = 4
[04-13_03:45:04:507] Get clientUIM = 1
[04-13_03:45:04:540] Get clientWDA = 1
[04-13_03:45:04:571] requestBaseBandVersion EC25EFAR06A11M4G
[04-13_03:45:04:602] qmap_settings.rx_urb_size = 4096
[ 1609.700000] net wwan0: ul_data_aggregation_max_datagrams=11, ul_data_aggregation_max_size=4096, dl_minimum_padding=0
[04-13_03:45:04:603] qmap_settings.ul_data_aggregation_max_datagrams = 11
[04-13_03:45:04:603] qmap_settings.ul_data_aggregation_max_size = 4096
[04-13_03:45:04:603] qmap_settings.dl_minimum_padding = 0
[04-13_03:45:04:731] requestGetSIMStatus SIMStatus: SIM_READY
[04-13_03:45:04:731] requestSetProfile[1] cmnet///0
[04-13_03:45:04:795] requestGetProfile[1] cmnet///0
[04-13_03:45:04:827] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: LTE
[04-13_03:45:04:858] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED
[ 1609.960000] net wwan0: link_state 0x1 -> 0x0
[04-13_03:45:04:865] ifconfig wwan0 down
[04-13_03:45:04:879] ifconfig wwan0_1 0.0.0.0
[04-13_03:45:04:889] ifconfig wwan0_1 down
[04-13_03:45:04:955] requestSetupDataCall WdsConnectionIPv4Handle: 0x87253410
[ 1610.180000] net wwan0: link_state 0x0 -> 0x1
[04-13_03:45:05:087] ifconfig wwan0 up
[ 1610.200000] IPv6: ADDRCONF(NETDEV_UP): wwan0: link is not ready
[04-13_03:45:05:105] ifconfig wwan0_1 up
[ 1610.220000] IPv6: ADDRCONF(NETDEV_CHANGE): wwan0: link becomes ready
[04-13_03:45:05:125] you are use OpenWrt?
[04-13_03:45:05:125] should not calling udhcpc manually?
[04-13_03:45:05:125] should modify /etc/config/network as below?
[04-13_03:45:05:125] config interface wan
[04-13_03:45:05:125] option ifname wwan0_1
[04-13_03:45:05:125] option proto dhcp
[04-13_03:45:05:126] should use "/sbin/ifstaus wan" to check wwan0_1 's status?
[04-13_03:45:05:126] busybox udhcpc -f -n -q -t 5 -i wwan0_1
[04-13_03:45:05:136] udhcpc (v1.23.2) started
[04-13_03:45:05:148] Sending discover...
[04-13_03:45:05:155] Sending select for 10.244.10.206...
[04-13_03:45:05:160] Lease of 10.244.10.206 obtained, lease time 7200
[04-13_03:45:05:165] udhcpc: ifconfig wwan0_1 10.244.10.206 netmask 255.255.255.252 broadcast +
[04-13_03:45:05:174] udhcpc: setting default routers: 10.244.10.205
root@ZhuoTK:/# quectel-CM -n 2 -s 4gnet &
[04-13_03:45:10:764] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_03:45:10:767] Find /sys/bus/usb/devices/1-1.3 idVendor=0x2c7c idProduct=0x125, bus=0x001, dev=0x008
[04-13_03:45:10:768] Auto find qmichannel = /dev/cdc-wdm0
[04-13_03:45:10:768] Auto find usbnet_adapter = wwan0
[04-13_03:45:10:768] netcard driver = qmi_wwan_q, driver version = V1.2.0.23
[04-13_03:45:10:769] qmap_mode = 4, qmap_version = 5, qmap_size = 4096, muxid = 0x82, qmap_netcard = wwan0_2
[04-13_03:45:10:769] Modem works in QMI mode
[04-13_03:45:10:771] connect to quectel-qmi-proxy0 sockfd = 7
[04-13_03:45:10:771] cdc_wdm_fd = 7
[04-13_03:45:10:812] Get clientWDS = 21
[04-13_03:45:10:844] Get clientDMS = 2
[04-13_03:45:10:876] Get clientNAS = 5
[04-13_03:45:10:908] Get clientUIM = 2
[04-13_03:45:10:971] requestBaseBandVersion EC25EFAR06A11M4G
[04-13_03:45:11:099] requestGetSIMStatus SIMStatus: SIM_READY
[04-13_03:45:11:099] requestSetProfile[2] 4gnet///0
[04-13_03:45:11:163] requestGetProfile[2] 4gnet///0
[04-13_03:45:11:195] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: LTE
[04-13_03:45:11:227] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED
[04-13_03:45:11:227] ifconfig wwan0_2 0.0.0.0
[ 1616.340000] IPv6: ADDRCONF(NETDEV_UP): wwan0_2: link is not ready
[04-13_03:45:11:246] ifconfig wwan0_2 down
[04-13_03:45:11:642] requestSetupDataCall WdsConnectionIPv4Handle: 0x87254580
[ 1616.870000] net wwan0: link_state 0x1 -> 0x3
[04-13_03:45:11:775] ifconfig wwan0 up
[04-13_03:45:11:785] ifconfig wwan0_2 up
[04-13_03:45:11:798] you are use OpenWrt?
[04-13_03:45:11:798] should not calling udhcpc manually?
[04-13_03:45:11:798] should modify /etc/config/network as below?
[04-13_03:45:11:798] config interface wan
[04-13_03:45:11:798] option ifname wwan0_2
[04-13_03:45:11:798] option proto dhcp
[04-13_03:45:11:798] should use "/sbin/ifstaus wan" to check wwan0_2 's status?
[04-13_03:45:11:799] busybox udhcpc -f -n -q -t 5 -i wwan0_2
[04-13_03:45:11:809] udhcpc (v1.23.2) started
[04-13_03:45:11:821] Sending discover...
[04-13_03:45:11:830] Sending select for 10.245.78.212...
[04-13_03:45:11:836] Lease of 10.245.78.212 obtained, lease time 7200
[04-13_03:45:11:842] udhcpc: ifconfig wwan0_2 10.245.78.212 netmask 255.255.255.248 broadcast +
[04-13_03:45:11:852] udhcpc: setting default routers: 10.245.78.213
root@ZhuoTK:/# ifconfig wwan0_1
wwan0_1 Link encap:Ethernet HWaddr DA:0B:CE:B2:DB:21
inet addr:10.244.10.206 Mask:255.255.255.252
inet6 addr: fe80::d80b:ceff:feb2:db21/64 Scope:Link
UP RUNNING NOARP MTU:1500 Metric:1
RX packets:2 errors:0 dropped:0 overruns:0 frame:0
TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:640 (640.0 B) TX bytes:1344 (1.3 KiB)
root@ZhuoTK:/# ifconfig wwan0_2
wwan0_2 Link encap:Ethernet HWaddr DA:0B:CE:B2:DB:21
inet addr:10.245.78.212 Mask:255.255.255.248
inet6 addr: fe80::d80b:ceff:feb2:db21/64 Scope:Link
UP RUNNING NOARP MTU:1500 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:7 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1193 (1.1 KiB) TX bytes:1028 (1.0 KiB)
root@ZhuoTK:/# ip ro del 8.8.8.8/32
RTNETLINK answers: No such process
root@ZhuoTK:/# ip ro add 8.8.8.8/32 dev wwan0_1
root@ZhuoTK:/# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=52 time=113.508 ms
root@ZhuoTK:/# ip ro del 8.8.8.8/32
root@ZhuoTK:/# ip ro del 8.8.8.8/32
RTNETLINK answers: No such process
root@ZhuoTK:/# ip ro add 8.8.8.8/32 dev wwan0_2
root@ZhuoTK:/# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=111 time=123.651 ms
root@ZhuoTK:/# quectel-CM -k 2
[04-13_03:46:30:808] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_03:46:30:811] /proc/2834/cmdline: quectel-CM -n 2 -s 4gnet
[04-13_03:46:30:811] send SIGINT to process 2834
[04-13_03:46:30:811] requestDeactivateDefaultPDP WdsConnectionIPv4Handle
[ 1696.460000] net wwan0: link_state 0x3 -> 0x1
[04-13_03:46:31:361] ifconfig wwan0_2 0.0.0.0
[04-13_03:46:31:373] ifconfig wwan0_2 down
[04-13_03:46:31:516] QmiWwanThread exit
[04-13_03:46:31:516] qmi_main exit
root@ZhuoTK:/# ifconfig wwan0_2
wwan0_2 Link encap:Ethernet HWaddr DA:0B:CE:B2:DB:21
NOARP MTU:1500 Metric:1
RX packets:16 errors:0 dropped:0 overruns:0 frame:0
TX packets:15 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1865 (1.8 KiB) TX bytes:1620 (1.5 KiB)

View File

@ -1,132 +0,0 @@
root@ZhuoTK:/# brctl addbr br0
brctl: bridge br0: File exists
root@ZhuoTK:/# brctl delbr br0
root@ZhuoTK:/# brctl addbr br0
root@ZhuoTK:/# brctl addif br0 eth0.1
root@ZhuoTK:/# insmod qmi_wwan_q.ko qmap_mode=4
[ 365.340000] usbcore: registered new interface driver qmi_wwan_q
[ 380.860000] usb 1-1.3: new high-speed USB device number 4 using ehci-platform
[ 381.100000] qmi_wwan_q 1-1.3:1.4: cdc-wdm0: USB WDM device
[ 381.100000] qmi_wwan_q 1-1.3:1.4: Quectel Android work on RawIP mode
[ 381.120000] qmi_wwan_q 1-1.3:1.4: rx_urb_size = 4096
[ 381.120000] qmi_wwan_q 1-1.3:1.4 wwan0: register 'qmi_wwan_q' at usb-101c0000.ehci-1.3, RMNET/USB device, fa:24:73:b5:39:a8
[ 381.130000] net wwan0: qmap_register_device wwan0_1
[ 381.140000] net wwan0: qmap_register_device wwan0_2
[ 381.150000] net wwan0: qmap_register_device wwan0_3
[ 381.150000] net wwan0: qmap_register_device wwan0_4
root@ZhuoTK:/# brctl addbr br0
root@ZhuoTK:/# brctl addif br0 eth0.1
root@ZhuoTK:/# brctl addif br0 wwan0_2
root@ZhuoTK:/# brctl show
bridge name bridge id STP enabled interfaces
br0 8000.00ca019197b9 no eth0.1
wwan0_2
root@ZhuoTK:/# quectel-qmi-proxy &
[04-13_05:18:10:832] Will use cdc-wdm='/dev/cdc-wdm0', proxy='quectel-qmi-proxy0'
[04-13_05:18:10:833] qmi_proxy_init enter
[04-13_05:18:10:833] qmi_proxy_loop enter thread_id 0x77995530
[04-13_05:18:11:833] qmi_proxy_init succful
[04-13_05:18:11:833] local server: quectel-qmi-proxy0 sockfd = 4
[04-13_05:18:11:833] qmi_proxy_server_fd = 4
root@ZhuoTK:/# quectel-CM -n 2 -s 4gnet -b &
[04-13_05:18:20:144] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_05:18:20:146] Find /sys/bus/usb/devices/1-1.3 idVendor=0x2c7c idProduct=0x125, bus=0x001, dev=0x004
[04-13_05:18:20:147] Auto find qmichannel = /dev/cdc-wdm0
[04-13_05:18:20:148] Auto find usbnet_adapter = wwan0
[04-13_05:18:20:148] netcard driver = qmi_wwan_q, driver version = V1.2.0.23
[04-13_05:18:20:148] qmap_mode = 4, qmap_version = 5, qmap_size = 4096, muxid = 0x82, qmap_netcard = wwan0_2
[04-13_05:18:20:149] Modem works in QMI mode
[04-13_05:18:20:150] connect to quectel-qmi-proxy0 sockfd = 7
[04-13_05:18:20:150] cdc_wdm_fd = 7
[04-13_05:18:20:370] requestBaseBandVersion EC25EFAR06A11M4G
[04-13_05:18:20:403] qmap_settings.rx_urb_size = 4096
[04-13_05:18:20:404] qmap_settings.ul_data_aggregation_max_datagrams = 11
[04-13_05:18:20:404] qmap_settings.ul_data_aggregation_max_size = 4096
[04-13_05:18:20:404] qmap_settings.dl_minimum_padding = 0
[04-13_05:18:20:530] requestGetSIMStatus SIMStatus: SIM_READY
[04-13_05:18:20:530] requestSetProfile[2] 4gnet///0
[04-13_05:18:20:594] requestGetProfile[2] 4gnet///0
[04-13_05:18:20:626] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: LTE
[04-13_05:18:20:657] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED
[04-13_05:18:20:658] ifconfig wwan0_2 0.0.0.0
[04-13_05:18:20:669] ifconfig wwan0_2 down
[04-13_05:18:21:010] requestSetupDataCall WdsConnectionIPv4Handle: 0x87249650
[ 425.100000] net wwan0: link_state 0x1 -> 0x3
[04-13_05:18:21:143] ifconfig wwan0 up
[04-13_05:18:21:156] ifconfig wwan0_2 up
[04-13_05:18:21:168] echo '0xa8ceec7' > /sys/class/net/wwan0_2/bridge_ipv4
root@ZhuoTK:/# ifconfig br0 up
[ 450.520000] br0: port 2(wwan0_2) entered forwarding state
[ 450.520000] br0: port 1(eth0.1) entered forwarding state
[ 450.770000] wwan0_2 PC Mac Address: 00:0e:c6:a6:6c:f1
[ 450.790000] wwan0_2 PC Mac Address: 00:0e:c6:a6:6c:f1
[ 450.840000] wwan0_2 sip = 10.140.238.199, tip=10.140.238.200, ipv4=10.140.238.199
[ 450.950000] wwan0_2 sip = 10.140.238.199, tip=10.140.238.200, ipv4=10.140.238.199
[ 450.950000] wwan0_2 sip = 10.140.238.199, tip=10.140.238.200, ipv4=10.140.238.199
[ 451.120000] wwan0_2 sip = 0.0.0.0, tip=10.140.238.199, ipv4=10.140.238.199
[ 451.180000] wwan0_2 sip = 10.140.238.199, tip=10.140.238.200, ipv4=10.140.238.199
[ 452.120000] wwan0_2 sip = 0.0.0.0, tip=10.140.238.199, ipv4=10.140.238.199
[ 453.080000] wwan0_2 sip = 10.140.238.199, tip=10.140.238.200, ipv4=10.140.238.199
[ 453.120000] wwan0_2 sip = 0.0.0.0, tip=10.140.238.199, ipv4=10.140.238.199
[ 454.120000] wwan0_2 sip = 10.140.238.199, tip=10.140.238.199, ipv4=10.140.238.199
[ 454.220000] wwan0_2 sip = 10.140.238.199, tip=10.140.238.200, ipv4=10.140.238.199
[ 456.200000] wwan0_2 sip = 10.140.238.199, tip=10.140.238.200, ipv4=10.140.238.199
[ 458.120000] wwan0_2 sip = 10.140.238.199, tip=10.140.238.200, ipv4=10.140.238.199
[ 459.240000] wwan0_2 sip = 10.140.238.199, tip=10.140.238.200, ipv4=10.140.238.199
root@ZhuoTK:/# quectel-CM -n 1 -s cmnet &
[04-13_05:19:21:122] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_05:19:21:125] Find /sys/bus/usb/devices/1-1.3 idVendor=0x2c7c idProduct=0x125, bus=0x001, dev=0x004
[04-13_05:19:21:126] Auto find qmichannel = /dev/cdc-wdm0
[04-13_05:19:21:126] Auto find usbnet_adapter = wwan0
[04-13_05:19:21:127] netcard driver = qmi_wwan_q, driver version = V1.2.0.23
[04-13_05:19:21:127] qmap_mode = 4, qmap_version = 5, qmap_size = 4096, muxid = 0x81, qmap_netcard = wwan0_1
[04-13_05:19:21:127] Modem works in QMI mode
[04-13_05:19:21:128] connect to quectel-qmi-proxy0 sockfd = 7
[04-13_05:19:21:129] cdc_wdm_fd = 7
[04-13_05:19:21:331] requestBaseBandVersion EC25EFAR06A11M4G
[04-13_05:19:21:459] requestGetSIMStatus SIMStatus: SIM_READY
[04-13_05:19:21:459] requestSetProfile[1] cmnet///0
[04-13_05:19:21:522] requestGetProfile[1] cmnet///0
[04-13_05:19:21:554] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: LTE
[04-13_05:19:21:585] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED
[ 485.550000] net wwan0: link_state 0x3 -> 0x2
[04-13_05:19:21:592] ifconfig wwan0_1 0.0.0.0
[ 485.570000] IPv6: ADDRCONF(NETDEV_UP): wwan0_1: link is not ready
[04-13_05:19:21:610] ifconfig wwan0_1 down
[04-13_05:19:21:682] requestSetupDataCall WdsConnectionIPv4Handle: 0x8725ed70
[ 485.780000] net wwan0: link_state 0x2 -> 0x3
[04-13_05:19:21:815] ifconfig wwan0 up
[04-13_05:19:21:826] ifconfig wwan0_1 up
[04-13_05:19:21:845] you are use OpenWrt?
[04-13_05:19:21:845] should not calling udhcpc manually?
[04-13_05:19:21:845] should modify /etc/config/network as below?
[04-13_05:19:21:845] config interface wan
[04-13_05:19:21:845] option ifname wwan0_1
[04-13_05:19:21:845] option proto dhcp
[04-13_05:19:21:845] should use "/sbin/ifstaus wan" to check wwan0_1 's status?
[04-13_05:19:21:846] busybox udhcpc -f -n -q -t 5 -i wwan0_1
[04-13_05:19:21:863] udhcpc (v1.23.2) started
[04-13_05:19:21:923] Sending discover...
[04-13_05:19:21:927] Sending select for 10.141.146.55...
[04-13_05:19:21:932] Lease of 10.141.146.55 obtained, lease time 7200
[04-13_05:19:21:938] udhcpc: ifconfig wwan0_1 10.141.146.55 netmask 255.255.255.240 broadcast +
[04-13_05:19:21:949] udhcpc: setting default routers: 10.141.146.56
root@ZhuoTK:/# ip ro show
default via 10.141.146.56 dev wwan0_1
10.141.146.48/28 dev wwan0_1 proto kernel scope link src 10.141.146.55
192.168.1.0/24 dev br-lan proto kernel scope link src 192.168.1.251
root@ZhuoTK:/# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=111 time=86.006 ms
64 bytes from 8.8.8.8: seq=1 ttl=111 time=74.763 ms
64 bytes from 8.8.8.8: seq=2 ttl=111 time=85.501 ms
64 bytes from 8.8.8.8: seq=3 ttl=111 time=74.231 ms

View File

@ -1,55 +0,0 @@
# dmesg
[ 1737.738025] usb 1-1.2: new high-speed USB device number 5 using xhci-hcd
[ 1737.838917] usb 1-1.2: New USB device found, idVendor=2c7c, idProduct=0512, bcdDevice= 3.18
[ 1737.838948] usb 1-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 1737.838963] usb 1-1.2: Product: EG12-EA
[ 1737.838975] usb 1-1.2: Manufacturer: Quectel
[ 1737.838986] usb 1-1.2: SerialNumber: 0123456789ABCDE
[ 1737.994955] option 1-1.2:1.0: GSM modem (1-port) converter detected
[ 1737.995430] usb 1-1.2: GSM modem (1-port) converter now attached to ttyUSB0
[ 1737.995978] option 1-1.2:1.1: GSM modem (1-port) converter detected
[ 1737.996409] usb 1-1.2: GSM modem (1-port) converter now attached to ttyUSB1
[ 1737.996963] option 1-1.2:1.2: GSM modem (1-port) converter detected
[ 1737.997351] usb 1-1.2: GSM modem (1-port) converter now attached to ttyUSB2
[ 1737.997909] option 1-1.2:1.3: GSM modem (1-port) converter detected
[ 1737.998976] usb 1-1.2: GSM modem (1-port) converter now attached to ttyUSB3
[ 1825.835796] qmi_wwan 1-1.2:1.4: cdc-wdm0: USB WDM device
[ 1825.839685] qmi_wwan 1-1.2:1.4 wwan0: register 'qmi_wwan' at usb-fe9c0000.xhci-1.2, WWAN/QMI device, 0e:80:14:b1:f6:b9
[ 1825.840062] usbcore: registered new interface driver qmi_wwan
# ifconfig wwan0 down
# echo Y > /sys/class/net/wwan0/qmi/raw_ip
# echo 1 > /sys/class/net/wwan0/qmi/add_mux
# ifconfig qmimux0
qmimux0: flags=4240<POINTOPOINT,NOARP,MULTICAST> mtu 1500
unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 1000 (UNSPEC)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
# echo 2 > /sys/class/net/wwan0/qmi/add_mux
# echo 3 > /sys/class/net/wwan0/qmi/add_mux
# echo 4 > /sys/class/net/wwan0/qmi/add_mux
# ifconfig qmimux3
qmimux3: flags=4240<POINTOPOINT,NOARP,MULTICAST> mtu 1500
unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 1000 (UNSPEC)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
set wwan0's mtu to max qmap packet size, for usbnet.c:usbnet_change_mtu() do not accept
# ifconfig wwan0 mtu 16385
run qmi proxy programm,
# quectel-CM/quectel-qmi-proxy -d /dev/cdc-wdm0
or libqmi's qmi-proxy, if use libqmi's qmi-proxy, you can use qmicli to setup data call.
# /usr/libexec/qmi-proxy --verbose --no-exit
use quectel-CM to setup data call, if use libqmi's qmi-proxy, use '-p qmi-proxy' instead of '-p quectel-qmi-proxy'
# quectel-CM -p quectel-qmi-proxy -n 4 -s cmnet4
# quectel-CM -p quectel-qmi-proxy -n 1 -s cmnet
for how to use libqmi to setup data call, please refer to https://knowledge.quectel.com/display/SWSYSTLinuxAndroid/libqmi_How+to+using+QMAP+multiplexing

View File

@ -1,68 +0,0 @@
root@OpenWrt:~# quectel-CM -s cmnet -4 -6
[04-14_06:56:51:778] Quectel_QConnectManager_Linux_V1.6.0.25
[04-14_06:56:51:779] network interface '' or qmidev '' is not exist
[04-14_06:56:51:780] netcard driver = pcie_mhi, driver version = V1.3.0.17
[04-14_06:56:51:781] qmap_mode = 4, qmap_version = 9, qmap_size = 16384, muxid = 0x81, qmap_netcard = rmnet_mhi0.1
[04-14_06:56:51:782] Modem works in QMI mode
[04-14_06:56:51:783] connect to quectel-qmi-proxy0 sockfd = 7
[04-14_06:56:51:783] cdc_wdm_fd = 7
[04-14_06:56:51:789] Get clientWDS = 15
[04-14_06:56:51:792] Get clientWDS = 16
[04-14_06:56:51:794] Get clientDMS = 3
[04-14_06:56:51:798] Get clientNAS = 4
[04-14_06:56:51:801] Get clientUIM = 1
[04-14_06:56:51:805] Get clientWDA = 1
[04-14_06:56:51:809] requestBaseBandVersion RM500QGLABR10A03M4G
[04-14_06:56:51:813] qmap_settings.rx_urb_size = 16384
[04-14_06:56:51:813] qmap_settings.ul_data_aggregation_max_datagrams = 11
[04-14_06:56:51:814] qmap_settings.ul_data_aggregation_max_size = 8192
[04-14_06:56:51:814] qmap_settings.dl_minimum_padding = 0
[04-14_06:56:51:835] requestGetSIMStatus SIMStatus: SIM_READY
[04-14_06:56:51:836] requestSetProfile[1] cmnet///0
[04-14_06:56:51:848] requestGetProfile[1] cmnet///0
[04-14_06:56:51:852] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: 5G_NSA
[04-14_06:56:51:857] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED
[04-14_06:56:51:860] requestQueryDataCall IPv6ConnectionStatus: DISCONNECTED
[04-14_06:56:51:861] ifconfig rmnet_mhi0 down
[04-14_06:56:51:885] ifconfig rmnet_mhi0.1 0.0.0.0
ifconfig: SIOCSIFFLAGS: Network is down
[04-14_06:56:51:909] ifconfig rmnet_mhi0.1 down
[04-14_06:56:51:943] requestSetupDataCall WdsConnectionIPv4Handle: 0x341450a0
[04-14_06:56:52:423] requestSetupDataCall WdsConnectionIPv6Handle: 0x341439f0
[ 1001.561353] net rmnet_mhi0: link_state 0x0 -> 0x1
[04-14_06:56:52:441] ifconfig rmnet_mhi0 up
[ 1001.584623] [I][mhi_netdev_open] Opened net dev interface
[04-14_06:56:52:467] ifconfig rmnet_mhi0.1 up
[04-14_06:56:52:495] you are use OpenWrt?
[04-14_06:56:52:496] should not calling udhcpc manually?
[04-14_06:56:52:496] should modify /etc/config/network as below?
[04-14_06:56:52:497] config interface wan
[04-14_06:56:52:497] option ifname rmnet_mhi0.1
[04-14_06:56:52:497] option proto dhcp
[04-14_06:56:52:498] should use "/sbin/ifstaus wan" to check rmnet_mhi0.1 's status?
[04-14_06:56:52:498] busybox udhcpc -f -n -q -t 5 -i rmnet_mhi0.1
udhcpc: started, v1.28.3
udhcpc: sending discover
udhcpc: sending select for 10.245.22.3
udhcpc: lease of 10.245.22.3 obtained, lease time 7200
[04-14_06:56:52:713] udhcpc: ifconfig rmnet_mhi0.1 10.245.22.3 netmask 255.255.255.248 broadcast +
[04-14_06:56:52:754] udhcpc: setting default routers: 10.245.22.4
[04-14_06:56:52:838] ip -6 address flush dev rmnet_mhi0.1
[04-14_06:56:52:861] ip -6 address add 2409:8930:463:3daa:7c8e:429a:c902:c6cc/64 dev rmnet_mhi0.1
[04-14_06:56:52:884] ip -6 route add default dev rmnet_mhi0.1
root@OpenWrt:~# cat /etc/resolv.conf
nameserver 2409:8030:2000:0:0:0:0:1 # IPV6 rmnet_mhi0.1
nameserver 2409:8030:2000:0:0:0:0:2 # IPV6 rmnet_mhi0.1
search lan
nameserver 127.0.0.1
root@OpenWrt:~# ip -6 ro show
2409:8930:463:96df::/64 dev rmnet_mhi0.1 proto kernel metric 256
fe80::/64 dev br-lan proto kernel metric 256
fe80::/64 dev br0 proto kernel metric 256
default dev rmnet_mhi0.1 metric 1024
root@OpenWrt:~# ping6 www.qq.com
PING www.qq.com (2402:4e00:1430:1301::9227:79cc:76f2): 56 data bytes
64 bytes from 2402:4e00:1430:1301::9227:79cc:76f2: seq=0 ttl=51 time=97.230 ms

View File

@ -1,58 +0,0 @@
root@ZhuoTK:/# quectel-CM -n 1 -m 4 -s cmnet &
[04-13_05:12:07:455] Quectel_QConnectManager_Linux_V1.6.0.25
[04-13_05:12:07:458] Find /sys/bus/usb/devices/1-1.3 idVendor=0x2c7c idProduct=0x125, bus=0x001, dev=0x003
[04-13_05:12:07:459] Auto find qmichannel = /dev/qcqmi0
[04-13_05:12:07:459] Auto find usbnet_adapter = usb0
[04-13_05:12:07:467] netcard driver = GobiNet, driver version = V1.6.2.13
[04-13_05:12:07:467] qmap_mode = 4, qmap_version = 5, qmap_size = 4096, muxid = 0x84, qmap_netcard = usb0.4
[04-13_05:12:07:467] Modem works in QMI mode
[04-13_05:12:07:495] Get clientWDS = 7
[04-13_05:12:07:529] Get clientDMS = 8
[04-13_05:12:07:561] Get clientNAS = 9
[04-13_05:12:07:591] Get clientUIM = 10
[04-13_05:12:07:623] requestBaseBandVersion EC25EFAR06A11M4G
[04-13_05:12:07:752] requestGetSIMStatus SIMStatus: SIM_READY
[04-13_05:12:07:752] requestSetProfile[1] cmnet///0
[04-13_05:12:07:817] requestGetProfile[1] cmnet///0
[04-13_05:12:07:849] requestRegistrationState2 MCC: 460, MNC: 0, PS: Attached, DataCap: LTE
[04-13_05:12:07:881] requestQueryDataCall IPv4ConnectionStatus: DISCONNECTED
[04-13_05:12:07:881] ifconfig usb0 down
[04-13_05:12:07:892] ifconfig usb0.4 0.0.0.0
[04-13_05:12:07:903] ifconfig usb0.4 down
[04-13_05:12:07:944] requestSetupDataCall WdsConnectionIPv4Handle: 0x87265c40
[ 52.020000] net usb0: link_state 0x0 -> 0x8
[04-13_05:12:08:077] ifconfig usb0 up
[04-13_05:12:08:096] ifconfig usb0.4 up
[04-13_05:12:08:116] you are use OpenWrt?
[04-13_05:12:08:116] should not calling udhcpc manually?
[04-13_05:12:08:116] should modify /etc/config/network as below?
[04-13_05:12:08:116] config interface wan
[04-13_05:12:08:116] option ifname usb0.4
[04-13_05:12:08:116] option proto dhcp
[04-13_05:12:08:116] should use "/sbin/ifstaus wan" to check usb0.4 's status?
[04-13_05:12:08:117] busybox udhcpc -f -n -q -t 5 -i usb0.4
[04-13_05:12:08:134] udhcpc (v1.23.2) started
[04-13_05:12:08:193] Sending discover...
[04-13_05:12:08:197] Sending select for 10.84.241.180...
[04-13_05:12:08:203] Lease of 10.84.241.180 obtained, lease time 7200
[04-13_05:12:08:208] udhcpc: ifconfig usb0.4 10.84.241.180 netmask 255.255.255.248 broadcast +
[04-13_05:12:08:221] udhcpc: setting default routers: 10.84.241.181
root@ZhuoTK:/# ifconfig usb0.4
usb0.4 Link encap:Ethernet HWaddr 02:50:F4:00:00:00
inet addr:10.84.241.180 Mask:255.255.255.248
inet6 addr: fe80::50:f4ff:fe00:0/64 Scope:Link
UP RUNNING NOARP MTU:1500 Metric:1
RX packets:2 errors:0 dropped:0 overruns:0 frame:0
TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:612 (612.0 B) TX bytes:984 (984.0 B)
root@ZhuoTK:/# ip ro show
default via 10.84.241.181 dev usb0.4
10.84.241.176/29 dev usb0.4 proto kernel scope link src 10.84.241.180
192.168.1.0/24 dev br-lan proto kernel scope link src 192.168.1.251
root@ZhuoTK:/# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=52 time=99.431 ms

View File

@ -1,956 +0,0 @@
/******************************************************************************
@file main.c
@brief The entry program.
DESCRIPTION
Connectivity Management Tool for USB network adapter of Quectel wireless cellular modules.
INITIALIZATION AND SEQUENCING REQUIREMENTS
None.
---------------------------------------------------------------------------
Copyright (c) 2016 -2023 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
Quectel Wireless Solution Proprietary and Confidential.
---------------------------------------------------------------------------
******************************************************************************/
#include "QMIThread.h"
#include <sys/wait.h>
#include <sys/utsname.h>
#include <sys/time.h>
#include <dirent.h>
#include "util.h"
//#define CONFIG_PID_FILE_FORMAT "/var/run/quectel-CM-%s.pid" //for example /var/run/quectel-CM-wwan0.pid
static PROFILE_T s_profile;
int debug_qmi = 0;
int qmidevice_control_fd[2];
static int signal_control_fd[2];
int g_donot_exit_when_modem_hangup = 0;
extern int ql_ifconfig(int argc, char *argv[]);
extern int ql_get_netcard_driver_info(const char*);
extern int ql_capture_usbmon_log(PROFILE_T *profile, const char *log_path);
extern void ql_stop_usbmon_log(PROFILE_T *profile);
//UINT ifc_get_addr(const char *ifname);
static int s_link = -1;
static void usbnet_link_change(int link, PROFILE_T *profile) {
if (s_link == link)
return;
s_link = link;
if (!(link & (1<<IpFamilyV4)))
memset(&profile->ipv4, 0, sizeof(IPV4_T));
if (!(link & (1<<IpFamilyV6)))
memset(&profile->ipv6, 0, sizeof(IPV6_T));
if (link) {
udhcpc_start(profile);
} else {
udhcpc_stop(profile);
}
}
static int check_ipv4_address(PROFILE_T *profile) {
uint32_t oldAddress = profile->ipv4.Address;
if (profile->request_ops == &mbim_request_ops)
return 1; //we will get a new ipv6 address per requestGetIPAddress()
if (profile->request_ops == &atc_request_ops) {
if (!profile->udhcpc_ip) return 1;
oldAddress = profile->udhcpc_ip;
}
if (profile->request_ops->requestGetIPAddress(profile, IpFamilyV4) == 0) {
if (profile->ipv4.Address != oldAddress || debug_qmi) {
unsigned char *l = (unsigned char *)&oldAddress;
unsigned char *r = (unsigned char *)&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 (profile->ipv4.Address == oldAddress);
}
return 0;
}
static void main_send_event_to_qmidevice(int triger_event) {
if (write(qmidevice_control_fd[0], &triger_event, sizeof(triger_event)) == -1) {};
}
static void send_signo_to_main(int signo) {
if (write(signal_control_fd[0], &signo, sizeof(signo)) == -1) {};
}
void qmidevice_send_event_to_main(int triger_event) {
if (write(qmidevice_control_fd[1], &triger_event, sizeof(triger_event)) == -1) {};
}
void qmidevice_send_event_to_main_ext(int triger_event, void *data, unsigned len) {
if (write(qmidevice_control_fd[1], &triger_event, sizeof(triger_event)) == -1) {};
if (write(qmidevice_control_fd[1], data, len) == -1) {};
}
#define MAX_PATH 256
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*2+6];
char filename[MAX_PATH];
int linksize;
snprintf(linkname, sizeof(linkname), "%.256s/%s", dir, file);
linksize = readlink(linkname, filename, sizeof(filename));
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*2+6];
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, sizeof(linkname), "%s/%s/exe", dir, file);
linksize = readlink(linkname, filename, sizeof(filename));
if (linksize <= 0)
return 0;
filename[linksize] = 0;
pid = atoi(file);
if (pid >= getpid())
return 0;
snprintf(linkname, sizeof(linkname), "%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, sizeof(myself));
if (filenamesize <= 0)
return 0;
myself[filenamesize] = 0;
if (ls_dir("/proc", is_brother_process, argv))
sleep(1);
return 0;
}
static int kill_data_call_pdp(int pdp, char *self) {
int pid;
char *p = NULL;
p = self;
while (*self) {
if (*self == '/')
p = self+1;
self++;
}
pid = getpid_by_pdp(pdp, p);
if (pid > 0) {
dbg_time("send SIGINT to process %d", pid);
return kill(pid, SIGINT);
}
return -1;
}
static void ql_sigaction(int signo) {
if (SIGALRM == signo)
send_signo_to_main(SIG_EVENT_START);
else
{
g_donot_exit_when_modem_hangup = 0;
send_signo_to_main(SIG_EVENT_STOP);
main_send_event_to_qmidevice(SIG_EVENT_STOP); //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. auth: 1~pap, 2~chap, 3~MsChapV2");
dbg_time("-p pincode Verify sim card pin if sim card is locked");
dbg_time("-p [quectel-][qmi|mbim]-proxy Request to use proxy");
dbg_time("-f logfilename Save log message of this program to file");
dbg_time("-u usbmonlog filename Save usbmon log to file");
dbg_time("-i interface Specify which network interface to setup data call when multi-modems exits");
dbg_time("-4 Setup IPv4 data call (default)");
dbg_time("-6 Setup IPv6 data call");
dbg_time("-n pdn Specify which pdn to setup data call (default 1 for QMI, 0 for MBIM)");
dbg_time("-k pdn Specify which pdn to hangup data call (by send SIGINT to 'quectel-CM -n pdn')");
dbg_time("-m iface-idx Bind QMI data call to wwan0_<iface idx> when QMAP used. E.g '-n 7 -m 1' bind pdn-7 data call to wwan0_1");
dbg_time("-b Enable network interface bridge function (default 0)");
dbg_time("-v Verbose log mode, for debug purpose.");
dbg_time("-d Obtain the IP address and dns through qmi");
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 1 -p 1234 -f gobinet_log.txt", progname);
return 0;
}
static int qmi_main(PROFILE_T *profile)
{
int triger_event = 0;
int signo;
#ifdef CONFIG_SIM
SIM_Status SIMStatus = SIM_ABSENT;
#endif
UCHAR PSAttachedState = 0;
UCHAR IPv4ConnectionStatus = QWDS_PKT_DATA_UNKNOW;
UCHAR IPv6ConnectionStatus = QWDS_PKT_DATA_UNKNOW;
unsigned SetupCallFail = 0;
unsigned long SetupCallAllowTime = clock_msec();
#ifdef REBOOT_SIM_CARD_WHEN_LONG_TIME_NO_PS
unsigned PsAttachFail = 0;
unsigned long PsAttachTime = clock_msec();
#endif
int qmierr = 0;
const struct request_ops *request_ops = profile ->request_ops;
pthread_t gQmiThreadID = 0;
//sudo apt-get install udhcpc
//sudo apt-get remove ModemManager
if (profile->reattach_flag) {
if (!reattach_driver(profile))
sleep(2);
}
/* try to recreate FDs*/
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;
}
if ((profile->qmap_mode == 0 || profile->qmap_mode == 1)
&& (!profile->proxy[0] || strstr(profile->qmichannel, "_IPCR"))) {
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;
}
if (request_ops->requestBaseBandVersion)
request_ops->requestBaseBandVersion(profile);
if (request_ops->requestSetEthMode)
request_ops->requestSetEthMode(profile);
if (request_ops->requestSetLoopBackState && profile->loopback_state) {
qmierr = request_ops->requestSetLoopBackState(profile->loopback_state, profile->replication_factor);
if (qmierr != QMI_ERR_INVALID_QMI_CMD) //X20 return this error
profile->loopback_state = 0; //wait for RIL_UNSOL_LOOPBACK_CONFIG_IND
}
if (request_ops->requestGetSIMStatus) {
qmierr = request_ops->requestGetSIMStatus(&SIMStatus);
while (qmierr == QMI_ERR_OP_DEVICE_UNSUPPORTED) {
sleep(1);
qmierr = request_ops->requestGetSIMStatus(&SIMStatus);
}
if ((SIMStatus == SIM_PIN) && profile->pincode && request_ops->requestEnterSimPin) {
request_ops->requestEnterSimPin(profile->pincode);
}
}
if (SIMStatus == SIM_READY) {
if (request_ops->requestGetICCID)
request_ops->requestGetICCID();
if (request_ops->requestGetIMSI)
request_ops->requestGetIMSI();
}
if (request_ops->requestGetProfile)
request_ops->requestGetProfile(profile);
if (request_ops->requestSetProfile && (profile->apn || profile->user || profile->password)) {
if (request_ops->requestSetProfile(profile) == 1) {
#ifdef REBOOT_SIM_CARD_WHEN_APN_CHANGE //enable at only when customer asked
if (request_ops->requestRadioPower) {
request_ops->requestRadioPower(0);
request_ops->requestRadioPower(1);
}
#endif
}
}
request_ops->requestRegistrationState(&PSAttachedState);
#ifdef CONFIG_ENABLE_QOS
request_ops->requestRegisterQos(profile);
#endif
#if 1 //USB disconnnect and re-connect, but not reboot modem, will get this bug
if (profile->enable_ipv4
&& profile->request_ops == &atc_request_ops
&& !request_ops->requestQueryDataCall(&IPv4ConnectionStatus, IpFamilyV4)
&& IPv4ConnectionStatus == QWDS_PKT_DATA_CONNECTED) {
request_ops->requestDeactivateDefaultPDP(profile, IpFamilyV4);
}
#endif
send_signo_to_main(SIG_EVENT_CHECK);
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(SIG_EVENT_CHECK);
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;
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);
switch (signo)
{
case SIG_EVENT_START:
if (PSAttachedState != 1 && profile->loopback_state == 0)
break;
if (SetupCallAllowTime > clock_msec()) {
alarm((SetupCallAllowTime - clock_msec()+999)/1000);
break;
}
if (profile->enable_ipv4 && IPv4ConnectionStatus != QWDS_PKT_DATA_CONNECTED) {
qmierr = request_ops->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 = request_ops->requestSetupDataCall(profile, IpFamilyV4);
if (qmierr)
profile->auth = old_auto; //still fail, restore old auth moe
}
if (!qmierr) {
qmierr = request_ops->requestGetIPAddress(profile, IpFamilyV4);
if (!qmierr)
IPv4ConnectionStatus = QWDS_PKT_DATA_CONNECTED;
}
}
if (profile->enable_ipv6 && IPv6ConnectionStatus != QWDS_PKT_DATA_CONNECTED) {
if (profile->enable_ipv4 && profile->request_ops != &qmi_request_ops) {
IPv6ConnectionStatus = IPv4ConnectionStatus;
}
else {
qmierr = request_ops->requestSetupDataCall(profile, IpFamilyV6);
if (!qmierr) {
qmierr = request_ops->requestGetIPAddress(profile, IpFamilyV6);
if (!qmierr)
IPv6ConnectionStatus = QWDS_PKT_DATA_CONNECTED;
}
}
}
if ((profile->enable_ipv4 && IPv4ConnectionStatus == QWDS_PKT_DATA_DISCONNECTED)
|| (profile->enable_ipv6 && IPv6ConnectionStatus == QWDS_PKT_DATA_DISCONNECTED)) {
const unsigned allow_time[] = {5, 10, 20, 40, 60};
if (SetupCallFail < (sizeof(allow_time)/sizeof(unsigned)))
SetupCallAllowTime = allow_time[SetupCallFail];
else
SetupCallAllowTime = 60;
SetupCallFail++;
dbg_time("try to requestSetupDataCall %ld second later", SetupCallAllowTime);
alarm(SetupCallAllowTime);
SetupCallAllowTime = SetupCallAllowTime*1000 + clock_msec();
}
else if (IPv4ConnectionStatus == QWDS_PKT_DATA_CONNECTED || IPv6ConnectionStatus == QWDS_PKT_DATA_CONNECTED) {
SetupCallFail = 0;
SetupCallAllowTime = clock_msec();
}
break;
case SIG_EVENT_CHECK:
if (request_ops->requestGetSignalInfo)
request_ops->requestGetSignalInfo();
if (request_ops->requestGetCellInfoList)
request_ops->requestGetCellInfoList();
if (request_ops->requestGetCoexWWANState)
request_ops->requestGetCoexWWANState();
if (PSAttachedState != 1)
request_ops->requestRegistrationState(&PSAttachedState);
#ifdef REBOOT_SIM_CARD_WHEN_LONG_TIME_NO_PS
if (PSAttachedState) {
PsAttachTime = clock_msec();
PsAttachFail = 0;
}
else {
unsigned long diff = (clock_msec() - PsAttachTime) / 1000;
unsigned long threshold = REBOOT_SIM_CARD_WHEN_LONG_TIME_NO_PS << PsAttachFail;
if (diff > threshold || diff > 960) {
//interval time is 60 -> 120 - > 240 - > 480 -> 960
PsAttachTime = clock_msec();
PsAttachFail++;
if (request_ops->requestRadioPower) {
request_ops->requestRadioPower(0);
request_ops->requestRadioPower(1);
}
}
}
#endif
if (profile->enable_ipv4 && IPv4ConnectionStatus != QWDS_PKT_DATA_DISCONNECTED
&& !request_ops->requestQueryDataCall(&IPv4ConnectionStatus, IpFamilyV4))
{
if (QWDS_PKT_DATA_CONNECTED == IPv4ConnectionStatus && profile->ipv4.Address == 0) {
//killall -9 quectel-CM for MBIM and ATC call
qmierr = request_ops->requestGetIPAddress(profile, IpFamilyV4);
if (qmierr)
IPv4ConnectionStatus = QWDS_PKT_DATA_DISCONNECTED;
}
//local ip is different with remote ip
if (QWDS_PKT_DATA_CONNECTED == IPv4ConnectionStatus && check_ipv4_address(profile) == 0) {
request_ops->requestDeactivateDefaultPDP(profile, IpFamilyV4);
IPv4ConnectionStatus = QWDS_PKT_DATA_DISCONNECTED;
}
}
else {
IPv4ConnectionStatus = QWDS_PKT_DATA_DISCONNECTED;
}
if (profile->enable_ipv6 && IPv6ConnectionStatus != QWDS_PKT_DATA_DISCONNECTED) {
if (profile->enable_ipv4 && profile->request_ops != &qmi_request_ops) {
IPv6ConnectionStatus = IPv4ConnectionStatus;
}
else {
request_ops->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);
}
else if (IPv4ConnectionStatus == QWDS_PKT_DATA_CONNECTED || IPv6ConnectionStatus == QWDS_PKT_DATA_CONNECTED) {
int link = 0;
if (IPv4ConnectionStatus == QWDS_PKT_DATA_CONNECTED)
link |= (1<<IpFamilyV4);
if (IPv6ConnectionStatus == QWDS_PKT_DATA_CONNECTED)
link |= (1<<IpFamilyV6);
usbnet_link_change(link, profile);
}
if ((profile->enable_ipv4 && IPv4ConnectionStatus == QWDS_PKT_DATA_DISCONNECTED)
|| (profile->enable_ipv6 && IPv6ConnectionStatus == QWDS_PKT_DATA_DISCONNECTED)) {
send_signo_to_main(SIG_EVENT_START);
}
break;
case SIG_EVENT_STOP:
if (profile->enable_ipv4 && IPv4ConnectionStatus == QWDS_PKT_DATA_CONNECTED) {
request_ops->requestDeactivateDefaultPDP(profile, IpFamilyV4);
}
if (profile->enable_ipv6 && IPv6ConnectionStatus == QWDS_PKT_DATA_CONNECTED) {
if (profile->enable_ipv4 && profile->request_ops != &qmi_request_ops) {
}
else {
request_ops->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);
goto __main_quit;
break;
case RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED:
request_ops->requestRegistrationState(&PSAttachedState);
if (PSAttachedState == 1) {
if ((profile->enable_ipv4 && IPv4ConnectionStatus == QWDS_PKT_DATA_DISCONNECTED)
|| (profile->enable_ipv6 && IPv6ConnectionStatus == QWDS_PKT_DATA_DISCONNECTED)) {
send_signo_to_main(SIG_EVENT_START);
}
} else {
SetupCallAllowTime = clock_msec();
}
break;
case RIL_UNSOL_DATA_CALL_LIST_CHANGED:
if (IPv4ConnectionStatus == QWDS_PKT_DATA_CONNECTED || IPv6ConnectionStatus == QWDS_PKT_DATA_CONNECTED) {
SetupCallAllowTime = clock_msec() + 1000; //from connect -> disconnect, do not re-dail immediately, wait network stable
}
send_signo_to_main(SIG_EVENT_CHECK);
break;
case MODEM_REPORT_RESET_EVENT:
{
dbg_time("main recv MODEM RESET SIGNAL");
main_send_event_to_qmidevice(RIL_REQUEST_QUIT);
g_donot_exit_when_modem_hangup = 1;
goto __main_quit;
}
break;
case RIL_UNSOL_LOOPBACK_CONFIG_IND:
{
QMI_WDA_SET_LOOPBACK_CONFIG_IND_MSG SetLoopBackInd;
if (read(fd, &SetLoopBackInd, sizeof(SetLoopBackInd)) == sizeof(SetLoopBackInd)) {
profile->loopback_state = SetLoopBackInd.loopback_state.TLVVaule;
profile->replication_factor = le32_to_cpu(SetLoopBackInd.replication_factor.TLVVaule);
dbg_time("SetLoopBackInd: loopback_state=%d, replication_factor=%u",
profile->loopback_state, profile->replication_factor);
if (profile->loopback_state)
send_signo_to_main(SIG_EVENT_START);
}
}
break;
#ifdef CONFIG_REG_QOS_IND
case RIL_UNSOL_GLOBAL_QOS_FLOW_IND_QOS_ID:
{
UINT qos_id = 0;
if (read(fd, &qos_id, sizeof(qos_id)) == sizeof(qos_id)) {
profile->qos_id = qos_id;
}
}
break;
#endif
default:
break;
}
}
}
}
}
__main_quit:
usbnet_link_change(0, profile);
if (gQmiThreadID && 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__);
return 0;
}
static int quectel_CM(PROFILE_T *profile)
{
int ret = 0;
char qmichannel[32] = {'\0'};
char usbnet_adapter[32] = {'\0'};
if (profile->expect_adapter[0])
strncpy(usbnet_adapter, profile->expect_adapter, sizeof(usbnet_adapter));
if (qmidevice_detect(qmichannel, usbnet_adapter, sizeof(qmichannel), profile)) {
profile->hardware_interface = HARDWARE_USB;
}
else if (mhidevice_detect(qmichannel, usbnet_adapter, profile)) {
profile->hardware_interface = HARDWARE_PCIE;
}
else if (atdevice_detect(qmichannel, usbnet_adapter, profile)) {
profile->hardware_interface = HARDWARE_PCIE;
}
#ifdef CONFIG_QRTR
else if (1) {
strcpy(qmichannel, "qrtr");
strcpy(usbnet_adapter, "rmnet_mhi0");
profile->hardware_interface = HARDWARE_PCIE;
profile->software_interface = SOFTWARE_QRTR;
}
#endif
else {
dbg_time("qmidevice_detect failed");
goto error;
}
strncpy(profile->qmichannel, qmichannel, sizeof(profile->qmichannel));
strncpy(profile->usbnet_adapter, usbnet_adapter, sizeof(profile->usbnet_adapter));
ql_get_netcard_driver_info(profile->usbnet_adapter);
if ((profile->hardware_interface == HARDWARE_USB) && profile->usblogfile)
ql_capture_usbmon_log(profile, profile->usblogfile);
if (profile->hardware_interface == HARDWARE_USB) {
profile->software_interface = get_driver_type(profile);
}
ql_qmap_mode_detect(profile);
if (profile->software_interface == SOFTWARE_MBIM) {
dbg_time("Modem works in MBIM mode");
profile->request_ops = &mbim_request_ops;
profile->qmi_ops = &mbim_dev_ops;
if (!profile->apn || !profile->apn[0]) {
//see FAE-51804 FAE-59811
dbg_time("When MBIM mode, must specify APN with '-s', or setup data call may fail!");
exit(-404); //if no such issue on your side, please comment this
}
ret = qmi_main(profile);
}
else if (profile->software_interface == SOFTWARE_QMI) {
dbg_time("Modem works in QMI mode");
profile->request_ops = &qmi_request_ops;
if (qmidev_is_gobinet(profile->qmichannel))
profile->qmi_ops = &gobi_qmidev_ops;
else
profile->qmi_ops = &qmiwwan_qmidev_ops;
qmidev_send = profile->qmi_ops->send;
ret = qmi_main(profile);
}
else if (profile->software_interface == SOFTWARE_ECM_RNDIS_NCM) {
dbg_time("Modem works in ECM_RNDIS_NCM mode");
profile->request_ops = &atc_request_ops;
profile->qmi_ops = &atc_dev_ops;
ret = qmi_main(profile);
}
#ifdef CONFIG_QRTR
else if (profile->software_interface == SOFTWARE_QRTR) {
dbg_time("Modem works in QRTR mode");
profile->request_ops = &qmi_request_ops;
profile->qmi_ops = &qrtr_qmidev_ops;
qmidev_send = profile->qmi_ops->send;
ret = qmi_main(profile);
}
#endif
else {
dbg_time("unsupport software_interface %d", profile->software_interface);
}
ql_stop_usbmon_log(profile);
error:
return ret;
}
static int parse_user_input(int argc, char **argv, PROFILE_T *profile) {
int opt = 1;
profile->pdp = CONFIG_DEFAULT_PDP;
profile->profile_index = CONFIG_DEFAULT_PDP;
if (!strcmp(argv[argc-1], "&"))
argc--;
#define has_more_argv() ((opt < argc) && (argv[opt][0] != '-'))
while (opt < argc) {
if (argv[opt][0] != '-') {
return usage(argv[0]);
}
switch (argv[opt++][1])
{
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()) {
const char *auth = argv[opt++];
if (!strcmp(auth, "0") || !strcasecmp(auth, "none")) {
profile->auth = 0;
}
else if (!strcmp(auth, "1") || !strcasecmp(auth, "pap")) {
profile->auth = 1;
}
else if (!strcmp(auth, "2") || !strcasecmp(auth, "chap")) {
profile->auth = 2;
}
else if (!strcmp(auth, "3") || !strcasecmp(auth, "MsChapV2")) {
profile->auth = 3;
}
else {
dbg_time("unknow auth '%s'", auth);
return usage(argv[0]);
}
}
break;
case 'p':
if (has_more_argv()) {
const char *arg = argv[opt++];
if (!strcmp(arg, QUECTEL_QMI_PROXY) || !strcmp(arg, QUECTEL_MBIM_PROXY)
|| !strcmp(arg, LIBQMI_PROXY) || !strcmp(arg, LIBMBIM_PROXY) || !strcmp(arg, QUECTEL_ATC_PROXY)) {
strncpy(profile->proxy, arg, sizeof(profile->proxy) - 1);
}
else if ((999 < atoi(arg)) && (atoi(arg) < 10000)) {
profile->pincode = arg;
}
else {
dbg_time("unknow -p '%s'", arg);
return usage(argv[0]);
}
}
break;
case 'm':
if (has_more_argv())
profile->muxid = argv[opt++][0] - '0' + 0x80;
break;
case 'n':
if (has_more_argv())
profile->pdp = argv[opt++][0] - '0';
break;
case 'f':
if (has_more_argv()) {
profile->logfile = argv[opt++];
}
break;
case 'i':
if (has_more_argv()) {
strncpy(profile->expect_adapter, argv[opt++], sizeof(profile->expect_adapter) - 1);
}
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;
}
}
break;
case '4':
profile->enable_ipv4 = 1;
break;
case '6':
profile->enable_ipv6 = 1;
break;
case 'd':
profile->no_dhcp = 1;
break;
case 'u':
if (has_more_argv()) {
profile->usblogfile = argv[opt++];
}
break;
case 'b':
profile->enable_bridge = 1;
break;
case 'k':
if (has_more_argv()) {
profile->kill_pdp = argv[opt++][0] - '0';
}
break;
default:
return usage(argv[0]);
break;
}
}
if (profile->enable_ipv4 != 1 && profile->enable_ipv6 != 1) { // default enable IPv4
profile->enable_ipv4 = 1;
}
return 1;
}
int main(int argc, char *argv[])
{
int ret;
PROFILE_T *ctx = &s_profile;
dbg_time("QConnectManager_Linux_V1.6.5");
ret = parse_user_input(argc, argv, ctx);
if (!ret)
return ret;
if (ctx->kill_pdp) {
return kill_data_call_pdp(ctx->kill_pdp, argv[0]);
}
if (ctx->logfile) {
logfilefp = fopen(ctx->logfile, "a+");
if (!logfilefp) {
dbg_time("Fail to open %s, errno: %d(%s)", ctx->logfile, errno, strerror(errno));
}
}
signal(SIGINT, ql_sigaction);
signal(SIGTERM, ql_sigaction);
signal(SIGALRM, ql_sigaction);
do {
ret = quectel_CM(ctx);
if (g_donot_exit_when_modem_hangup > 0)
sleep(3);
} while (g_donot_exit_when_modem_hangup > 0);
if (logfilefp) {
fclose(logfilefp);
}
return ret;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,52 +0,0 @@
#ifndef __QUECTEL_ENDIAN_H__
#define __QUECTEL_ENDIAN_H__
#include <endian.h>
#ifndef htole32
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define htole16(x) (uint16_t)(x)
#define le16toh(x) (uint16_t)(x)
#define letoh16(x) (uint16_t)(x)
#define htole32(x) (uint32_t)(x)
#define le32toh(x) (uint32_t)(x)
#define letoh32(x) (uint32_t)(x)
#define htole64(x) (uint64_t)(x)
#define le64toh(x) (uint64_t)(x)
#define letoh64(x) (uint64_t)(x)
#else
static __inline uint16_t __bswap16(uint16_t __x) {
return (__x<<8) | (__x>>8);
}
static __inline uint32_t __bswap32(uint32_t __x) {
return (__x>>24) | (__x>>8&0xff00) | (__x<<8&0xff0000) | (__x<<24);
}
static __inline uint64_t __bswap64(uint64_t __x) {
return (__bswap32(__x)+0ULL<<32) | (__bswap32(__x>>32));
}
#define htole16(x) __bswap16(x)
#define le16toh(x) __bswap16(x)
#define letoh16(x) __bswap16(x)
#define htole32(x) __bswap32(x)
#define le32toh(x) __bswap32(x)
#define letoh32(x) __bswap32(x)
#define htole64(x) __bswap64(x)
#define le64toh(x) __bswap64(x)
#define letoh64(x) __bswap64(x)
#endif
#endif
#define le16_to_cpu(x) le16toh((uint16_t)(x))
#define le32_to_cpu(x) le32toh((uint32_t)(x))
#define le64_to_cpu(x) le64toh((uint64_t)(x))
#define cpu_to_le16(x) htole16((uint16_t)(x))
#define cpu_to_le32(x) htole32((uint32_t)(x))
#define cpu_to_le64(x) htole64((uint64_t)(x))
static __inline uint32_t ql_swap32(uint32_t __x) {
return (__x>>24) | (__x>>8&0xff00) | (__x<<8&0xff0000) | (__x<<24);
}
#endif //__QUECTEL_ENDIAN_H__

View File

@ -1,38 +0,0 @@
#ifndef __QUECTEL_LIST_H__
#define __QUECTEL_LIST_H__
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)
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;
}
#endif

View File

@ -1,402 +0,0 @@
/******************************************************************************
@file qmap_bridge_mode.c
@brief Connectivity bridge manager.
DESCRIPTION
Connectivity Management Tool for USB network adapter of Quectel wireless cellular modules.
INITIALIZATION AND SEQUENCING REQUIREMENTS
None.
---------------------------------------------------------------------------
Copyright (c) 2016 - 2023 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
Quectel Wireless Solution Proprietary and Confidential.
---------------------------------------------------------------------------
******************************************************************************/
#include "QMIThread.h"
static size_t ql_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=%zu, buf_size=%zu: (%s)", filename, n, size, strerror(errno));
}
fclose(fp);
}
return n > 0 ? n : 0;
}
static size_t ql_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=%zu, buf_size=%zu: (%s)", filename, n, size, strerror(errno));
}
fclose(fp);
}
return n > 0 ? n : 0;
}
int ql_bridge_mode_detect(PROFILE_T *profile) {
const char *ifname = profile->qmapnet_adapter[0] ? 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 = 0;
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_ipv4, R_OK)) {
if (errno != ENOENT) {
dbg_time("fail to access %s, errno: %d (%s)", bridge_mode, errno, strerror(errno));
return 0;
}
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, R_OK)) {
if (errno != ENOENT) {
dbg_time("fail to access %s, errno: %d (%s)", bridge_mode, errno, strerror(errno));
}
return 0;
}
}
n = ql_fread(bridge_mode, buf, sizeof(buf));
if (n > 0) {
in_bridge = (buf[0] != '0');
}
if (!in_bridge)
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);
ql_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);
ql_fwrite(bridge_ipv4, ipv4, strlen(ipv4));
}
return in_bridge;
}
int ql_enable_qmi_wwan_rawip_mode(PROFILE_T *profile) {
char filename[256];
char buf[4];
size_t n;
FILE *fp;
if (!qmidev_is_qmiwwan(profile->qmichannel))
return 0;
snprintf(filename, sizeof(filename), "/sys/class/net/%s/qmi/rawip", profile->usbnet_adapter);
n = ql_fread(filename, buf, sizeof(buf));
if (n == 0)
return 0;
if (buf[0] == '1' || buf[0] == 'Y')
return 0;
fp = fopen(filename , "w");
if (fp == NULL) {
dbg_time("Fail to fopen(%s, \"w\"), errno: %d (%s)", filename, errno, strerror(errno));
return 1;
}
buf[0] = 'Y';
n = fwrite(buf, 1, 1, fp);
if (n != 1) {
dbg_time("Fail to fwrite(%s), errno: %d (%s)", filename, errno, strerror(errno));
fclose(fp);
return 1;
}
fclose(fp);
return 0;
}
int ql_driver_type_detect(PROFILE_T *profile) {
if (qmidev_is_gobinet(profile->qmichannel)) {
profile->qmi_ops = &gobi_qmidev_ops;
}
else {
profile->qmi_ops = &qmiwwan_qmidev_ops;
}
qmidev_send = profile->qmi_ops->send;
return 0;
}
void ql_set_driver_bridge_mode(PROFILE_T *profile) {
char enable[16];
char filename[256];
if(profile->qmap_mode)
snprintf(filename, sizeof(filename), "/sys/class/net/%s/bridge_mode", profile->qmapnet_adapter);
else
snprintf(filename, sizeof(filename), "/sys/class/net/%s/bridge_mode", profile->usbnet_adapter);
snprintf(enable, sizeof(enable), "%02d\n", profile->enable_bridge);
ql_fwrite(filename, enable, sizeof(enable));
}
static int ql_qmi_qmap_mode_detect(PROFILE_T *profile) {
char buf[128];
int n;
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--;
strncpy(profile->driver_name, &pl->filename[n+1], sizeof(profile->driver_name) - 1);
ql_get_driver_rmnet_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->muxid == 0)? profile->pdp - 1 : profile->muxid - 0x81;
if (profile->qmap_mode == 1)
offset_id = 0;
profile->muxid = profile->rmnet_info.mux_id[offset_id];
strncpy(profile->qmapnet_adapter, profile->rmnet_info.ifname[offset_id], sizeof(profile->qmapnet_adapter) - 1);
profile->qmap_size = profile->rmnet_info.rx_urb_size;
profile->qmap_version = profile->rmnet_info.qmap_version;
}
goto _out;
}
snprintf(pl->filename, sizeof(pl->filename), "/sys/class/net/%s/qmap_mode", 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_mode", 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_mode", 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)) {
n = ql_fread(pl->filename, buf, sizeof(buf));
if (n > 0) {
profile->qmap_mode = atoi(buf);
if (profile->qmap_mode > 1) {
if(!profile->muxid)
profile->muxid = profile->pdp + 0x80; //muxis is 0x8X for PDN-X
snprintf(profile->qmapnet_adapter, sizeof(profile->qmapnet_adapter),
"%.16s.%d", profile->usbnet_adapter, profile->muxid - 0x80);
} if (profile->qmap_mode == 1) {
profile->muxid = 0x81;
strncpy(profile->qmapnet_adapter, profile->usbnet_adapter, sizeof(profile->qmapnet_adapter));
}
}
}
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 = ql_fread(pl->filename, buf, sizeof(buf));
if (n >= 5) {
dbg_time("If use QMAP by /sys/class/net/%s/qmi/add_mux", profile->usbnet_adapter);
#if 1
dbg_time("Please set mtu of wwan0 >= max dl qmap packet size");
#else
dbg_time("File:%s Line:%d Please make sure add next patch to qmi_wwan.c", __func__, __LINE__);
/*
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 74bebbd..db8a777 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -379,6 +379,24 @@ static ssize_t add_mux_store(struct device *d, struct device_attribute *attr, c
if (!ret) {
info->flags |= QMI_WWAN_FLAG_MUX;
ret = len;
+#if 1 //Add by Quectel
+ if (le16_to_cpu(dev->udev->descriptor.idVendor) == 0x2c7c) {
+ int idProduct = le16_to_cpu(dev->udev->descriptor.idProduct);
+
+ if (idProduct == 0x0121 || idProduct == 0x0125 || idProduct == 0x0435) //MDM9x07
+ dev->rx_urb_size = 4*1024;
+ else if (idProduct == 0x0306) //MDM9x40
+ dev->rx_urb_size = 16*1024;
+ else if (idProduct == 0x0512) //SDX20
+ dev->rx_urb_size = 32*1024;
+ else if (idProduct == 0x0620) //SDX24
+ dev->rx_urb_size = 32*1024;
+ else if (idProduct == 0x0800) //SDX55
+ dev->rx_urb_size = 32*1024;
+ else
+ dev->rx_urb_size = 32*1024;
+ }
+#endif
}
err:
rtnl_unlock();
*/
#endif
profile->qmap_mode = n/5; //0x11\n0x22\n0x33\n
if (profile->qmap_mode > 1) {
//PDN-X map to qmimux-X
if(!profile->muxid) {
profile->muxid = (buf[5*(profile->pdp - 1) + 2] - '0')*16 + (buf[5*(profile->pdp - 1) + 3] - '0');
snprintf(profile->qmapnet_adapter, sizeof(profile->qmapnet_adapter), "qmimux%d", profile->pdp - 1);
} else {
profile->muxid = (buf[5*(profile->muxid - 0x81) + 2] - '0')*16 + (buf[5*(profile->muxid - 0x81) + 3] - '0');
snprintf(profile->qmapnet_adapter, sizeof(profile->qmapnet_adapter), "qmimux%d", profile->muxid - 0x81);
}
} else if (profile->qmap_mode == 1) {
profile->muxid = (buf[5*0 + 2] - '0')*16 + (buf[5*0 + 3] - '0');
snprintf(profile->qmapnet_adapter, sizeof(profile->qmapnet_adapter),
"qmimux%d", 0);
}
}
}
_out:
if (profile->qmap_mode) {
if (profile->qmap_size == 0) {
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 = ql_fread(pl->filename, buf, sizeof(buf));
if (n > 0) {
profile->qmap_size = atoi(buf);
}
}
}
if (profile->qmap_version == 0) {
profile->qmap_version = WDA_DL_DATA_AGG_QMAP_ENABLED;
}
dbg_time("qmap_mode = %d, qmap_version = %d, qmap_size = %d, muxid = 0x%02x, qmap_netcard = %s",
profile->qmap_mode, profile->qmap_version, profile->qmap_size, profile->muxid, profile->qmapnet_adapter);
}
ql_set_driver_bridge_mode(profile);
free(pl);
return 0;
}
static int ql_mbim_usb_vlan_mode_detect(PROFILE_T *profile) {
char tmp[128];
snprintf(tmp, sizeof(tmp), "/sys/class/net/%s.%d", profile->usbnet_adapter, profile->pdp);
if (!access(tmp, F_OK)) {
profile->qmap_mode = 4;
profile->muxid = profile->pdp;
no_trunc_strncpy(profile->qmapnet_adapter, tmp + strlen("/sys/class/net/"), sizeof(profile->qmapnet_adapter) - 1);
dbg_time("mbim_qmap_mode = %d, vlan_id = 0x%02x, qmap_netcard = %s",
profile->qmap_mode, profile->muxid, profile->qmapnet_adapter);
}
return 0;
}
static int ql_mbim_mhi_qmap_mode_detect(PROFILE_T *profile) {
ql_get_driver_rmnet_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->pdp;
strcpy(profile->qmapnet_adapter, profile->rmnet_info.ifname[offset_id]);
profile->qmap_size = profile->rmnet_info.rx_urb_size;
profile->qmap_version = profile->rmnet_info.qmap_version;
dbg_time("mbim_qmap_mode = %d, vlan_id = 0x%02x, qmap_netcard = %s",
profile->qmap_mode, profile->muxid, profile->qmapnet_adapter);
}
goto _out;
}
_out:
return 0;
}
int ql_qmap_mode_detect(PROFILE_T *profile) {
if (profile->software_interface == SOFTWARE_MBIM) {
if (profile->hardware_interface == HARDWARE_USB)
return ql_mbim_usb_vlan_mode_detect(profile);
else if (profile->hardware_interface == HARDWARE_PCIE)
return ql_mbim_mhi_qmap_mode_detect(profile);
} else if (profile->software_interface == SOFTWARE_QMI) {
return ql_qmi_qmap_mode_detect(profile);
}
#ifdef CONFIG_QRTR
else if(profile->software_interface == SOFTWARE_QRTR) {
char tmp[128];
profile->qmap_mode = 4;
profile->qmap_version = WDA_DL_DATA_AGG_QMAP_V5_ENABLED;
profile->qmap_size = 31*1024;
profile->muxid = 0x80 | profile->pdp;
snprintf(profile->qmapnet_adapter, sizeof(profile->qmapnet_adapter), "rmnet_data%d", profile->muxid&0xF);
snprintf(tmp, sizeof(tmp), "/sys/class/net/%s", profile->qmapnet_adapter);
if (access(tmp, F_OK)) {
rtrmnet_ctl_create_vnd(profile->usbnet_adapter, profile->qmapnet_adapter,
profile->muxid, profile->qmap_version, 11, 4096);
}
}
#endif
return 0;
}

View File

@ -1,657 +0,0 @@
//https://github.com/andersson/qrtr
/******************************************************************************
@file QrtrCM.c
@brief GobiNet driver.
DESCRIPTION
Connectivity Management Tool for USB network adapter of Quectel wireless cellular modules.
INITIALIZATION AND SEQUENCING REQUIREMENTS
None.
---------------------------------------------------------------------------
Copyright (c) 2016 - 2023 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
Quectel Wireless Solution Proprietary and Confidential.
---------------------------------------------------------------------------
******************************************************************************/
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <stdio.h>
#include <ctype.h>
#include "QMIThread.h"
typedef struct {
uint32_t service;
uint32_t version;
uint32_t instance;
uint32_t node;
uint32_t port;
} QrtrService;
#define QRTR_MAX (QMUX_TYPE_WDS_ADMIN + 1)
static QrtrService service_list[QRTR_MAX];
static int qmiclientId[QRTR_MAX];
static int get_client(UCHAR QMIType);
static uint32_t node_modem = 3; //IPQ ~ 3, QCM ~ 0
#ifdef USE_LINUX_MSM_IPC
#include <linux/msm_ipc.h>
struct xport_ipc_router_server_addr {
uint32_t service;
uint32_t instance;
uint32_t node_id;
uint32_t port_id;
};
union ctl_msg {
uint32_t cmd;
struct {
uint32_t cmd;
uint32_t service;
uint32_t instance;
uint32_t node_id;
uint32_t port_id;
} srv;
struct {
uint32_t cmd;
uint32_t node_id;
uint32_t port_id;
} cli;
};
#define CTL_CMD_NEW_SERVER 4
#define CTL_CMD_REMOVE_SERVER 5
#define VERSION_MASK 0xff
#define GET_VERSION(x) (x & 0xff)
#define GET_XPORT_SVC_INSTANCE(x) GET_VERSION(x)
#define GET_INSTANCE(x) ((x & 0xff00) >> 8)
static int msm_ipc_socket(const char *name)
{
int sock;
int flags;
sock = socket(AF_MSM_IPC, SOCK_DGRAM, 0);
if (sock < 0) {
dbg_time("%s(%s) errno: %d (%s)\n", __func__, name, errno, strerror(errno));
return -1;
}
fcntl(sock, F_SETFD, FD_CLOEXEC);
flags = fcntl(sock, F_GETFL, 0);
fcntl(sock, F_SETFL, flags | O_NONBLOCK);
return sock;
}
static uint32_t xport_lookup
(
int lookup_sock_fd,
uint32_t service_id,
uint32_t version
)
{
uint32_t num_servers_found = 0;
uint32_t num_entries_to_fill = 4;
struct server_lookup_args *lookup_arg;
int i;
lookup_arg = (struct server_lookup_args *)malloc(sizeof(*lookup_arg)
+ (num_entries_to_fill * sizeof(struct msm_ipc_server_info)));
if (!lookup_arg)
{
dbg_time("%s: Malloc failed\n", __func__);
return 0;
}
lookup_arg->port_name.service = service_id;
lookup_arg->port_name.instance = GET_XPORT_SVC_INSTANCE(version);
lookup_arg->num_entries_in_array = num_entries_to_fill;
lookup_arg->lookup_mask = VERSION_MASK;
lookup_arg->num_entries_found = 0;
if (ioctl(lookup_sock_fd, IPC_ROUTER_IOCTL_LOOKUP_SERVER, lookup_arg) < 0)
{
dbg_time("%s: Lookup failed for %08x: %08x\n", __func__, service_id, version);
free(lookup_arg);
return 0;
}
dbg_time("%s: num_entries_found %d for type=%d instance=%d", __func__,
lookup_arg->num_entries_found, service_id, version);
num_servers_found = 0;
for (i = 0; ((i < (int)num_entries_to_fill) && (i < lookup_arg->num_entries_found)); i++)
{
QrtrService service_info[1];
if (lookup_arg->srv_info[i].node_id != node_modem)
continue;
num_servers_found++;
service_info[0].service = lookup_arg->srv_info[i].service;
service_info[0].version = GET_VERSION(lookup_arg->srv_info[i].instance);
service_info[0].instance = GET_INSTANCE(lookup_arg->srv_info[i].instance);
service_info[0].node = lookup_arg->srv_info[i].node_id;
service_info[0].port = lookup_arg->srv_info[i].port_id;
service_list[service_id] = service_info[0];
qmiclientId[service_id] = get_client(service_id);
}
free(lookup_arg);
return num_servers_found;
}
static int xport_send(int sock, uint32_t node, uint32_t port, const void *data, unsigned int sz)
{
struct sockaddr_msm_ipc addr = {};
int rc;
addr.family = AF_MSM_IPC;
addr.address.addrtype = MSM_IPC_ADDR_ID;
addr.address.addr.port_addr.node_id = node;
addr.address.addr.port_addr.port_id = port;
rc = sendto(sock, data, sz, MSG_DONTWAIT, (void *)&addr, sizeof(addr));
if (rc < 0) {
dbg_time("xport_send errno: %d (%s)\n", errno, strerror(errno));
return -1;
}
return 0;
}
static int xport_recv(int sock, void *data, unsigned int sz, uint32_t *node, uint32_t *port)
{
struct sockaddr_msm_ipc addr = {};
socklen_t addr_size = sizeof(struct sockaddr_msm_ipc);
int rc;
rc = recvfrom(sock, data, sz, MSG_DONTWAIT, (void *)&addr, &addr_size);
if (rc < 0) {
dbg_time("xport_recv errno: %d (%s)\n", errno, strerror(errno));
}
else if (addr.address.addrtype != MSM_IPC_ADDR_ID) {
dbg_time("xport_recv addrtype is NOT MSM_IPC_ADDR_ID\n");
rc = -1;
}
*node = addr.address.addr.port_addr.node_id;
*port = addr.address.addr.port_addr.port_id;
return rc;
}
#define qmi_recv xport_recv
static int xport_ctrl_init(void)
{
int ctrl_sock;
int rc;
uint32_t instance = 1; //modem
uint32_t version;
ctrl_sock = msm_ipc_socket("ctrl_port");
if (ctrl_sock == -1)
return -1;
rc = ioctl(ctrl_sock, IPC_ROUTER_IOCTL_GET_VERSION, &version);
if (rc < 0) {
dbg_time("%s: failed to get ipc version\n", __func__);
goto init_close_ctrl_fd;
}
dbg_time("%s ipc_version = %d", __func__, version);
rc = ioctl(ctrl_sock, IPC_ROUTER_IOCTL_BIND_CONTROL_PORT, NULL);
if (rc < 0) {
dbg_time("%s: failed to bind as control port\n", __func__);
goto init_close_ctrl_fd;
}
//cat /sys/kernel/debug/msm_ipc_router/dump_servers
rc = 0;
rc += xport_lookup(ctrl_sock, QMUX_TYPE_WDS, instance);
if (service_list[QMUX_TYPE_WDS].port) {
qmiclientId[QMUX_TYPE_WDS_IPV6] = get_client(QMUX_TYPE_WDS);
}
rc += xport_lookup(ctrl_sock, QMUX_TYPE_NAS, instance);
rc += xport_lookup(ctrl_sock, QMUX_TYPE_UIM, instance);
rc += xport_lookup(ctrl_sock, QMUX_TYPE_DMS, instance);
rc += xport_lookup(ctrl_sock, QMUX_TYPE_WDS_ADMIN, instance);
if (rc == 0) {
dbg_time("%s: failed to lookup qmi service\n", __func__);
goto init_close_ctrl_fd;
}
return ctrl_sock;
init_close_ctrl_fd:
close(ctrl_sock);
return -1;
}
static void handle_ctrl_pkt(int sock) {
union ctl_msg pkt;
uint32_t type;
int rc;
rc = recvfrom(sock, &pkt, sizeof(pkt), 0, NULL, NULL);
if (rc < 0)
return;
type = le32toh(pkt.cmd);
if (CTL_CMD_NEW_SERVER == type || CTL_CMD_REMOVE_SERVER == type) {
QrtrService s;
s.service = le32toh(pkt.srv.service);
s.version = le32toh(pkt.srv.instance) & 0xff;
s.instance = le32toh(pkt.srv.instance) >> 8;
s.node = le32toh(pkt.srv.node_id);
s.port = le32toh(pkt.srv.port_id);
if (debug_qmi)
dbg_time ("[qrtr] %s server on %u:%u -> service %u, version %u, instance %u",
CTL_CMD_NEW_SERVER == type ? "add" : "remove",
s.node, s.port, s.service, s.version, s.instance);
if (CTL_CMD_NEW_SERVER == type) {
if (s.service < QRTR_MAX) {
service_list[s.service] = s;
}
}
else if (CTL_CMD_REMOVE_SERVER == type) {
if (s.service < QRTR_MAX) {
memset(&service_list[s.service], 0, sizeof(QrtrService));
}
}
}
}
#else
#include <linux/socket.h>
#include "qrtr.h"
#endif
static int qrtr_socket(void)
{
struct sockaddr_qrtr sq;
socklen_t sl = sizeof(sq);
int sock;
int rc;
sock = socket(AF_QIPCRTR, SOCK_DGRAM, 0);
if (sock < 0) {
dbg_time("qrtr_socket errno: %d (%s)\n", errno, strerror(errno));
return -1;
}
rc = getsockname(sock, (void *)&sq, &sl);
if (rc || sq.sq_family != AF_QIPCRTR || sl != sizeof(sq)) {
dbg_time("getsockname: %d (%s)\n", errno, strerror(errno));
close(sock);
return -1;
}
return sock;
}
static int qrtr_send(int sock, uint32_t node, uint32_t port, const void *data, unsigned int sz)
{
struct sockaddr_qrtr sq = {};
int rc;
sq.sq_family = AF_QIPCRTR;
sq.sq_node = node;
sq.sq_port = port;
rc = sendto(sock, data, sz, MSG_DONTWAIT, (void *)&sq, sizeof(sq));
if (rc < 0) {
dbg_time("sendto errno: %d (%s)\n", errno, strerror(errno));
return -1;
}
return 0;
}
static int qrtr_recv(int sock, void *data, unsigned int sz, uint32_t *node, uint32_t *port)
{
struct sockaddr_qrtr sq = {};
socklen_t sl = sizeof(sq);
int rc;
rc = recvfrom(sock, data, sz, MSG_DONTWAIT, (void *)&sq, &sl);
if (rc < 0) {
dbg_time("qrtr_recv errno: %d (%s)\n", errno, strerror(errno));
}
*node = sq.sq_node;
*port = sq.sq_port;
return rc;
}
#define qmi_recv qrtr_recv
static int qrtr_ctrl_init(void) {
int sock;
int rc;
struct qrtr_ctrl_pkt pkt;
struct sockaddr_qrtr sq;
socklen_t sl = sizeof(sq);
sock = qrtr_socket();
if (sock == -1)
return -1;
memset(&pkt, 0, sizeof(pkt));
pkt.cmd = htole32(QRTR_TYPE_NEW_LOOKUP);
getsockname(sock, (void *)&sq, &sl);
rc = qrtr_send(sock, sq.sq_node, QRTR_PORT_CTRL, &pkt, sizeof(pkt));
if (rc == -1) {
dbg_time("qrtr_send errno: %d (%s)\n", errno, strerror(errno));
close(sock);
return -1;
}
return sock;
}
static void handle_server_change(uint32_t type, struct qrtr_ctrl_pkt *ppkt) {
struct qrtr_ctrl_pkt pkt = *ppkt;
QrtrService s;
s.service = le32toh(pkt.server.service);
s.version = le32toh(pkt.server.instance) & 0xff;
s.instance = le32toh(pkt.server.instance) >> 8;
s.node = le32toh(pkt.server.node);
s.port = le32toh(pkt.server.port);
if (debug_qmi)
dbg_time ("[qrtr] %s server on %u:%u -> service %u, version %u, instance %u",
QRTR_TYPE_NEW_SERVER == type ? "add" : "remove",
s.node, s.port, s.service, s.version, s.instance);
if (s.node != node_modem)
return; //we only care modem
if (QRTR_TYPE_NEW_SERVER == type) {
if (s.service < QRTR_MAX) {
service_list[s.service] = s;
}
}
else if (QRTR_TYPE_DEL_SERVER == type) {
if (s.service < QRTR_MAX) {
memset(&service_list[s.service], 0, sizeof(QrtrService));
}
}
}
static void handle_ctrl_pkt(int sock) {
struct qrtr_ctrl_pkt pkt;
struct sockaddr_qrtr sq;
socklen_t sl = sizeof(sq);
uint32_t type;
int rc;
rc = recvfrom(sock, &pkt, sizeof(pkt), 0, (void *)&sq, &sl);
if (rc < 0)
return;
type = le32toh(pkt.cmd);
if (debug_qmi)
dbg_time("type %u, node %u, sq.port %x, len: %d", type, sq.sq_node, sq.sq_port, rc);
if (sq.sq_port != QRTR_PORT_CTRL)
return;
if (QRTR_TYPE_NEW_SERVER == type || QRTR_TYPE_DEL_SERVER == type) {
handle_server_change(type, &pkt);
}
}
static int get_client(UCHAR QMIType) {
int ClientId;
QrtrService *s = &service_list[QMIType];
if (!s ->service) {
dbg_time("%s service: %d for QMIType: %d", __func__, s ->service, QMIType);
return -ENODEV;
}
#ifdef USE_LINUX_MSM_IPC
ClientId = msm_ipc_socket("xport");
#else
ClientId = qrtr_socket();
#endif
if (ClientId == -1) {
return 0;
}
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 void handle_alloc_client(PROFILE_T *profile) {
int srv_list[] = {QMUX_TYPE_WDS, QMUX_TYPE_NAS, QMUX_TYPE_UIM, QMUX_TYPE_DMS, QMUX_TYPE_WDS_ADMIN};
size_t i = 0, srv_ready = 0;
static int report = -1;
if (report != -1)
return;
for(i = 0; i < sizeof(srv_list)/sizeof(srv_list[0]); i++) {
int srv = srv_list[i];
if (service_list[srv].service)
srv_ready++;
else
continue;
if (qmiclientId[srv] == 0) {
qmiclientId[srv] = get_client(srv);
if (qmiclientId[srv] != 0) {
if (srv == QMUX_TYPE_WDS) {
qmiclientId[QMUX_TYPE_WDS_IPV6] = get_client(QMUX_TYPE_WDS);
}
else if (srv == QMUX_TYPE_WDS_ADMIN) {
profile->wda_client = qmiclientId[QMUX_TYPE_WDS_ADMIN];
}
}
}
}
if (srv_ready == sizeof(srv_list)/sizeof(srv_list[0])) {
if (qmiclientId[QMUX_TYPE_WDS]) {
qmidevice_send_event_to_main(RIL_INDICATE_DEVICE_CONNECTED);
} else {
qmidevice_send_event_to_main(RIL_INDICATE_DEVICE_DISCONNECTED);
}
report = 1;
}
}
static int qmi_send(PQCQMIMSG pRequest) {
uint8_t QMIType = pRequest->QMIHdr.QMIType;
int sock;
QrtrService *s = &service_list[QMIType == QMUX_TYPE_WDS_IPV6 ? QMUX_TYPE_WDS: QMIType];
sock = qmiclientId[QMIType];
pRequest->QMIHdr.ClientId = 0xaa;
if (!s ->service || !sock) {
dbg_time("%s service: %d, sock: %d for QMIType: %d", __func__, s ->service, sock, QMIType);
return -ENODEV;
}
#ifdef USE_LINUX_MSM_IPC
return xport_send(sock, s->node, s->port, &pRequest->MUXMsg,
le16_to_cpu(pRequest->QMIHdr.Length) + 1 - sizeof(QCQMI_HDR));
#else
return qrtr_send(sock, s->node, s->port, &pRequest->MUXMsg,
le16_to_cpu(pRequest->QMIHdr.Length) + 1 - sizeof(QCQMI_HDR));
#endif
}
static int qmi_deinit(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 * qmi_read(void *pData) {
PROFILE_T *profile = (PROFILE_T *)pData;
int ctrl_sock;
int wait_for_request_quit = 0;
#ifdef USE_LINUX_MSM_IPC
ctrl_sock = xport_ctrl_init();
if (ctrl_sock != -1)
qmidevice_send_event_to_main(RIL_INDICATE_DEVICE_CONNECTED);
#else
ctrl_sock = qrtr_ctrl_init();
#endif
if (ctrl_sock == -1)
goto _quit;
while (1) {
struct pollfd pollfds[16] = {{qmidevice_control_fd[1], POLLIN, 0}, {ctrl_sock, POLLIN, 0}};
int ne, ret, nevents = 2;
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 _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 _quit;
break;
case SIG_EVENT_STOP:
wait_for_request_quit = 1;
break;
default:
break;
}
}
}
else if (fd == ctrl_sock) {
handle_ctrl_pkt(ctrl_sock);
handle_alloc_client(profile);
}
else
{
PQCQMIMSG pResponse = (PQCQMIMSG)cm_recv_buf;
int rc;
uint32_t sq_node = 0;
uint32_t sq_port = 0;
rc = qmi_recv(fd, &pResponse->MUXMsg, sizeof(cm_recv_buf) - sizeof(QCQMI_HDR), &sq_node, &sq_port);
if (debug_qmi)
dbg_time("fd %d, node %u, port %x, len: %d", fd, sq_node, sq_port, rc);
if (rc <= 0)
{
dbg_time("%s read=%d errno: %d (%s)", __func__, rc, errno, strerror(errno));
break;
}
for (i = 0; i < sizeof(qmiclientId)/sizeof(qmiclientId[0]); i++)
{
if (qmiclientId[i] == fd)
{
pResponse->QMIHdr.QMIType = i;
if (service_list[i].node != sq_node || service_list[i].port != sq_port) {
continue;
}
}
}
pResponse->QMIHdr.IFType = USB_CTL_MSG_TYPE_QMI;
pResponse->QMIHdr.Length = cpu_to_le16(rc + sizeof(QCQMI_HDR) - 1);
pResponse->QMIHdr.CtlFlags = 0x00;
pResponse->QMIHdr.ClientId = 0xaa;
QmiThreadRecvQMI(pResponse);
}
}
}
_quit:
qmi_deinit();
close(ctrl_sock);
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;
}
const struct qmi_device_ops qrtr_qmidev_ops = {
.deinit = qmi_deinit,
.send = qmi_send,
.read = qmi_read,
};

View File

@ -1,74 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _LINUX_QRTR_H
#define _LINUX_QRTR_H
#include <linux/socket.h>
#include <linux/types.h>
#ifndef AF_QIPCRTR
#define AF_QIPCRTR 42
#endif
#define QRTR_NODE_BCAST 0xffffffffu
#define QRTR_PORT_CTRL 0xfffffffeu
struct sockaddr_qrtr {
__kernel_sa_family_t sq_family;
__u32 sq_node;
__u32 sq_port;
};
enum qrtr_pkt_type {
QRTR_TYPE_DATA = 1,
QRTR_TYPE_HELLO = 2,
QRTR_TYPE_BYE = 3,
QRTR_TYPE_NEW_SERVER = 4,
QRTR_TYPE_DEL_SERVER = 5,
QRTR_TYPE_DEL_CLIENT = 6,
QRTR_TYPE_RESUME_TX = 7,
QRTR_TYPE_EXIT = 8,
QRTR_TYPE_PING = 9,
QRTR_TYPE_NEW_LOOKUP = 10,
QRTR_TYPE_DEL_LOOKUP = 11,
};
#define QRTR_TYPE_DEL_PROC 13
struct qrtr_ctrl_pkt {
__le32 cmd;
union {
struct {
__le32 service;
__le32 instance;
__le32 node;
__le32 port;
} server;
struct {
__le32 node;
__le32 port;
} client;
struct {
__le32 rsvd;
__le32 node;
} proc;
};
} __attribute__ ((packed));
#define QRTR_PROTO_VER_1 1
struct qrtr_hdr_v1 {
__le32 version;
__le32 type;
__le32 src_node_id;
__le32 src_port_id;
__le32 confirm_rx;
__le32 size;
__le32 dst_node_id;
__le32 dst_port_id;
} __attribute__ ((packed));
#endif /* _LINUX_QRTR_H */

View File

@ -1,506 +0,0 @@
/******************************************************************************
@file quectel-atc-proxy.c
@brief atc proxy.
DESCRIPTION
Connectivity Management Tool for USB network adapter of Quectel wireless cellular modules.
INITIALIZATION AND SEQUENCING REQUIREMENTS
None.
---------------------------------------------------------------------------
Copyright (c) 2016 - 2023 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
Quectel Wireless Solution Proprietary and Confidential.
---------------------------------------------------------------------------
******************************************************************************/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <stddef.h>
#include <pthread.h>
#include <errno.h>
#include <time.h>
#include <signal.h>
#include <getopt.h>
#include <poll.h>
#include <sys/time.h>
#include <endian.h>
#include <time.h>
#include <sys/types.h>
#include <limits.h>
#include <inttypes.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <stddef.h>
#include <fcntl.h>
#include <pthread.h>
#include <poll.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <linux/un.h>
#include <linux/if.h>
#include <dirent.h>
#include <signal.h>
#include <endian.h>
#include <inttypes.h>
#include "qlist.h"
#include "QMIThread.h"
#include "atchannel.h"
#include "at_tok.h"
#define dprintf(fmt, args...) do { fprintf(stdout, "%s " fmt, get_time(), ##args); } 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 safe_free(__x) do { if (__x) { free((void *)__x); __x = NULL;}} while(0)
#define safe_at_response_free(__x) { if (__x) { at_response_free(__x); __x = NULL;}}
#define at_response_error(err, p_response) \
(err \
|| p_response == NULL \
|| p_response->finalResponse == NULL \
|| p_response->success == 0)
typedef struct {
struct qlistnode qnode;
int ClientFd;
unsigned AccessTime;
} ATC_PROXY_CONNECTION;
static int atc_proxy_quit = 0;
static pthread_t thread_id = 0;
static int atc_dev_fd = -1;
static int atc_proxy_server_fd = -1;
static struct qlistnode atc_proxy_connection;
static int verbose_debug = 0;
static int modem_reset_flag = 0;
static uint8_t atc_buf[4096];
static int asr_style_atc = 0;
extern int asprintf(char **s, const char *fmt, ...);
static ATC_PROXY_CONNECTION *current_client_fd = NULL;
static void dump_atc(uint8_t *pATC, int fd,int size, const char flag)
{
if (verbose_debug) {
printf("%c %d:\n", flag, fd);
printf("%.*s\n", size, pATC);
}
}
static int send_atc_to_client(int clientFd, uint8_t *pATC, int size) {
struct pollfd pollfds[]= {{clientFd, POLLOUT, 0}};
ssize_t ret = 0;
do {
ret = poll(pollfds, sizeof(pollfds)/sizeof(pollfds[0]), 5000);
} while (ret == -1 && errno == EINTR && atc_proxy_quit == 0);
if (pollfds[0].revents & POLLOUT) {
ret = write(clientFd, pATC, size);
}
return ret;
}
static void onUnsolicited (const char *s, const char *sms_pdu)
{
struct qlistnode *con_node;
int ret;
char buf[1024];
if(s) {
strcpy(buf, s);
strcat(buf, "\r\n");
}
if(sms_pdu) {
strcat(buf, sms_pdu);
strcat(buf, "\r\n");
}
if(current_client_fd) {
ATC_PROXY_CONNECTION *atc_con = current_client_fd;
ret = send_atc_to_client(atc_con->ClientFd, (uint8_t *)buf, strlen(buf));
if(ret < 0) {
close(atc_con->ClientFd);
qlist_remove(&atc_con->qnode);
free(atc_con);
}
return;
}
qlist_for_each(con_node, &atc_proxy_connection) {
ATC_PROXY_CONNECTION *atc_con = qnode_to_item(con_node, ATC_PROXY_CONNECTION, qnode);
if(atc_con && atc_con->ClientFd > 0) {
ret = send_atc_to_client(atc_con->ClientFd, (uint8_t *)buf, strlen(buf));
if(ret < 0) {
close(atc_con->ClientFd);
con_node = con_node->prev;
qlist_remove(&atc_con->qnode);
free(atc_con);
continue;
}
}
}
}
static void onTimeout(void) {
dprintf("%s", __func__);
//TODO
}
static void onClose(void) {
dprintf("%s", __func__);
}
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("bind %s errno: %d (%s)\n", 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_atc_connection(int serverfd) {
int clientfd = -1;
unsigned char addr[128];
socklen_t alen = sizeof(addr);
ATC_PROXY_CONNECTION *atc_con;
clientfd = accept(serverfd, (struct sockaddr *)addr, &alen);
atc_con = (ATC_PROXY_CONNECTION *)malloc(sizeof(ATC_PROXY_CONNECTION));
if (atc_con) {
qlist_init(&atc_con->qnode);
atc_con->ClientFd= clientfd;
atc_con->AccessTime = 0;
dprintf("+++ ClientFd=%d\n", atc_con->ClientFd);
qlist_add_tail(&atc_proxy_connection, &atc_con->qnode);
}
cfmakenoblock(clientfd);
}
static void cleanup_atc_connection(int clientfd) {
struct qlistnode *con_node;
qlist_for_each(con_node, &atc_proxy_connection) {
ATC_PROXY_CONNECTION *atc_con = qnode_to_item(con_node, ATC_PROXY_CONNECTION, qnode);
if (atc_con->ClientFd == clientfd) {
dprintf("--- ClientFd=%d\n", atc_con->ClientFd);
close(atc_con->ClientFd);
qlist_remove(&atc_con->qnode);
free(atc_con);
if (current_client_fd == atc_con)
current_client_fd = NULL;
break;
}
}
}
static int atc_proxy_init(void) {
int err;
char *cmd;
ATResponse *p_response = NULL;
err = at_handshake();
if (err) {
dprintf("handshake fail, TODO ... ");
goto exit;
}
at_send_command_singleline("AT+QCFG=\"usbnet\"", "+QCFG:", NULL);
at_send_command_multiline("AT+QNETDEVCTL=?", "+QNETDEVCTL:", NULL);
at_send_command("AT+CGREG=2", NULL); //GPRS Network Registration Status
at_send_command("AT+CEREG=2", NULL); //EPS Network Registration Status
at_send_command("AT+C5GREG=2", NULL); //5GS Network Registration Status
at_send_command_singleline("AT+QNETDEVSTATUS=?", "+QNETDEVSTATUS:", &p_response);
if (at_response_error(err, p_response))
asr_style_atc = 1; //EC200T/EC100Y do not support this AT, but RG801/RG500U support
safe_at_response_free(p_response);
err = at_send_command_singleline("AT+QCFG=\"NAT\"", "+QCFG:", &p_response);
if (!at_response_error(err, p_response)) {
int old_nat, new_nat = asr_style_atc ? 1 : 0;
err = at_tok_scanf(p_response->p_intermediates->line, "%s%d", NULL, &old_nat);
if (err == 2 && old_nat != new_nat) {
safe_at_response_free(p_response);
asprintf(&cmd, "AT+QCFG=\"NAT\",%d", new_nat);
err = at_send_command(cmd, &p_response);
safe_free(cmd);
if (!at_response_error(err, p_response)) {
err = at_send_command("at+cfun=1,1",NULL);
}
safe_at_response_free(p_response);
}
err = 0;
}
safe_at_response_free(p_response);
exit:
return err;
}
static void atc_start_server(const char* servername) {
atc_proxy_server_fd = create_local_server(servername);
dprintf("atc_proxy_server_fd = %d\n", atc_proxy_server_fd);
if (atc_proxy_server_fd == -1) {
dprintf("Failed to create %s, errno: %d (%s)\n", servername, errno, strerror(errno));
}
}
static void atc_close_server(const char* servername) {
if (atc_proxy_server_fd != -1) {
dprintf("%s %s close server\n", __func__, servername);
close(atc_proxy_server_fd);
atc_proxy_server_fd = -1;
}
}
static void *atc_proxy_loop(void *param)
{
uint8_t *pATC = atc_buf;
struct qlistnode *con_node;
ATC_PROXY_CONNECTION *atc_con;
(void)param;
dprintf("%s enter thread_id %p\n", __func__, (void *)pthread_self());
qlist_init(&atc_proxy_connection);
while (atc_dev_fd > 0 && atc_proxy_quit == 0) {
struct pollfd pollfds[2+64];
int ne, ret, nevents = 0;
ssize_t nreads;
pollfds[nevents].fd = atc_dev_fd;
pollfds[nevents].events = POLLIN;
pollfds[nevents].revents= 0;
nevents++;
if (atc_proxy_server_fd > 0) {
pollfds[nevents].fd = atc_proxy_server_fd;
pollfds[nevents].events = POLLIN;
pollfds[nevents].revents= 0;
nevents++;
}
qlist_for_each(con_node, &atc_proxy_connection) {
atc_con = qnode_to_item(con_node, ATC_PROXY_CONNECTION, qnode);
pollfds[nevents].fd = atc_con->ClientFd;
pollfds[nevents].events = POLLIN;
pollfds[nevents].revents= 0;
nevents++;
if (nevents == (sizeof(pollfds)/sizeof(pollfds[0])))
break;
}
do {
ret = poll(pollfds, nevents, (atc_proxy_server_fd > 0) ? -1 : 200);
} while (ret == -1 && errno == EINTR && atc_proxy_quit == 0);
if (ret < 0) {
dprintf("%s poll=%d, errno: %d (%s)\n", __func__, ret, errno, strerror(errno));
goto atc_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 == atc_dev_fd) {
goto atc_proxy_loop_exit;
} else if(fd == atc_proxy_server_fd) {
} else {
cleanup_atc_connection(fd);
}
continue;
}
if (!(pollfds[ne].revents & POLLIN)) {
continue;
}
if (fd == atc_proxy_server_fd) {
accept_atc_connection(fd);
}
else if (fd == atc_dev_fd) {
usleep(10*1000); //let atchannel.c read at response.
if (modem_reset_flag)
goto atc_proxy_loop_exit;
}
else {
memset(atc_buf, 0x0, sizeof(atc_buf));
nreads = read(fd, pATC, sizeof(atc_buf));
if (nreads <= 0) {
dprintf("%s read=%d errno: %d (%s)", __func__, (int)nreads, errno, strerror(errno));
cleanup_atc_connection(fd);
break;
}
dump_atc(pATC, fd, nreads, 'r');
qlist_for_each(con_node, &atc_proxy_connection) {
atc_con = qnode_to_item(con_node, ATC_PROXY_CONNECTION, qnode);
if (atc_con->ClientFd == pollfds[nevents].fd) {
current_client_fd = atc_con;
break;
}
}
at_send_command ((const char *)pATC, NULL);
current_client_fd = NULL;
}
}
}
atc_proxy_loop_exit:
at_close();
while (!qlist_empty(&atc_proxy_connection)) {
ATC_PROXY_CONNECTION *atc_con = qnode_to_item(qlist_head(&atc_proxy_connection), ATC_PROXY_CONNECTION, qnode);
cleanup_atc_connection(atc_con->ClientFd);
}
dprintf("%s exit, thread_id %p\n", __func__, (void *)pthread_self());
return NULL;
}
static void usage(void) {
dprintf(" -d <device_name> A valid atc device\n"
" default /dev/ttyUSB2, but /dev/ttyUSB2 may be invalid\n"
" -i <netcard_name> netcard name\n"
" -v Will show all details\n");
}
static void sig_action(int sig) {
if (atc_proxy_quit == 0) {
atc_proxy_quit = 1;
if (thread_id)
pthread_kill(thread_id, sig);
}
}
int main(int argc, char *argv[]) {
int opt;
char atc_dev[32+1] = "/dev/ttyUSB2";
int retry_times = 0;
char servername[64] = {0};
optind = 1;
signal(SIGINT, sig_action);
while ( -1 != (opt = getopt(argc, argv, "d:i:vh"))) {
switch (opt) {
case 'd':
strcpy(atc_dev, optarg);
break;
case 'v':
verbose_debug = 1;
break;
default:
usage();
return 0;
}
}
if (access(atc_dev, R_OK | W_OK)) {
dprintf("Fail to access %s, errno: %d (%s). break\n", atc_dev, errno, strerror(errno));
return -1;
}
sprintf(servername, "quectel-atc-proxy%c", atc_dev[strlen(atc_dev) - 1]);
dprintf("Will use atc-dev='%s', proxy='%s'\n", atc_dev, servername);
while (atc_proxy_quit == 0) {
if (access(atc_dev, R_OK | W_OK)) {
dprintf("Fail to access %s, errno: %d (%s). continue\n", atc_dev, errno, strerror(errno));
// wait device
sleep(3);
continue;
}
atc_dev_fd = open(atc_dev, O_RDWR | O_NONBLOCK | O_NOCTTY);
if (atc_dev_fd == -1) {
dprintf("Failed to open %s, errno: %d (%s). break\n", atc_dev, errno, strerror(errno));
return -1;
}
cfmakenoblock(atc_dev_fd);
if (at_open(atc_dev_fd, onUnsolicited, 1)) {
close(atc_dev_fd);
atc_dev_fd = -1;
}
at_set_on_timeout(onTimeout);
at_set_on_reader_closed(onClose);
/* no atc_proxy_loop lives, create one */
pthread_create(&thread_id, NULL, atc_proxy_loop, NULL);
/* try to redo init if failed, init function must be successfully */
while (atc_proxy_init() != 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(atc_dev, F_OK|R_OK|W_OK))
break;
}
retry_times = 0;
atc_start_server(servername);
if (atc_proxy_server_fd == -1)
pthread_cancel(thread_id);
pthread_join(thread_id, NULL);
/* close local server at last */
atc_close_server(servername);
close(atc_dev_fd);
/* DO RESTART IN 20s IF MODEM RESET ITSELF */
if (modem_reset_flag) {
unsigned int time_to_wait = 20;
while (time_to_wait) {
time_to_wait = sleep(time_to_wait);
}
modem_reset_flag = 0;
}
}
return 0;
}

View File

@ -1,453 +0,0 @@
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <stddef.h>
#include <fcntl.h>
#include <pthread.h>
#include <poll.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <linux/un.h>
#include <linux/in.h>
#include <linux/if.h>
#include <dirent.h>
#include <signal.h>
#include <inttypes.h>
#include <getopt.h>
#include "qendian.h"
#define QUECTEL_MBIM_PROXY "quectel-mbim-proxy"
#define safe_close(_fd) do { if (_fd > 0) { close(_fd); _fd = -1; } } while(0)
#define CM_MAX_CLIENT 32
#define TID_MASK (0xFFFFFF)
#define TID_SHIFT (24)
typedef enum {
MBIM_OPEN_MSG = 1,
MBIM_CLOSE_MSG = 2,
MBIM_OPEN_DONE = 0x80000001,
MBIM_CLOSE_DONE = 0x80000002,
} MBIM_MSG;
typedef struct {
unsigned int MessageType;
unsigned int MessageLength;
unsigned int TransactionId;
} MBIM_MESSAGE_HEADER;
typedef struct {
MBIM_MESSAGE_HEADER MessageHeader;
unsigned int MaxControlTransfer;
} MBIM_OPEN_MSG_T;
typedef struct {
MBIM_MESSAGE_HEADER MessageHeader;
unsigned int Status;
} MBIM_OPEN_DONE_T;
typedef struct {
int client_fd;
int client_idx;
} CM_CLIENT_T;
static unsigned char cm_recv_buffer[4096];
static CM_CLIENT_T cm_clients[CM_MAX_CLIENT];
static int verbose = 0;
const char * get_time(void) {
static char time_buf[128];
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;
}
#define mbim_debug(fmt, args...) do { fprintf(stdout, "%s " fmt, get_time(), ##args); } while(0);
static int non_block_write(int fd, void *data, int len)
{
int ret;
struct pollfd pollfd = {fd, POLLOUT, 0};
ret = poll(&pollfd, 1, 3000);
if (ret <= 0) {
mbim_debug("%s poll ret=%d, errno: %d(%s)\n", __func__, ret, errno, strerror(errno));
}
ret = write (fd, data, len);
if (ret != len)
mbim_debug("%s write ret=%d, errno: %d(%s)\n", __func__, ret, errno, strerror(errno));
return len;
}
static int mbim_send_open_msg(int mbim_dev_fd, uint32_t MaxControlTransfer) {
MBIM_OPEN_MSG_T open_msg;
MBIM_OPEN_MSG_T *pRequest = &open_msg;
pRequest->MessageHeader.MessageType = htole32(MBIM_OPEN_MSG);
pRequest->MessageHeader.MessageLength = htole32(sizeof(MBIM_OPEN_MSG_T));
pRequest->MessageHeader.TransactionId = htole32(1);
pRequest->MaxControlTransfer = htole32(MaxControlTransfer);
mbim_debug("%s()\n", __func__);
return non_block_write(mbim_dev_fd, pRequest, sizeof(MBIM_OPEN_MSG_T));
}
/*
* parameter: proxy name
* return: local proxy server fd or -1
*/
static int proxy_make_server(const char *proxy_name)
{
int len, flag;
struct sockaddr_un sockaddr;
int mbim_server_fd;
mbim_server_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
if (mbim_server_fd < 0) {
mbim_debug("socket failed: %s\n", strerror(errno));
return -1;
}
if (fcntl(mbim_server_fd, F_SETFL, fcntl(mbim_server_fd, F_GETFL) | O_NONBLOCK) < 0)
mbim_debug("fcntl set server(%d) NONBLOCK attribute failed: %s\n", mbim_server_fd, strerror(errno));
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sun_family = AF_LOCAL;
sockaddr.sun_path[0] = 0;
snprintf(sockaddr.sun_path, UNIX_PATH_MAX, "0%s", proxy_name);
sockaddr.sun_path[0] = '\0'; // string starts with leading '\0'
flag = 1;
if (setsockopt(mbim_server_fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) < 0) {
safe_close(mbim_server_fd);
mbim_debug("setsockopt failed\n");
}
len = strlen(proxy_name) + offsetof(struct sockaddr_un, sun_path) + 1;
if (bind(mbim_server_fd, (struct sockaddr*)&sockaddr, len) < 0) {
safe_close(mbim_server_fd);
mbim_debug("bind failed: %s\n", strerror(errno));
return -1;
}
listen(mbim_server_fd, 4);
return mbim_server_fd;
}
static int handle_client_connect(int server_fd)
{
int i, client_fd;
struct sockaddr_in cli_addr;
socklen_t len = sizeof(cli_addr);
client_fd = accept(server_fd, (struct sockaddr *)&cli_addr, &len);
if (client_fd < 0) {
mbim_debug("proxy accept failed: %s\n", strerror(errno));
return -1;
}
if (fcntl(client_fd, F_SETFL, fcntl(client_fd, F_GETFL) | O_NONBLOCK) < 0)
mbim_debug("fcntl set client(%d) NONBLOCK attribute failed: %s\n", client_fd, strerror(errno));
for (i = 0; i < CM_MAX_CLIENT; i++) {
if (cm_clients[i].client_fd <= 0) {
cm_clients[i].client_fd = client_fd;
cm_clients[i].client_idx= i+1;
mbim_debug("%s client_fd=%d, client_idx=%d\n", __func__, cm_clients[i].client_fd, cm_clients[i].client_idx);
return 0;
}
}
close(client_fd);
return -1;
}
static void handle_client_disconnect(int client_fd)
{
int i;
for (i = 0; i < CM_MAX_CLIENT; i++) {
if (cm_clients[i].client_fd == client_fd) {
mbim_debug("%s client_fd=%d, client_idx=%d\n", __func__, cm_clients[i].client_fd, cm_clients[i].client_idx);
safe_close(cm_clients[i].client_fd);
return;
}
}
}
static int handle_client_request(int mbim_dev_fd, int client_fd, void *pdata, int len)
{
int i;
int client_idx = -1;
int ret;
MBIM_MESSAGE_HEADER *pRequest = (MBIM_MESSAGE_HEADER *)pdata;
unsigned int TransactionId = le32toh(pRequest->TransactionId);
for (i = 0; i < CM_MAX_CLIENT; i++) {
if (cm_clients[i].client_fd == client_fd) {
client_idx = cm_clients[i].client_idx;
break;
}
}
if (client_idx == -1) {
goto error;
}
if (le32toh(pRequest->MessageType) == MBIM_OPEN_MSG
|| le32toh(pRequest->MessageType) == MBIM_CLOSE_MSG) {
MBIM_OPEN_DONE_T OpenDone;
OpenDone.MessageHeader.MessageType = htole32(le32toh(pRequest->MessageType) | 0x80000000);
OpenDone.MessageHeader.MessageLength = htole32(sizeof(OpenDone));
OpenDone.MessageHeader.TransactionId = htole32(TransactionId);
OpenDone.Status = htole32(0);
non_block_write (client_fd, &OpenDone, sizeof(OpenDone));
return 0;
}
/* transfer TransicationID to proxy transicationID and record in sender list */
pRequest->TransactionId = htole32(TransactionId | (client_idx << TID_SHIFT));
if (verbose) mbim_debug("REQ client_fd=%d, client_idx=%d, tid=%u\n",
cm_clients[client_idx].client_fd, cm_clients[client_idx].client_idx, TransactionId);
ret = non_block_write (mbim_dev_fd, pRequest, len);
if (ret == len)
return 0;
error:
return -1;
}
/*
* Will read message from device and transfer it to clients/client
* Notice:
* unsocial message will be send to all clients
*/
static int handle_device_response(void *pdata, int len)
{
int i;
MBIM_MESSAGE_HEADER *pResponse = (MBIM_MESSAGE_HEADER *)pdata;
unsigned int TransactionId = le32toh(pResponse->TransactionId);
/* unsocial/function error message */
if (TransactionId == 0) {
for (i = 0; i < CM_MAX_CLIENT; i++) {
if (cm_clients[i].client_fd > 0) {
non_block_write(cm_clients[i].client_fd, pResponse, len);
}
}
}
else {
/* try to find the sender */
int client_idx = (TransactionId >> TID_SHIFT);
for (i = 0; i < CM_MAX_CLIENT; i++) {
if (cm_clients[i].client_idx == client_idx && cm_clients[i].client_fd > 0) {
TransactionId &= TID_MASK;
pResponse->TransactionId = htole32(TransactionId);
if (verbose) mbim_debug("RSP client_fd=%d, client_idx=%d, tid=%u\n",
cm_clients[i].client_fd, cm_clients[i].client_idx, TransactionId);
non_block_write(cm_clients[i].client_fd, pResponse, len);
break;
}
}
if (i == CM_MAX_CLIENT) {
mbim_debug("%s nobody care tid=%u\n", __func__, TransactionId);
}
}
return 0;
}
static int proxy_loop(int mbim_dev_fd)
{
int i;
int mbim_server_fd = -1;
while (mbim_dev_fd > 0) {
struct pollfd pollfds[2+CM_MAX_CLIENT];
int ne, ret, nevents = 0;
pollfds[nevents].fd = mbim_dev_fd;
pollfds[nevents].events = POLLIN;
pollfds[nevents].revents= 0;
nevents++;
if (mbim_server_fd > 0) {
pollfds[nevents].fd = mbim_server_fd;
pollfds[nevents].events = POLLIN;
pollfds[nevents].revents= 0;
nevents++;
for (i = 0; i < CM_MAX_CLIENT; i++) {
if (cm_clients[i].client_fd > 0) {
pollfds[nevents].fd = cm_clients[i].client_fd;
pollfds[nevents].events = POLLIN;
pollfds[nevents].revents= 0;
nevents++;
}
}
}
ret = poll(pollfds, nevents, (mbim_server_fd > 0) ? -1 : (10*1000));
if (ret <= 0) {
goto error;
}
for (ne = 0; ne < nevents; ne++) {
int fd = pollfds[ne].fd;
short revents = pollfds[ne].revents;
if (revents & (POLLERR | POLLHUP | POLLNVAL)) {
mbim_debug("%s poll fd = %d, revents = %04x\n", __func__, fd, revents);
if (fd == mbim_dev_fd) {
goto error;
} else if(fd == mbim_server_fd) {
} else {
handle_client_disconnect(fd);
}
continue;
}
if (!(pollfds[ne].revents & POLLIN)) {
continue;
}
if (fd == mbim_server_fd) {
handle_client_connect(fd);
}
else {
int len = read(fd, cm_recv_buffer, sizeof(cm_recv_buffer));
if (len <= 0) {
mbim_debug("%s read fd=%d, len=%d, errno: %d(%s)\n", __func__, fd, len, errno, strerror(errno));
if (fd == mbim_dev_fd)
goto error;
else
handle_client_disconnect(fd);
return len;
}
if (fd == mbim_dev_fd) {
if (mbim_server_fd == -1) {
MBIM_OPEN_DONE_T *pOpenDone = (MBIM_OPEN_DONE_T *)cm_recv_buffer;
if (le32toh(pOpenDone->MessageHeader.MessageType) == MBIM_OPEN_DONE) {
mbim_debug("receive MBIM_OPEN_DONE, status=%d\n", htole32(pOpenDone->Status));
if (htole32(pOpenDone->Status))
goto error;
mbim_server_fd = proxy_make_server(QUECTEL_MBIM_PROXY);
mbim_debug("mbim_server_fd=%d\n", mbim_server_fd);
}
}
else {
handle_device_response(cm_recv_buffer, len);
}
}
else {
handle_client_request(mbim_dev_fd, fd, cm_recv_buffer, len);
}
}
}
}
error:
safe_close(mbim_server_fd);
for (i = 0; i < CM_MAX_CLIENT; i++) {
safe_close(cm_clients[i].client_fd);
}
mbim_debug("%s exit\n", __func__);
return 0;
}
/*
* How to use this proxy?
* 1. modprobe -a 8021q
* 2. Create network interface for channels:
* ip link add link wwan0 name wwan0.1 type vlan id 1
* ip link add link wwan0 name wwan0.2 type vlan id 2
* 3. Start './mbim-proxy' with -d 'device'
* 4. Start Clients: ./quectel-CM -n id1
* 5. Start Clients: ./quectel-CM -n id2
* ...
* Notice:
* mbim-proxy can work in backgroud as a daemon
* '-n' sessionID
* The modem may not support multi-PDN mode or how many PDN it supports is undefined. It depends!!!
* Besides, some modem also may not support some sessionID. For instance EC20 doesn't support SessionId 1...
*/
int main(int argc, char **argv)
{
int optidx = 0;
int opt;
char *optstr = "d:vh";
const char *device = "/dev/cdc-wdm0";
struct option options[] = {
{"verbose", no_argument, NULL, 'v'},
{"device", required_argument, NULL, 'd'},
{0, 0, 0, 0},
};
while ((opt = getopt_long(argc, argv, optstr, options, &optidx)) != -1) {
switch (opt) {
case 'v':
verbose = 1;
break;
case 'd':
device = optarg;
break;
case 'h':
mbim_debug("-h Show this message\n");
mbim_debug("-v Verbose\n");
mbim_debug("-d [device] MBIM device\n");
return 0;
default:
mbim_debug("illegal argument\n");
return -1;
}
}
if (!device) {
mbim_debug("Missing parameter: device\n");
return -1;
}
while (1) {
int mbim_dev_fd = open(device, O_RDWR | O_NONBLOCK | O_NOCTTY);
if (mbim_dev_fd < 0) {
mbim_debug("cannot open mbim_device %s: %s\n", device, strerror(errno));
sleep(2);
continue;
}
mbim_debug ("mbim_dev_fd=%d\n", mbim_dev_fd);
memset(cm_clients, 0, sizeof(cm_clients));
mbim_send_open_msg(mbim_dev_fd, sizeof(cm_recv_buffer));
proxy_loop(mbim_dev_fd);
safe_close(mbim_dev_fd);
}
return -1;
}

View File

@ -1,700 +0,0 @@
/******************************************************************************
@file quectel-qmi-proxy.c
@brief The qmi proxy.
DESCRIPTION
Connectivity Management Tool for USB network adapter of Quectel wireless cellular modules.
INITIALIZATION AND SEQUENCING REQUIREMENTS
None.
---------------------------------------------------------------------------
Copyright (c) 2016 - 2023 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
Quectel Wireless Solution Proprietary and Confidential.
---------------------------------------------------------------------------
******************************************************************************/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <stddef.h>
#include <fcntl.h>
#include <pthread.h>
#include <poll.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <linux/un.h>
#include <linux/if.h>
#include <dirent.h>
#include <signal.h>
#include <inttypes.h>
#include "qendian.h"
#include "qlist.h"
#include "QCQMI.h"
#include "QCQCTL.h"
#include "QCQMUX.h"
#ifndef MIN
#define MIN(a, b) ((a) < (b)? (a): (b))
#endif
const char * get_time(void) {
static char time_buf[128];
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;
}
#define dprintf(fmt, args...) do { fprintf(stdout, "%s " fmt, get_time(), ##args); } 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)
typedef struct {
struct qlistnode qnode;
int 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;
int ClientFd;
unsigned AccessTime;
} QMI_PROXY_CONNECTION;
#ifdef QUECTEL_QMI_MERGE
#define MERGE_PACKET_IDENTITY 0x2c7c
#define MERGE_PACKET_VERSION 0x0001
#define MERGE_PACKET_MAX_PAYLOAD_SIZE 56
typedef struct __QMI_MSG_HEADER {
uint16_t idenity;
uint16_t version;
uint16_t cur_len;
uint16_t total_len;
} QMI_MSG_HEADER;
typedef struct __QMI_MSG_PACKET {
QMI_MSG_HEADER header;
uint16_t len;
char buf[4096];
} QMI_MSG_PACKET;
#endif
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 int verbose_debug = 0;
static int modem_reset_flag = 0;
static int qmi_sync_done = 0;
static uint8_t qmi_buf[4096];
static int send_qmi_to_cdc_wdm(PQCQMIMSG pQMI);
#ifdef QUECTEL_QMI_MERGE
static int merge_qmi_rsp_packet(void *buf, ssize_t *src_size) {
static QMI_MSG_PACKET s_QMIPacket;
QMI_MSG_HEADER *header = NULL;
ssize_t size = *src_size;
if((uint16_t)size < sizeof(QMI_MSG_HEADER))
return -1;
header = (QMI_MSG_HEADER *)buf;
if(le16toh(header->idenity) != MERGE_PACKET_IDENTITY || le16toh(header->version) != MERGE_PACKET_VERSION || le16toh(header->cur_len) > le16toh(header->total_len))
return -1;
if(le16toh(header->cur_len) == le16toh(header->total_len)) {
*src_size = le16toh(header->total_len);
memcpy(buf, buf + sizeof(QMI_MSG_HEADER), *src_size);
s_QMIPacket.len = 0;
return 0;
}
memcpy(s_QMIPacket.buf + s_QMIPacket.len, buf + sizeof(QMI_MSG_HEADER), le16toh(header->cur_len));
s_QMIPacket.len += le16toh(header->cur_len);
if (le16toh(header->cur_len) < MERGE_PACKET_MAX_PAYLOAD_SIZE || s_QMIPacket.len >= le16toh(header->total_len)) {
memcpy(buf, s_QMIPacket.buf, s_QMIPacket.len);
*src_size = s_QMIPacket.len;
s_QMIPacket.len = 0;
return 0;
}
return -1;
}
#endif
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) {
dprintf("bind %s errno: %d (%s)\n", name, errno, strerror(errno));
close(sockfd);
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, int clientDisconnect) {
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);
if (clientDisconnect) {
int size = 17;
QMI_PROXY_MSG *qmi_msg = malloc(sizeof(QMI_PROXY_MSG) + size);
PQCQMIMSG pQMI = &qmi_msg->qmi[0];
dprintf("xxx ClientFd=%d QMIType=%d ClientId=%d\n", qmi_con->ClientFd, qmi_client->QMIType, qmi_client->ClientId);
qlist_init(&qmi_msg->qnode);
qmi_msg->ClientFd = qmi_proxy_server_fd;
pQMI->QMIHdr.IFType = USB_CTL_MSG_TYPE_QMI;
pQMI->QMIHdr.Length = htole16(16);
pQMI->QMIHdr.CtlFlags = 0x00;
pQMI->QMIHdr.QMIType = QMUX_TYPE_CTL;
pQMI->QMIHdr.ClientId= 0x00;
pQMI->CTLMsg.ReleaseClientIdReq.CtlFlags = QMICTL_FLAG_REQUEST;
pQMI->CTLMsg.ReleaseClientIdReq.TransactionId = 255;
pQMI->CTLMsg.ReleaseClientIdReq.QMICTLType = htole16(QMICTL_RELEASE_CLIENT_ID_REQ);
pQMI->CTLMsg.ReleaseClientIdReq.Length = htole16(5);
pQMI->CTLMsg.ReleaseClientIdReq.TLVType = QCTLV_TYPE_REQUIRED_PARAMETER;
pQMI->CTLMsg.ReleaseClientIdReq.TLVLength = htole16(2);
pQMI->CTLMsg.ReleaseClientIdReq.QMIType = qmi_client->QMIType;
pQMI->CTLMsg.ReleaseClientIdReq.ClientId = qmi_client->ClientId;
if (qlist_empty(&qmi_proxy_ctl_msg))
send_qmi_to_cdc_wdm(pQMI);
qlist_add_tail(&qmi_proxy_ctl_msg, &qmi_msg->qnode);
}
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 void dump_qmi(PQCQMIMSG pQMI, int fd, const char flag)
{
if (verbose_debug)
{
unsigned i;
unsigned size = le16toh(pQMI->QMIHdr.Length) + 1;
char buf[128];
int cnt = 0;
cnt += snprintf(buf + cnt, sizeof(buf) - cnt, "%c %d %u: ", flag, fd, size);
for (i = 0; i < size && i < 24; i++)
cnt += snprintf(buf + cnt, sizeof(buf) - cnt, "%02x ", ((uint8_t *)pQMI)[i]);
dprintf("%s\n", buf)
}
}
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 == -1 && errno == EINTR && qmi_proxy_quit == 0);
if (pollfds[0].revents & POLLOUT) {
ssize_t size = le16toh(pQMI->QMIHdr.Length) + 1;
ret = write(cdc_wdm_fd, pQMI, size);
dump_qmi(pQMI, cdc_wdm_fd, 'w');
}
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 == -1 && errno == EINTR && qmi_proxy_quit == 0);
if (pollfds[0].revents & POLLOUT) {
ssize_t size = le16toh(pQMI->QMIHdr.Length) + 1;
ret = write(clientFd, pQMI, size);
dump_qmi(pQMI, clientFd, 'w');
}
return ret;
}
static void recv_qmi_from_dev(PQCQMIMSG pQMI) {
struct qlistnode *con_node, *client_node;
if (qmi_proxy_server_fd == -1) {
qmi_sync_done = 1;
}
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);
if (qmi_msg->qmi[0].CTLMsg.QMICTLMsgHdrRsp.TransactionId != pQMI->CTLMsg.QMICTLMsgHdrRsp.TransactionId
|| qmi_msg->qmi[0].CTLMsg.QMICTLMsgHdrRsp.QMICTLType != pQMI->CTLMsg.QMICTLMsgHdrRsp.QMICTLType) {
dprintf("ERROR: ctl rsp tid:%d, type:%d - ctl req %d, %d\n",
pQMI->CTLMsg.QMICTLMsgHdrRsp.TransactionId, pQMI->CTLMsg.QMICTLMsgHdrRsp.QMICTLType,
qmi_msg->qmi[0].CTLMsg.QMICTLMsgHdrRsp.TransactionId, qmi_msg->qmi[0].CTLMsg.QMICTLMsgHdrRsp.QMICTLType);
}
else if (qmi_msg->ClientFd == qmi_proxy_server_fd) {
if (le16toh(pQMI->CTLMsg.QMICTLMsgHdrRsp.QMICTLType) == QMICTL_RELEASE_CLIENT_ID_RESP) {
dprintf("--- ClientFd=%d QMIType=%d ClientId=%d\n", qmi_proxy_server_fd,
pQMI->CTLMsg.ReleaseClientIdRsp.QMIType, pQMI->CTLMsg.ReleaseClientIdRsp.ClientId);
}
}
else {
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 (le16toh(pQMI->CTLMsg.QMICTLMsgHdrRsp.QMICTLType) == QMICTL_GET_CLIENT_ID_RESP) {
get_client_id(qmi_con, &pQMI->CTLMsg.GetClientIdRsp);
}
else if (le16toh(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);
send_qmi_to_cdc_wdm(qmi_msg->qmi);
}
}
}
else if (pQMI->QMIHdr.QMIType == QMICTL_CTL_FLAG_IND) {
if (le16toh(pQMI->CTLMsg.QMICTLMsgHdrRsp.QMICTLType) == QMICTL_REVOKE_CLIENT_ID_IND) {
modem_reset_flag = 1;
}
}
}
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 recv_qmi_from_client(PQCQMIMSG pQMI, unsigned size, int clientfd) {
if (qmi_proxy_server_fd == -1)
return -1;
if (pQMI->QMIHdr.QMIType == QMUX_TYPE_CTL) {
QMI_PROXY_MSG *qmi_msg;
if (pQMI->CTLMsg.QMICTLMsgHdr.QMICTLType == QMICTL_SYNC_REQ) {
dprintf("do not allow client send QMICTL_SYNC_REQ\n");
return 0;
}
qmi_msg = malloc(sizeof(QMI_PROXY_MSG) + size);
qlist_init(&qmi_msg->qnode);
qmi_msg->ClientFd = clientfd;
memcpy(qmi_msg->qmi, pQMI, size);
if (qlist_empty(&qmi_proxy_ctl_msg))
send_qmi_to_cdc_wdm(pQMI);
qlist_add_tail(&qmi_proxy_ctl_msg, &qmi_msg->qnode);
}
else {
send_qmi_to_cdc_wdm(pQMI);
}
return 0;
}
static int qmi_proxy_init(unsigned retry) {
unsigned i;
QCQMIMSG _QMI;
PQCQMIMSG pQMI = &_QMI;
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;
qmi_sync_done = 0;
for (i = 0; i < retry; i++) {
pQMI->CTLMsg.SyncReq.TransactionId = i+1;
pQMI->CTLMsg.SyncReq.QMICTLType = htole16(QMICTL_SYNC_REQ);
pQMI->CTLMsg.SyncReq.Length = htole16(0);
pQMI->QMIHdr.Length =
htole16(le16toh(pQMI->CTLMsg.QMICTLMsgHdr.Length) + sizeof(QCQMI_HDR) + sizeof(QCQMICTL_MSG_HDR) - 1);
if (send_qmi_to_cdc_wdm(pQMI) <= 0)
break;
sleep(1);
if (qmi_sync_done)
break;
}
dprintf("%s %s\n", __func__, qmi_sync_done ? "succful" : "fail");
return qmi_sync_done ? 0 : -1;
}
static void *qmi_proxy_loop(void *param)
{
PQCQMIMSG pQMI = (PQCQMIMSG)qmi_buf;
struct qlistnode *con_node;
QMI_PROXY_CONNECTION *qmi_con;
(void)param;
dprintf("%s enter thread_id %p\n", __func__, (void *)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;
}
#if 0
dprintf("poll ");
for (ne = 0; ne < nevents; ne++) {
dprintf("%d ", pollfds[ne].fd);
}
dprintf("\n");
#endif
do {
//ret = poll(pollfds, nevents, -1);
ret = poll(pollfds, nevents, (qmi_proxy_server_fd > 0) ? -1 : 200);
} while (ret == -1 && 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, 1);
}
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 (nreads <= 0) {
dprintf("%s read=%d errno: %d (%s)\n", __func__, (int)nreads, errno, strerror(errno));
goto qmi_proxy_loop_exit;
}
#ifdef QUECTEL_QMI_MERGE
if(merge_qmi_rsp_packet(pQMI, &nreads))
continue;
#endif
if (nreads != (le16toh(pQMI->QMIHdr.Length) + 1)) {
dprintf("%s nreads=%d, pQCQMI->QMIHdr.Length = %d\n", __func__, (int)nreads, le16toh(pQMI->QMIHdr.Length));
continue;
}
dump_qmi(pQMI, fd, 'r');
recv_qmi_from_dev(pQMI);
if (modem_reset_flag)
goto qmi_proxy_loop_exit;
}
else {
nreads = read(fd, pQMI, sizeof(qmi_buf));
if (nreads <= 0) {
dprintf("%s read=%d errno: %d (%s)", __func__, (int)nreads, errno, strerror(errno));
cleanup_qmi_connection(fd, 1);
break;
}
if (nreads != (le16toh(pQMI->QMIHdr.Length) + 1)) {
dprintf("%s nreads=%d, pQCQMI->QMIHdr.Length = %d\n", __func__, (int)nreads, le16toh(pQMI->QMIHdr.Length));
continue;
}
dump_qmi(pQMI, fd, 'r');
recv_qmi_from_client(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, 0);
}
dprintf("%s exit, thread_id %p\n", __func__, (void *)pthread_self());
return NULL;
}
static void usage(void) {
dprintf(" -d <device_name> A valid qmi device\n"
" default /dev/cdc-wdm0, but cdc-wdm0 may be invalid\n"
" -i <netcard_name> netcard name\n"
" -v Will show all details\n");
}
static void sig_action(int sig) {
if (qmi_proxy_quit++ == 0) {
if (thread_id)
pthread_kill(thread_id, sig);
}
}
int main(int argc, char *argv[]) {
int opt;
char cdc_wdm[32+1] = "/dev/cdc-wdm0";
char servername[64] = {0};
optind = 1;
signal(SIGINT, sig_action);
while ( -1 != (opt = getopt(argc, argv, "d:i:vh"))) {
switch (opt) {
case 'd':
strcpy(cdc_wdm, optarg);
break;
case 'v':
verbose_debug = 1;
break;
default:
usage();
return 0;
}
}
sprintf(servername, "quectel-qmi-proxy%c", cdc_wdm[strlen(cdc_wdm)-1]);
dprintf("Will use cdc-wdm='%s', proxy='%s'\n", cdc_wdm, servername);
while (qmi_proxy_quit == 0) {
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)\n", cdc_wdm, errno, strerror(errno));
sleep(3);
continue;
}
cfmakenoblock(cdc_wdm_fd);
/* no qmi_proxy_loop lives, create one */
pthread_create(&thread_id, NULL, qmi_proxy_loop, NULL);
if (qmi_proxy_init(60) == 0) {
qmi_proxy_server_fd = create_local_server(servername);
dprintf("qmi_proxy_server_fd = %d\n", qmi_proxy_server_fd);
if (qmi_proxy_server_fd == -1) {
dprintf("Failed to create %s, errno: %d (%s)\n", servername, errno, strerror(errno));
pthread_cancel(thread_id);
}
}
else {
pthread_cancel(thread_id);
}
pthread_join(thread_id, NULL);
thread_id = 0;
if (qmi_proxy_server_fd != -1) {
dprintf("close server %s\n", servername);
close(qmi_proxy_server_fd);
qmi_proxy_server_fd = -1;
}
close(cdc_wdm_fd);
cdc_wdm_fd = -1;
if (qmi_proxy_quit == 0)
sleep(modem_reset_flag ? 30 : 3);
modem_reset_flag = 0;
}
return 0;
}

View File

@ -1,894 +0,0 @@
/******************************************************************************
@file quectel-qrtr-proxy.c
@brief The qrtr proxy.
DESCRIPTION
Connectivity Management Tool for USB/PCIE network adapter of Quectel wireless cellular modules.
INITIALIZATION AND SEQUENCING REQUIREMENTS
None.
---------------------------------------------------------------------------
Copyright (c) 2016 - 2023 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
Quectel Wireless Solution Proprietary and Confidential.
---------------------------------------------------------------------------
******************************************************************************/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <stddef.h>
#include <fcntl.h>
#include <pthread.h>
#include <poll.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <linux/un.h>
#include <linux/if.h>
#include <dirent.h>
#include <signal.h>
#include <inttypes.h>
#include <linux/socket.h>
#include "qrtr.h"
#include "qendian.h"
#include "qlist.h"
#include "QCQMI.h"
#include "QCQCTL.h"
#include "QCQMUX.h"
static const char * get_time(void) {
static char time_buf[128];
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;
}
#define dprintf(fmt, args...) do { fprintf(stdout, "%s " fmt, get_time(), ##args); } 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 align_4(_len) (((_len) + 3) & ~3)
typedef struct {
struct qlistnode qnode;
int ClientFd;
QCQMIMSG qrtr[0];
} QRTR_PROXY_MSG;
typedef struct {
struct qlistnode qnode;
uint8_t QMIType;
uint8_t ClientId;
uint32_t node_id;
uint32_t port_id;
unsigned AccessTime;
} QRTR_PROXY_CLINET;
typedef struct {
struct qlistnode qnode;
struct qlistnode client_qnode;
int ClientFd;
unsigned AccessTime;
} QRTR_PROXY_CONNECTION;
typedef struct {
struct qlistnode qnode;
uint32_t service;
uint32_t version;
uint32_t instance;
uint32_t node;
uint32_t port;
__le32 src_node_id;
__le32 src_port_id;
} QRTR_SERVICE;
static int qrtr_proxy_quit = 0;
static pthread_t thread_id = 0;
static int cdc_wdm_fd = -1;
static int qrtr_proxy_server_fd = -1;
static struct qlistnode qrtr_proxy_connection;
static struct qlistnode qrtr_server_list;
static int verbose_debug = 0;
static uint32_t node_modem = 3; //IPQ ~ 3, QCM ~ 0
static uint32_t node_myself = 1;
static QRTR_SERVICE *find_qrtr_service(uint8_t QMIType)
{
struct qlistnode *node;
qlist_for_each (node, &qrtr_server_list) {
QRTR_SERVICE *srv = qnode_to_item(node, QRTR_SERVICE, qnode);
if (srv->service == QMIType)
return srv;
}
return NULL;
}
static uint8_t client_bitmap[0xf0];
static uint8_t port_bitmap[0xff0];
static int alloc_client_id(void) {
int id = 1;
for (id = 1; id < (int)sizeof(client_bitmap); id++) {
if (client_bitmap[id] == 0) {
client_bitmap[id] = id;
return id;
}
}
dprintf("NOT find %s()\n", __func__);
return 0;
}
static void free_client_id(int id) {
if (id < (int)sizeof(client_bitmap) && client_bitmap[id] == id) {
client_bitmap[id] = 0;
return;
}
dprintf("NOT find %s(id=%d)\n", __func__, id);
}
static int alloc_port_id(void) {
int id = 1;
for (id = 1; id < (int)sizeof(port_bitmap); id++) {
if (port_bitmap[id] == 0) {
port_bitmap[id] = id;
return id;
}
}
dprintf("NOT find %s()\n", __func__);
return 0;
}
static void free_port_id(int id) {
if (id < (int)sizeof(port_bitmap) && port_bitmap[id] == id) {
port_bitmap[id] = 0;
return;
}
dprintf("NOT find %s(id=%d)\n", __func__, id);
}
static void dump_qrtr(void *buf, size_t len, char flag)
{
size_t i;
static char printf_buf[1024];
int cnt = 0, limit=1024;
unsigned char *d = (unsigned char *)buf;
struct qrtr_hdr_v1 *hdr = (struct qrtr_hdr_v1 *)buf;
const char *ctrl_pkt_strings[] = {
[QRTR_TYPE_DATA] = "data",
[QRTR_TYPE_HELLO] = "hello",
[QRTR_TYPE_BYE] = "bye",
[QRTR_TYPE_NEW_SERVER] = "new-server",
[QRTR_TYPE_DEL_SERVER] = "del-server",
[QRTR_TYPE_DEL_CLIENT] = "del-client",
[QRTR_TYPE_RESUME_TX] = "resume-tx",
[QRTR_TYPE_EXIT] = "exit",
[QRTR_TYPE_PING] = "ping",
[QRTR_TYPE_NEW_LOOKUP] = "new-lookup",
[QRTR_TYPE_DEL_LOOKUP] = "del-lookup",
};
for (i = 0; i < len && i < 64; i++) {
if (i%4 == 0)
cnt += snprintf(printf_buf+cnt, limit-cnt, " ");
cnt += snprintf(printf_buf+cnt, limit-cnt, "%02x", d[i]);
}
dprintf("%s\n", printf_buf);
dprintf("%c ver=%d, type=%d(%s), %x,%x -> %x,%x, confirm_rx=%d, size=%u\n",
flag,
le32toh(hdr->version), le32toh(hdr->type), ctrl_pkt_strings[le32toh(hdr->type)],
le32toh(hdr->src_node_id), le32toh(hdr->src_port_id), le32toh(hdr->dst_node_id), le32toh(hdr->dst_port_id),
le32toh(hdr->confirm_rx), le32toh(hdr->size));
}
static int send_qmi_to_client(PQCQMIMSG pQMI, int fd) {
struct pollfd pollfds[]= {{fd, POLLOUT, 0}};
ssize_t ret = 0;
ssize_t size = le16toh(pQMI->QMIHdr.Length) + 1;
do {
ret = poll(pollfds, sizeof(pollfds)/sizeof(pollfds[0]), 5000);
} while (ret == -1 && errno == EINTR && qrtr_proxy_quit == 0);
if (pollfds[0].revents & POLLOUT) {
ret = write(fd, pQMI, size);
}
return ret == size ? 0 : -1;
}
static int send_qrtr_to_dev(struct qrtr_hdr_v1 *hdr, int fd) {
struct pollfd pollfds[]= {{fd, POLLOUT, 0}};
ssize_t ret = 0;
ssize_t size = align_4(le32toh(hdr->size) + sizeof(*hdr));
do {
ret = poll(pollfds, sizeof(pollfds)/sizeof(pollfds[0]), 5000);
} while (ret == -1 && errno == EINTR && qrtr_proxy_quit == 0);
if (pollfds[0].revents & POLLOUT) {
ret = write(fd, hdr, size);
}
return ret == size ? 0 : -1;
}
static int qrtr_node_enqueue(const void *data, size_t len,
int type, struct sockaddr_qrtr *from,
struct sockaddr_qrtr *to, unsigned int confirm_rx)
{
int rc = -1;
size_t size = sizeof(struct qrtr_hdr_v1) + len;
struct qrtr_hdr_v1 *hdr = (struct qrtr_hdr_v1 *)malloc(align_4(size));
if (hdr) {
hdr->version = htole32(QRTR_PROTO_VER_1);
hdr->type = htole32(type);
hdr->src_node_id = htole32(from->sq_node);
hdr->src_port_id = htole32(from->sq_port);
hdr->dst_node_id = htole32(to->sq_node);
hdr->dst_port_id = htole32(to->sq_port);
hdr->size = htole32(len);
hdr->confirm_rx = htole32(!!confirm_rx);
memcpy(hdr + 1, data, len);
dump_qrtr(hdr, size, '>');
send_qrtr_to_dev(hdr, cdc_wdm_fd);
free(hdr);
}
return rc;
}
static int send_ctrl_hello(__u32 sq_node, __u32 sq_port)
{
struct qrtr_ctrl_pkt pkt;
int rc;
struct sockaddr_qrtr to = {AF_QIPCRTR, sq_node, sq_port};
struct sockaddr_qrtr from = {AF_QIPCRTR, node_myself, QRTR_PORT_CTRL};
memset(&pkt, 0, sizeof(pkt));
pkt.cmd = htole32(QRTR_TYPE_HELLO);
rc = qrtr_node_enqueue(&pkt, sizeof(pkt), QRTR_TYPE_HELLO, &from, &to, 0);
if (rc < 0)
return rc;
return 0;
}
static int ctrl_cmd_del_client(__u32 sq_node, __u32 sq_port, uint8_t QMIType)
{
struct qrtr_ctrl_pkt pkt;
int rc;
struct sockaddr_qrtr to = {AF_QIPCRTR, QRTR_NODE_BCAST, QRTR_PORT_CTRL};
struct sockaddr_qrtr from = {AF_QIPCRTR, sq_node, sq_port};
QRTR_SERVICE *srv = find_qrtr_service(QMIType);
if (srv) {
to.sq_node = srv->src_node_id;
}
memset(&pkt, 0, sizeof(pkt));
pkt.cmd = htole32(QRTR_TYPE_DEL_CLIENT);
pkt.client.node = htole32(sq_node);
pkt.client.port = htole32(sq_port);
rc = qrtr_node_enqueue(&pkt, sizeof(pkt), QRTR_TYPE_DATA, &from, &to, 0);
if (rc < 0)
return rc;
return 0;
}
static void handle_server_change(struct qrtr_hdr_v1 *hdr) {
struct qrtr_ctrl_pkt *pkt = (struct qrtr_ctrl_pkt *)(hdr + 1);
QRTR_SERVICE *s;
dprintf ("[qrtr] %s server on %u:%u(%u:%u) -> service %u, instance %x\n",
QRTR_TYPE_NEW_SERVER == hdr->type ? "add" : "remove",
le32toh(pkt->server.node), le32toh(pkt->server.port),
le32toh(hdr->src_node_id), le32toh(hdr->src_port_id),
le32toh(pkt->server.service), le32toh(pkt->server.instance));
if (le32toh(pkt->server.node) != node_modem) {
return; //we only care modem
}
s = (QRTR_SERVICE *)malloc(sizeof(QRTR_SERVICE));
if (!s)
return;
qlist_init(&s->qnode);
s->service = le32toh(pkt->server.service);
s->version = le32toh(pkt->server.instance) & 0xff;
s->instance = le32toh(pkt->server.instance) >> 8;
s->node = le32toh(pkt->server.node);
s->port = le32toh(pkt->server.port);
s->src_node_id = le32toh(hdr->src_node_id);
s->src_port_id = le32toh(hdr->src_port_id);
if (QRTR_TYPE_NEW_SERVER == hdr->type) {
qlist_add_tail(&qrtr_server_list, &s->qnode);
}
else if (QRTR_TYPE_DEL_SERVER == hdr->type) {
qlist_remove(&s->qnode);
}
}
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("bind %s errno: %d (%s)\n", name, errno, strerror(errno));
return -1;
}
dprintf("local server: %s sockfd = %d\n", name, sockfd);
cfmakenoblock(sockfd);
listen(sockfd, 1);
return sockfd;
}
static uint8_t alloc_qrtr_client_id(QRTR_PROXY_CONNECTION *qrtr_con, uint8_t QMIType) {
QRTR_PROXY_CLINET *qrtr_client = (QRTR_PROXY_CLINET *)malloc(sizeof(QRTR_PROXY_CLINET));
qlist_init(&qrtr_client->qnode);
qrtr_client->QMIType = QMIType;
qrtr_client->ClientId = alloc_client_id();
qrtr_client->node_id = 1;
qrtr_client->port_id = alloc_port_id();
qrtr_client->AccessTime = 0;
dprintf("+++ ClientFd=%d QMIType=%d ClientId=%d, node_id=%d, port_id=%d\n",
qrtr_con->ClientFd, qrtr_client->QMIType, qrtr_client->ClientId,
qrtr_client->node_id, qrtr_client->port_id);
qlist_add_tail(&qrtr_con->client_qnode, &qrtr_client->qnode);
return qrtr_client->ClientId;
}
static void release_qrtr_client_id(QRTR_PROXY_CONNECTION *qrtr_con, uint8_t QMIType, uint8_t ClientId) {
struct qlistnode *client_node;
int find = 0;
qlist_for_each (client_node, &qrtr_con->client_qnode) {
QRTR_PROXY_CLINET *qrtr_client = qnode_to_item(client_node, QRTR_PROXY_CLINET, qnode);
if (QMIType == qrtr_client->QMIType && ClientId == qrtr_client->ClientId) {
dprintf("--- ClientFd=%d QMIType=%d ClientId=%d, node_id=%d, port_id=%d\n",
qrtr_con->ClientFd, qrtr_client->QMIType, qrtr_client->ClientId,
qrtr_client->node_id, qrtr_client->port_id);
ctrl_cmd_del_client(qrtr_client->node_id, qrtr_client->port_id, qrtr_client->QMIType);
free_client_id(qrtr_client->ClientId);
free_port_id(qrtr_client->port_id);
qlist_remove(&qrtr_client->qnode);
free(qrtr_client);
find++;
break;
}
}
if (!find) {
dprintf("NOT find on %s(ClientFd=%d, QMIType=%d, ClientId=%d)\n",
__func__, qrtr_con->ClientFd, QMIType, ClientId);
}
}
static void accept_qrtr_connection(int serverfd) {
int clientfd = -1;
unsigned char addr[128];
socklen_t alen = sizeof(addr);
QRTR_PROXY_CONNECTION *qrtr_con;
clientfd = accept(serverfd, (struct sockaddr *)addr, &alen);
qrtr_con = (QRTR_PROXY_CONNECTION *)malloc(sizeof(QRTR_PROXY_CONNECTION));
if (qrtr_con) {
qlist_init(&qrtr_con->qnode);
qlist_init(&qrtr_con->client_qnode);
qrtr_con->ClientFd= clientfd;
qrtr_con->AccessTime = 0;
dprintf("+++ ClientFd=%d\n", qrtr_con->ClientFd);
qlist_add_tail(&qrtr_proxy_connection, &qrtr_con->qnode);
}
cfmakenoblock(clientfd);
}
static void cleanup_qrtr_connection(int clientfd) {
struct qlistnode *con_node;
int find = 0;
qlist_for_each(con_node, &qrtr_proxy_connection) {
QRTR_PROXY_CONNECTION *qrtr_con = qnode_to_item(con_node, QRTR_PROXY_CONNECTION, qnode);
if (qrtr_con->ClientFd == clientfd) {
while (!qlist_empty(&qrtr_con->client_qnode)) {
QRTR_PROXY_CLINET *qrtr_client = qnode_to_item(qlist_head(&qrtr_con->client_qnode), QRTR_PROXY_CLINET, qnode);
release_qrtr_client_id(qrtr_con, qrtr_client->QMIType, qrtr_client->ClientId);
}
dprintf("--- ClientFd=%d\n", qrtr_con->ClientFd);
close(qrtr_con->ClientFd);
qlist_remove(&qrtr_con->qnode);
free(qrtr_con);
find = 1;
break;
}
}
if (!find) {
dprintf("NOT find on %s(ClientFd=%d)\n", __func__, clientfd);
}
}
static void recv_qrtr_from_dev(struct qrtr_hdr_v1 *hdr) {
int find = 0;
uint32_t type = le32toh(hdr->type);
if (type == QRTR_TYPE_HELLO) {
send_ctrl_hello(le32toh(hdr->src_node_id), le32toh(hdr->src_port_id));
find++;
}
else if (type == QRTR_TYPE_NEW_SERVER || type == QRTR_TYPE_DEL_SERVER) {
handle_server_change(hdr);
find++;
}
else if (type == QRTR_TYPE_DATA) {
struct qlistnode *con_node, *client_node;
qlist_for_each(con_node, &qrtr_proxy_connection) {
QRTR_PROXY_CONNECTION *qrtr_con = qnode_to_item(con_node, QRTR_PROXY_CONNECTION, qnode);
qlist_for_each(client_node, &qrtr_con->client_qnode) {
QRTR_PROXY_CLINET *qrtr_client = qnode_to_item(client_node, QRTR_PROXY_CLINET, qnode);
if (qrtr_client->node_id == le32toh(hdr->dst_node_id) && qrtr_client->port_id == le32toh(hdr->dst_port_id)) {
PQCQMIMSG pQMI = (PQCQMIMSG)malloc(hdr->size + sizeof(QCQMI_HDR));
if (pQMI) {
pQMI->QMIHdr.IFType = USB_CTL_MSG_TYPE_QMI;
pQMI->QMIHdr.Length = htole16(hdr->size + sizeof(QCQMI_HDR) - 1);
pQMI->QMIHdr.CtlFlags = 0x00;
pQMI->QMIHdr.QMIType = qrtr_client->QMIType;
pQMI->QMIHdr.ClientId = qrtr_client->ClientId;
memcpy(&pQMI->MUXMsg, hdr + 1, hdr->size);
send_qmi_to_client(pQMI, qrtr_con->ClientFd);
free(pQMI);
find++;
}
}
}
}
if (hdr->confirm_rx) {
struct qrtr_ctrl_pkt pkt;
struct sockaddr_qrtr from = {AF_QIPCRTR, le32toh(hdr->dst_node_id), le32toh(hdr->dst_port_id)};
struct sockaddr_qrtr to = {AF_QIPCRTR, le32toh(hdr->src_node_id), le32toh(hdr->src_port_id)};
memset(&pkt, 0, sizeof(pkt));
pkt.cmd = htole32(QRTR_TYPE_RESUME_TX);
pkt.client.node = hdr->dst_node_id;
pkt.client.port = hdr->dst_port_id;
qrtr_node_enqueue(&pkt, sizeof(pkt), QRTR_TYPE_RESUME_TX, &from, &to, 0);
}
}
else if (type == QRTR_TYPE_RESUME_TX) {
}
if (!find) {
dprintf("NOT find on %s()\n", __func__);
}
}
static int recv_qmi_from_client(PQCQMIMSG pQMI, int clientfd) {
QRTR_PROXY_CONNECTION *qrtr_con;
struct qlistnode *con_node, *client_node;
int find = 0;
qlist_for_each(con_node, &qrtr_proxy_connection) {
qrtr_con = qnode_to_item(con_node, QRTR_PROXY_CONNECTION, qnode);
if (qrtr_con->ClientFd == clientfd)
break;
qrtr_con = NULL;
}
if (!qrtr_con) {
return -1;
}
if (le16toh(pQMI->QMIHdr.QMIType) == QMUX_TYPE_CTL) {
if (pQMI->CTLMsg.QMICTLMsgHdr.QMICTLType == QMICTL_SYNC_REQ) {
dprintf("do not allow client send QMICTL_SYNC_REQ\n");
return 0;
}
else if (le16toh(pQMI->CTLMsg.QMICTLMsgHdr.QMICTLType) == QMICTL_GET_CLIENT_ID_REQ) {
uint8_t QMIType = pQMI->CTLMsg.GetClientIdReq.QMIType;
PQCQMIMSG pRsp = (PQCQMIMSG)malloc(256);
if (pRsp) {
uint8_t ClientId = 0;
if (find_qrtr_service(QMIType)) {
ClientId = alloc_qrtr_client_id(qrtr_con, QMIType);
}
pRsp->QMIHdr.IFType = USB_CTL_MSG_TYPE_QMI;
pRsp->QMIHdr.Length = htole16(sizeof(pRsp->CTLMsg.GetClientIdRsp) + sizeof(pRsp->QMIHdr) - 1);
pRsp->QMIHdr.CtlFlags = 0x00;
pRsp->QMIHdr.QMIType = QMUX_TYPE_CTL;
pRsp->QMIHdr.ClientId = 0;
pRsp->CTLMsg.QMICTLMsgHdrRsp.CtlFlags = QMICTL_FLAG_RESPONSE;
pRsp->CTLMsg.QMICTLMsgHdrRsp.TransactionId = pQMI->CTLMsg.QMICTLMsgHdr.TransactionId;
pRsp->CTLMsg.QMICTLMsgHdrRsp.QMICTLType = pQMI->CTLMsg.QMICTLMsgHdr.QMICTLType;
pRsp->CTLMsg.QMICTLMsgHdrRsp.Length = htole16(sizeof(pRsp->CTLMsg.GetClientIdRsp) - sizeof(pRsp->CTLMsg.QMICTLMsgHdr));
pRsp->CTLMsg.QMICTLMsgHdrRsp.TLVType = QCTLV_TYPE_RESULT_CODE;
pRsp->CTLMsg.QMICTLMsgHdrRsp.TLVLength = htole16(4);
pRsp->CTLMsg.QMICTLMsgHdrRsp.QMUXResult = htole16(ClientId ? 0 : QMI_RESULT_FAILURE);
pRsp->CTLMsg.QMICTLMsgHdrRsp.QMUXError = htole16(ClientId ? 0 : QMI_ERR_INTERNAL);
pRsp->CTLMsg.GetClientIdRsp.TLV2Type = QCTLV_TYPE_REQUIRED_PARAMETER;
pRsp->CTLMsg.GetClientIdRsp.TLV2Length = htole16(2);
pRsp->CTLMsg.GetClientIdRsp.QMIType = QMIType;
pRsp->CTLMsg.GetClientIdRsp.ClientId = ClientId;
send_qmi_to_client(pRsp, clientfd);
free(pRsp);
find++;
}
}
else if (le16toh(pQMI->CTLMsg.QMICTLMsgHdr.QMICTLType) == QMICTL_RELEASE_CLIENT_ID_REQ) {
PQCQMIMSG pRsp = (PQCQMIMSG)malloc(256);
release_qrtr_client_id(qrtr_con, pQMI->CTLMsg.ReleaseClientIdReq.QMIType, pQMI->CTLMsg.ReleaseClientIdReq.ClientId);
if (pRsp) {
pRsp->QMIHdr.IFType = USB_CTL_MSG_TYPE_QMI;
pRsp->QMIHdr.Length = htole16(sizeof(pRsp->CTLMsg.ReleaseClientIdRsp) + sizeof(pRsp->QMIHdr) - 1);
pRsp->QMIHdr.CtlFlags = 0x00;
pRsp->QMIHdr.QMIType = QMUX_TYPE_CTL;
pRsp->QMIHdr.ClientId = 0;
pRsp->CTLMsg.QMICTLMsgHdrRsp.CtlFlags = QMICTL_FLAG_RESPONSE;
pRsp->CTLMsg.QMICTLMsgHdrRsp.TransactionId = pQMI->CTLMsg.QMICTLMsgHdr.TransactionId;
pRsp->CTLMsg.QMICTLMsgHdrRsp.QMICTLType = pQMI->CTLMsg.QMICTLMsgHdr.QMICTLType;
pRsp->CTLMsg.QMICTLMsgHdrRsp.Length = htole16(sizeof(pRsp->CTLMsg.ReleaseClientIdRsp) - sizeof(pRsp->CTLMsg.QMICTLMsgHdr));
pRsp->CTLMsg.QMICTLMsgHdrRsp.TLVType = QCTLV_TYPE_RESULT_CODE;
pRsp->CTLMsg.QMICTLMsgHdrRsp.TLVLength = htole16(4);
pRsp->CTLMsg.QMICTLMsgHdrRsp.QMUXResult = htole16(0);
pRsp->CTLMsg.QMICTLMsgHdrRsp.QMUXError = htole16(0);
pRsp->CTLMsg.ReleaseClientIdRsp.TLV2Type = QCTLV_TYPE_REQUIRED_PARAMETER;
pRsp->CTLMsg.ReleaseClientIdRsp.TLV2Length = htole16(2);
pRsp->CTLMsg.ReleaseClientIdRsp.QMIType = pQMI->CTLMsg.ReleaseClientIdReq.QMIType;
pRsp->CTLMsg.ReleaseClientIdRsp.ClientId = pQMI->CTLMsg.ReleaseClientIdReq.ClientId;
send_qmi_to_client(pRsp, clientfd);
free(pRsp);
find++;
}
}
else if (le16toh(pQMI->CTLMsg.QMICTLMsgHdr.QMICTLType) == QMICTL_GET_VERSION_REQ) {
PQCQMIMSG pRsp = (PQCQMIMSG)malloc(256);
if (pRsp) {
pRsp->QMIHdr.IFType = USB_CTL_MSG_TYPE_QMI;
pRsp->QMIHdr.Length = htole16(sizeof(pRsp->CTLMsg.GetVersionRsp) + sizeof(pRsp->QMIHdr) - 1);
pRsp->QMIHdr.CtlFlags = 0x00;
pRsp->QMIHdr.QMIType = QMUX_TYPE_CTL;
pRsp->QMIHdr.ClientId = 0;
pRsp->CTLMsg.QMICTLMsgHdrRsp.CtlFlags = QMICTL_FLAG_RESPONSE;
pRsp->CTLMsg.QMICTLMsgHdrRsp.TransactionId = pQMI->CTLMsg.QMICTLMsgHdr.TransactionId;
pRsp->CTLMsg.QMICTLMsgHdrRsp.QMICTLType = pQMI->CTLMsg.QMICTLMsgHdr.QMICTLType;
pRsp->CTLMsg.QMICTLMsgHdrRsp.Length = htole16(sizeof(pRsp->CTLMsg.GetVersionRsp) - sizeof(pRsp->CTLMsg.QMICTLMsgHdr));
pRsp->CTLMsg.QMICTLMsgHdrRsp.TLVType = QCTLV_TYPE_RESULT_CODE;
pRsp->CTLMsg.QMICTLMsgHdrRsp.TLVLength = htole16(4);
pRsp->CTLMsg.QMICTLMsgHdrRsp.QMUXResult = htole16(0);
pRsp->CTLMsg.QMICTLMsgHdrRsp.QMUXError = htole16(0);
pRsp->CTLMsg.GetVersionRsp.TLV2Type = QCTLV_TYPE_REQUIRED_PARAMETER;
pRsp->CTLMsg.GetVersionRsp.TLV2Length = htole16(1);
pRsp->CTLMsg.GetVersionRsp.NumElements = 0;
send_qmi_to_client(pRsp, clientfd);
free(pRsp);
find++;
}
}
}
else {
qlist_for_each (client_node, &qrtr_con->client_qnode) {
QRTR_PROXY_CLINET *qrtr_client = qnode_to_item(client_node, QRTR_PROXY_CLINET, qnode);
if (pQMI->QMIHdr.QMIType == qrtr_client->QMIType && pQMI->QMIHdr.ClientId == qrtr_client->ClientId) {
QRTR_SERVICE *srv = find_qrtr_service(pQMI->QMIHdr.QMIType);
if (srv && srv->service) {
struct sockaddr_qrtr from = {AF_QIPCRTR, qrtr_client->node_id, qrtr_client->port_id};
struct sockaddr_qrtr to = {AF_QIPCRTR, srv->node, srv->port};
qrtr_node_enqueue(&pQMI->MUXMsg, le16toh(pQMI->QMIHdr.Length) + 1 - sizeof(QCQMI_HDR),
QRTR_TYPE_DATA, &from, &to, 0);
find++;
}
break;
}
}
}
if (!find) {
dprintf("NOT find on %s()\n", __func__);
}
return 0;
}
static int qrtr_proxy_init(void) {
unsigned i;
int qrtr_sync_done = 0;
dprintf("%s enter\n", __func__);
send_ctrl_hello(QRTR_NODE_BCAST, QRTR_PORT_CTRL);
for (i = 0; i < 10; i++) {
sleep(1);
qrtr_sync_done = !qlist_empty(&qrtr_server_list);
if (qrtr_sync_done)
break;
}
dprintf("%s %s\n", __func__, qrtr_sync_done ? "succful" : "fail");
return qrtr_sync_done ? 0 : -1;
}
static void qrtr_start_server(const char* servername) {
qrtr_proxy_server_fd = create_local_server(servername);
dprintf("qrtr_proxy_server_fd = %d\n", qrtr_proxy_server_fd);
if (qrtr_proxy_server_fd == -1) {
dprintf("Failed to create %s, errno: %d (%s)\n", servername, errno, strerror(errno));
}
}
static void qrtr_close_server(const char* servername) {
if (qrtr_proxy_server_fd != -1) {
dprintf("%s %s\n", __func__, servername);
close(qrtr_proxy_server_fd);
qrtr_proxy_server_fd = -1;
}
}
static void *qrtr_proxy_loop(void *param)
{
void *rx_buf;
struct qlistnode *con_node;
QRTR_PROXY_CONNECTION *qrtr_con;
(void)param;
dprintf("%s enter thread_id %p\n", __func__, (void *)pthread_self());
rx_buf = malloc(8192);
if (!rx_buf)
return NULL;
while (cdc_wdm_fd > 0 && qrtr_proxy_quit == 0) {
struct pollfd pollfds[32];
int ne, ret, nevents = 0;
ssize_t nreads;
pollfds[nevents].fd = cdc_wdm_fd;
pollfds[nevents].events = POLLIN;
pollfds[nevents].revents= 0;
nevents++;
if (qrtr_proxy_server_fd > 0) {
pollfds[nevents].fd = qrtr_proxy_server_fd;
pollfds[nevents].events = POLLIN;
pollfds[nevents].revents= 0;
nevents++;
}
qlist_for_each(con_node, &qrtr_proxy_connection) {
qrtr_con = qnode_to_item(con_node, QRTR_PROXY_CONNECTION, qnode);
pollfds[nevents].fd = qrtr_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, (qrtr_proxy_server_fd > 0) ? -1 : 200);
} while (ret == -1 && errno == EINTR && qrtr_proxy_quit == 0);
if (ret < 0) {
dprintf("%s poll=%d, errno: %d (%s)\n", __func__, ret, errno, strerror(errno));
goto qrtr_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 qrtr_proxy_loop_exit;
}
else if (fd == qrtr_proxy_server_fd) {
}
else {
cleanup_qrtr_connection(fd);
}
continue;
}
if (!(pollfds[ne].revents & POLLIN)) {
continue;
}
if (fd == qrtr_proxy_server_fd) {
accept_qrtr_connection(fd);
}
else if (fd == cdc_wdm_fd) {
struct qrtr_hdr_v1 *hdr = (struct qrtr_hdr_v1 *)rx_buf;
nreads = read(fd, rx_buf, 8192);
if (nreads <= 0) {
dprintf("%s read=%d errno: %d (%s)\n", __func__, (int)nreads, errno, strerror(errno));
goto qrtr_proxy_loop_exit;
}
else if (nreads != (int)align_4(le32toh(hdr->size) + sizeof(*hdr))) {
dprintf("%s nreads=%d, hdr->size = %d\n", __func__, (int)nreads, le32toh(hdr->size));
continue;
}
dump_qrtr(hdr, nreads, '<');
recv_qrtr_from_dev(hdr);
}
else {
PQCQMIMSG pQMI = (PQCQMIMSG)rx_buf;
nreads = read(fd, rx_buf, 8192);
if (nreads <= 0) {
dprintf("%s read=%d errno: %d (%s)", __func__, (int)nreads, errno, strerror(errno));
cleanup_qrtr_connection(fd);
break;
}
else if (nreads != (le16toh(pQMI->QMIHdr.Length) + 1)) {
dprintf("%s nreads=%d, pQCQMI->QMIHdr.Length = %d\n", __func__, (int)nreads, le16toh(pQMI->QMIHdr.Length));
continue;
}
recv_qmi_from_client(pQMI, fd);
}
}
}
qrtr_proxy_loop_exit:
while (!qlist_empty(&qrtr_proxy_connection)) {
QRTR_PROXY_CONNECTION *qrtr_con = qnode_to_item(qlist_head(&qrtr_proxy_connection), QRTR_PROXY_CONNECTION, qnode);
cleanup_qrtr_connection(qrtr_con->ClientFd);
}
dprintf("%s exit, thread_id %p\n", __func__, (void *)pthread_self());
free(rx_buf);
return NULL;
}
static void usage(void) {
dprintf(" -d <device_name> A valid qrtr device\n"
" default /dev/mhi_IPCR, but mhi_IPCR may be invalid\n"
" -i <netcard_name> netcard name\n"
" -v Will show all details\n");
}
static void sig_action(int sig) {
if (qrtr_proxy_quit == 0) {
qrtr_proxy_quit = 1;
if (thread_id)
pthread_kill(thread_id, sig);
}
}
int main(int argc, char *argv[]) {
int opt;
char cdc_wdm[32+1] = "/dev/mhi_IPCR";
char servername[64] = {0};
signal(SIGINT, sig_action);
signal(SIGTERM, sig_action);
optind = 1;
while ( -1 != (opt = getopt(argc, argv, "d:i:vh"))) {
switch (opt) {
case 'd':
strcpy(cdc_wdm, optarg);
break;
case 'v':
verbose_debug = 1;
break;
default:
usage();
return 0;
}
}
sprintf(servername, "quectel-qrtr-proxy%c", cdc_wdm[strlen(cdc_wdm)-1]);
dprintf("Will use cdc-wdm='%s', proxy='%s'\n", cdc_wdm, servername);
while (qrtr_proxy_quit == 0) {
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)\n", cdc_wdm, errno, strerror(errno));
sleep(5);
continue;
}
cfmakenoblock(cdc_wdm_fd);
qlist_init(&qrtr_proxy_connection);
qlist_init(&qrtr_server_list);
pthread_create(&thread_id, NULL, qrtr_proxy_loop, NULL);
if (qrtr_proxy_init() == 0) {
qrtr_start_server(servername);
pthread_join(thread_id, NULL);
qrtr_close_server(servername);
}
else {
pthread_cancel(thread_id);
pthread_join(thread_id, NULL);
}
close(cdc_wdm_fd);
}
return 0;
}

View File

@ -1,342 +0,0 @@
//https://source.codeaurora.org/quic/la/platform/vendor/qcom-opensource/dataservices/tree/rmnetctl
#include <sys/socket.h>
#include <stdint.h>
#include <linux/netlink.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <linux/rtnetlink.h>
#include <linux/gen_stats.h>
#include <net/if.h>
#include <asm/types.h>
#include <linux/rmnet_data.h>
#define RMNETCTL_SUCCESS 0
#define RMNETCTL_LIB_ERR 1
#define RMNETCTL_KERNEL_ERR 2
#define RMNETCTL_INVALID_ARG 3
enum rmnetctl_error_codes_e {
RMNETCTL_API_SUCCESS = 0,
RMNETCTL_API_FIRST_ERR = 1,
RMNETCTL_API_ERR_MESSAGE_SEND = 3,
RMNETCTL_API_ERR_MESSAGE_RECEIVE = 4,
RMNETCTL_INIT_FIRST_ERR = 5,
RMNETCTL_INIT_ERR_PROCESS_ID = RMNETCTL_INIT_FIRST_ERR,
RMNETCTL_INIT_ERR_NETLINK_FD = 6,
RMNETCTL_INIT_ERR_BIND = 7,
RMNETCTL_API_SECOND_ERR = 9,
RMNETCTL_API_ERR_HNDL_INVALID = RMNETCTL_API_SECOND_ERR,
RMNETCTL_API_ERR_RETURN_TYPE = 13,
};
struct rmnetctl_hndl_s {
uint32_t pid;
uint32_t transaction_id;
int netlink_fd;
struct sockaddr_nl src_addr, dest_addr;
};
typedef struct rmnetctl_hndl_s rmnetctl_hndl_t;
#define NLMSG_TAIL(nmsg) \
((struct rtattr *) (((char *)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
struct nlmsg {
struct nlmsghdr nl_addr;
struct ifinfomsg ifmsg;
char data[500];
};
#define MIN_VALID_PROCESS_ID 0
#define MIN_VALID_SOCKET_FD 0
#define KERNEL_PROCESS_ID 0
#define UNICAST 0
enum {
IFLA_RMNET_UL_AGG_PARAMS = __IFLA_RMNET_MAX,
__IFLA_RMNET_EXT_MAX,
};
struct rmnet_egress_agg_params {
uint16_t agg_size;
uint16_t agg_count;
uint32_t agg_time;
};
static int rmnet_get_ack(rmnetctl_hndl_t *hndl, uint16_t *error_code)
{
struct nlack {
struct nlmsghdr ackheader;
struct nlmsgerr ackdata;
char data[256];
} ack;
int i;
if (!hndl || !error_code)
return RMNETCTL_INVALID_ARG;
if ((i = recv(hndl->netlink_fd, &ack, sizeof(ack), 0)) < 0) {
*error_code = errno;
return RMNETCTL_API_ERR_MESSAGE_RECEIVE;
}
/*Ack should always be NLMSG_ERROR type*/
if (ack.ackheader.nlmsg_type == NLMSG_ERROR) {
if (ack.ackdata.error == 0) {
*error_code = RMNETCTL_API_SUCCESS;
return RMNETCTL_SUCCESS;
} else {
*error_code = -ack.ackdata.error;
return RMNETCTL_KERNEL_ERR;
}
}
*error_code = RMNETCTL_API_ERR_RETURN_TYPE;
return RMNETCTL_API_FIRST_ERR;
}
static int rtrmnet_ctl_init(rmnetctl_hndl_t **hndl, uint16_t *error_code)
{
struct sockaddr_nl __attribute__((__may_alias__)) *saddr_ptr;
int netlink_fd = -1;
pid_t pid = 0;
if (!hndl || !error_code)
return RMNETCTL_INVALID_ARG;
*hndl = (rmnetctl_hndl_t *)malloc(sizeof(rmnetctl_hndl_t));
if (!*hndl) {
*error_code = RMNETCTL_API_ERR_HNDL_INVALID;
return RMNETCTL_LIB_ERR;
}
memset(*hndl, 0, sizeof(rmnetctl_hndl_t));
pid = getpid();
if (pid < MIN_VALID_PROCESS_ID) {
free(*hndl);
*error_code = RMNETCTL_INIT_ERR_PROCESS_ID;
return RMNETCTL_LIB_ERR;
}
(*hndl)->pid = KERNEL_PROCESS_ID;
netlink_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (netlink_fd < MIN_VALID_SOCKET_FD) {
free(*hndl);
*error_code = RMNETCTL_INIT_ERR_NETLINK_FD;
return RMNETCTL_LIB_ERR;
}
(*hndl)->netlink_fd = netlink_fd;
memset(&(*hndl)->src_addr, 0, sizeof(struct sockaddr_nl));
(*hndl)->src_addr.nl_family = AF_NETLINK;
(*hndl)->src_addr.nl_pid = (*hndl)->pid;
saddr_ptr = &(*hndl)->src_addr;
if (bind((*hndl)->netlink_fd,
(struct sockaddr *)saddr_ptr,
sizeof(struct sockaddr_nl)) < 0) {
close((*hndl)->netlink_fd);
free(*hndl);
*error_code = RMNETCTL_INIT_ERR_BIND;
return RMNETCTL_LIB_ERR;
}
memset(&(*hndl)->dest_addr, 0, sizeof(struct sockaddr_nl));
(*hndl)->dest_addr.nl_family = AF_NETLINK;
(*hndl)->dest_addr.nl_pid = KERNEL_PROCESS_ID;
(*hndl)->dest_addr.nl_groups = UNICAST;
return RMNETCTL_SUCCESS;
}
static int rtrmnet_ctl_deinit(rmnetctl_hndl_t *hndl)
{
if (!hndl)
return RMNETCTL_SUCCESS;
close(hndl->netlink_fd);
free(hndl);
return RMNETCTL_SUCCESS;
}
static int rtrmnet_ctl_newvnd(rmnetctl_hndl_t *hndl, char *devname, char *vndname,
uint16_t *error_code, uint8_t index,
uint32_t flagconfig, uint32_t ul_agg_cnt, uint32_t ul_agg_size)
{
struct rtattr *attrinfo, *datainfo, *linkinfo;
struct ifla_vlan_flags flags;
int devindex = 0, val = 0;
char *kind = "rmnet";
struct nlmsg req;
short id;
if (!hndl || !devname || !vndname || !error_code)
return RMNETCTL_INVALID_ARG;
memset(&req, 0, sizeof(req));
req.nl_addr.nlmsg_type = RTM_NEWLINK;
req.nl_addr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
req.nl_addr.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL |
NLM_F_ACK;
req.nl_addr.nlmsg_seq = hndl->transaction_id;
hndl->transaction_id++;
/* Get index of devname*/
devindex = if_nametoindex(devname);
if (devindex < 0) {
*error_code = errno;
return RMNETCTL_KERNEL_ERR;
}
/* Setup link attr with devindex as data */
val = devindex;
attrinfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
attrinfo->rta_type = IFLA_LINK;
attrinfo->rta_len = RTA_ALIGN(RTA_LENGTH(sizeof(val)));
memcpy(RTA_DATA(attrinfo), &val, sizeof(val));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(sizeof(val)));
/* Set up IFLA info kind RMNET that has linkinfo and type */
attrinfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
attrinfo->rta_type = IFLA_IFNAME;
attrinfo->rta_len = RTA_ALIGN(RTA_LENGTH(strlen(vndname) + 1));
memcpy(RTA_DATA(attrinfo), vndname, strlen(vndname) + 1);
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(strlen(vndname) + 1));
linkinfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
linkinfo->rta_type = IFLA_LINKINFO;
linkinfo->rta_len = RTA_ALIGN(RTA_LENGTH(0));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(0));
attrinfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
attrinfo->rta_type = IFLA_INFO_KIND;
attrinfo->rta_len = RTA_ALIGN(RTA_LENGTH(strlen(kind)));
memcpy(RTA_DATA(attrinfo), kind, strlen(kind));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(strlen(kind)));
datainfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
datainfo->rta_type = IFLA_INFO_DATA;
datainfo->rta_len = RTA_ALIGN(RTA_LENGTH(0));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(0));
id = index;
attrinfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
attrinfo->rta_type = IFLA_VLAN_ID;
attrinfo->rta_len = RTA_LENGTH(sizeof(id));
memcpy(RTA_DATA(attrinfo), &id, sizeof(id));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(sizeof(id)));
if (flagconfig != 0) {
flags.mask = flagconfig;
flags.flags = flagconfig;
attrinfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
attrinfo->rta_type = IFLA_VLAN_FLAGS;
attrinfo->rta_len = RTA_LENGTH(sizeof(flags));
memcpy(RTA_DATA(attrinfo), &flags, sizeof(flags));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(sizeof(flags)));
}
if (ul_agg_cnt > 1) {
struct rmnet_egress_agg_params agg_params;
agg_params.agg_size = ul_agg_size;
agg_params.agg_count = ul_agg_cnt;
agg_params.agg_time = 3000000;
attrinfo = (struct rtattr *)(((char *)&req) +
NLMSG_ALIGN(req.nl_addr.nlmsg_len));
attrinfo->rta_type = IFLA_RMNET_UL_AGG_PARAMS;
attrinfo->rta_len = RTA_LENGTH(sizeof(agg_params));
memcpy(RTA_DATA(attrinfo), &agg_params, sizeof(agg_params));
req.nl_addr.nlmsg_len = NLMSG_ALIGN(req.nl_addr.nlmsg_len) +
RTA_ALIGN(RTA_LENGTH(sizeof(agg_params)));
}
datainfo->rta_len = (char *)NLMSG_TAIL(&req.nl_addr) - (char *)datainfo;
linkinfo->rta_len = (char *)NLMSG_TAIL(&req.nl_addr) - (char *)linkinfo;
if (send(hndl->netlink_fd, &req, req.nl_addr.nlmsg_len, 0) < 0) {
*error_code = RMNETCTL_API_ERR_MESSAGE_SEND;
return RMNETCTL_LIB_ERR;
}
return rmnet_get_ack(hndl, error_code);
}
int rtrmnet_ctl_create_vnd(char *devname, char *vndname, uint8_t muxid,
uint32_t qmap_version, uint32_t ul_agg_cnt, uint32_t ul_agg_size)
{
struct rmnetctl_hndl_s *handle;
uint16_t error_code;
int return_code;
uint32_t flagconfig = RMNET_FLAGS_INGRESS_DEAGGREGATION;
printf("%s devname: %s, vndname: %s, muxid: %d, qmap_version: %d\n",
__func__, devname, vndname, muxid, qmap_version);
ul_agg_cnt = 0; //TODO
if (ul_agg_cnt > 1)
flagconfig |= RMNET_EGRESS_FORMAT_AGGREGATION;
if (qmap_version == 9) { //QMAPV5
#ifdef RMNET_FLAGS_INGRESS_MAP_CKSUMV5
flagconfig |= RMNET_FLAGS_INGRESS_MAP_CKSUMV5;
flagconfig |= RMNET_FLAGS_EGRESS_MAP_CKSUMV5;
#else
return -1001;
#endif
}
else if (qmap_version == 8) { //QMAPV4
flagconfig |= RMNET_FLAGS_INGRESS_MAP_CKSUMV4;
flagconfig |= RMNET_FLAGS_EGRESS_MAP_CKSUMV4;
}
else if (qmap_version == 5) { //QMAPV1
}
else {
flagconfig = 0;
}
return_code = rtrmnet_ctl_init(&handle, &error_code);
if (return_code) {
printf("rtrmnet_ctl_init error_code: %d, return_code: %d, errno: %d (%s)\n",
error_code, return_code, errno, strerror(errno));
}
if (return_code == RMNETCTL_SUCCESS) {
return_code = rtrmnet_ctl_newvnd(handle, devname, vndname, &error_code,
muxid, flagconfig, ul_agg_cnt, ul_agg_size);
if (return_code) {
printf("rtrmnet_ctl_newvnd error_code: %d, return_code: %d, errno: %d (%s)\n",
error_code, return_code, errno, strerror(errno));
}
rtrmnet_ctl_deinit(handle);
}
return return_code;
}

View File

@ -1,745 +0,0 @@
/******************************************************************************
@file udhcpc.c
@brief call DHCP tools to obtain IP address.
DESCRIPTION
Connectivity Management Tool for USB network adapter of Quectel wireless cellular modules.
INITIALIZATION AND SEQUENCING REQUIREMENTS
None.
---------------------------------------------------------------------------
Copyright (c) 2016 - 2023 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
Quectel Wireless Solution Proprietary and Confidential.
---------------------------------------------------------------------------
******************************************************************************/
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/types.h>
#include <net/if.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <endian.h>
#include "util.h"
#include "QMIThread.h"
extern int ql_get_netcard_carrier_state(const char *devname);
static __inline in_addr_t qmi2addr(uint32_t __x) {
return (__x>>24) | (__x>>8&0xff00) | (__x<<8&0xff0000) | (__x<<24);
}
static int ql_system(const char *shell_cmd) {
dbg_time("%s", shell_cmd);
return system(shell_cmd);
}
static void ifc_init_ifr(const char *name, struct ifreq *ifr)
{
memset(ifr, 0, sizeof(struct ifreq));
no_trunc_strncpy(ifr->ifr_name, name, IFNAMSIZ);
ifr->ifr_name[IFNAMSIZ - 1] = 0;
}
static void ql_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) {
ifc_init_ifr(ifname, &ifr);
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 int ifc_get_addr(const char *name, in_addr_t *addr)
{
int inet_sock;
struct ifreq ifr;
int ret = 0;
inet_sock = socket(AF_INET, SOCK_DGRAM, 0);
ifc_init_ifr(name, &ifr);
if (addr != NULL) {
ret = ioctl(inet_sock, SIOCGIFADDR, &ifr);
if (ret < 0) {
*addr = 0;
} else {
*addr = ((struct sockaddr_in*) &ifr.ifr_addr)->sin_addr.s_addr;
}
}
close(inet_sock);
return ret;
}
static short ifc_get_flags(const char *ifname)
{
int inet_sock;
struct ifreq ifr;
int ret = 0;
inet_sock = socket(AF_INET, SOCK_DGRAM, 0);
if (inet_sock > 0) {
ifc_init_ifr(ifname, &ifr);
if (!ioctl(inet_sock, SIOCGIFFLAGS, &ifr)) {
ret = ifr.ifr_ifru.ifru_flags;
}
close(inet_sock);
}
return ret;
}
static void ifc_set_state(const char *ifname, int state) {
char shell_cmd[128];
if (!access("/sbin/ip", X_OK)) {
snprintf(shell_cmd, sizeof(shell_cmd), "ip link set dev %s %s", ifname, state ? "up" : "down");
} else {
snprintf(shell_cmd, sizeof(shell_cmd), "ifconfig %s %s", ifname, state ? "up" : "down");
}
ql_system(shell_cmd);
}
static int ql_netcard_ipv4_address_check(const char *ifname, in_addr_t ip) {
in_addr_t addr = 0;
ifc_get_addr(ifname, &addr);
return addr == ip;
}
static int ql_raw_ip_mode_check(const char *ifname, uint32_t ip) {
int fd;
char raw_ip[128];
char mode[2] = "X";
int mode_change = 0;
if (ql_netcard_ipv4_address_check(ifname, qmi2addr(ip)))
return 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;
}
if (read(fd, mode, 2) == -1) {};
if (mode[0] == '0' || mode[0] == 'N') {
dbg_time("File:%s Line:%d udhcpc fail to get ip address, try next:", __func__, __LINE__);
ifc_set_state(ifname, 0);
dbg_time("echo Y > /sys/class/net/%s/qmi/raw_ip", ifname);
mode[0] = 'Y';
if (write(fd, mode, 2) == -1) {};
mode_change = 1;
ifc_set_state(ifname, 1);
}
close(fd);
return mode_change;
}
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;
}
//#define USE_DHCLIENT
#ifdef USE_DHCLIENT
static int dhclient_alive = 0;
#endif
static int dibbler_client_alive = 0;
void ql_set_driver_link_state(PROFILE_T *profile, int link_state) {
char link_file[128];
int fd;
int new_state = 0;
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->muxid & 0x7F);
}
snprintf(link_file, sizeof(link_file), "%d\n", new_state);
if (write(fd, link_file, sizeof(link_file)) == -1) {};
if (link_state == 0 && profile->qmapnet_adapter[0]
&& strcmp(profile->qmapnet_adapter, profile->usbnet_adapter)) {
size_t rc;
lseek(fd, 0, SEEK_SET);
rc = read(fd, link_file, sizeof(link_file));
if (rc > 1 && (!strncasecmp(link_file, "0\n", 2) || !strncasecmp(link_file, "0x0\n", 4))) {
ifc_set_state(profile->usbnet_adapter, 0);
}
}
close(fd);
}
static const char *ipv4Str(const uint32_t Address) {
static char str[] = {"255.225.255.255"};
uint8_t *ip = (uint8_t *)&Address;
snprintf(str, sizeof(str), "%d.%d.%d.%d", ip[3], ip[2], ip[1], ip[0]);
return str;
}
static const char *ipv6Str(const UCHAR Address[16]) {
static char str[64];
uint16_t ip[8];
int i;
for (i = 0; i < 8; i++) {
ip[i] = (Address[i*2]<<8) + Address[i*2+1];
}
snprintf(str, sizeof(str), "%x:%x:%x:%x:%x:%x:%x:%x",
ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7]);
return str;
}
void update_ipv4_address(const char *ifname, const char *ip, const char *gw, unsigned prefix)
{
char shell_cmd[128];
if (!ifname)
return;
if (!access("/sbin/ip", X_OK)) {
snprintf(shell_cmd, sizeof(shell_cmd), "ip -%d address flush dev %s", 4, ifname);
ql_system(shell_cmd);
snprintf(shell_cmd, sizeof(shell_cmd), "ip -%d address add %s/%u dev %s", 4, ip, prefix, ifname);
ql_system(shell_cmd);
//ping6 www.qq.com
snprintf(shell_cmd, sizeof(shell_cmd), "ip -%d route add default via %s dev %s", 4, gw, ifname);
ql_system(shell_cmd);
} else {
unsigned n = (0xFFFFFFFF >> (32 - prefix)) << (32 - prefix);
// n = (n>>24) | (n>>8&0xff00) | (n<<8&0xff0000) | (n<<24);
snprintf(shell_cmd, sizeof(shell_cmd), "ifconfig %s %s netmask %s", ifname, ip, ipv4Str(n));
ql_system(shell_cmd);
//Resetting default routes
snprintf(shell_cmd, sizeof(shell_cmd), "route del default dev %s", ifname);
while(!system(shell_cmd));
snprintf(shell_cmd, sizeof(shell_cmd), "route add default gw %s dev %s", gw, ifname);
ql_system(shell_cmd);
}
}
void update_ipv6_address(const char *ifname, const char *ip, const char *gw, unsigned prefix) {
char shell_cmd[128];
(void)gw;
if (!access("/sbin/ip", X_OK)) {
snprintf(shell_cmd, sizeof(shell_cmd), "ip -%d address flush dev %s", 6, ifname);
ql_system(shell_cmd);
snprintf(shell_cmd, sizeof(shell_cmd), "ip -%d address add %s/%u dev %s", 6, ip, prefix, ifname);
ql_system(shell_cmd);
//ping6 www.qq.com
snprintf(shell_cmd, sizeof(shell_cmd), "ip -%d route add default dev %s", 6, ifname);
ql_system(shell_cmd);
} else {
snprintf(shell_cmd, sizeof(shell_cmd), "ifconfig %s %s/%d", ifname, ip, prefix);
ql_system(shell_cmd);
snprintf(shell_cmd, sizeof(shell_cmd), "route -A inet6 add default dev %s", ifname);
ql_system(shell_cmd);
}
}
static void update_ip_address_by_qmi(const char *ifname, const IPV4_T *ipv4, const IPV6_T *ipv6) {
char *d1, *d2;
if (ipv4 && ipv4->Address) {
d1 = strdup(ipv4Str(ipv4->Address));
d2 = strdup(ipv4Str(ipv4->Gateway));
unsigned prefix = 0;
unsigned n = 0;
for (n = 0; n < 32; n++) {
if (ipv4->SubnetMask&((unsigned)1<<n)) {
prefix++;
}
}
update_ipv4_address(ifname, d1, d2, prefix);
free(d1); free(d2);
//Adding DNS
if (ipv4->DnsPrimary) {
d1 = strdup(ipv4Str(ipv4->DnsPrimary));
d2 = strdup(ipv4Str(ipv4->DnsSecondary ? ipv4->DnsSecondary : ipv4->DnsPrimary));
update_resolv_conf(4, ifname, d1, d2);
free(d1); free(d2);
}
}
if (ipv6 && ipv6->Address[0] && ipv6->PrefixLengthIPAddr) {
d1 = strdup(ipv6Str(ipv6->Address));
d2 = strdup(ipv6Str(ipv6->Gateway));
update_ipv6_address(ifname, d1, d2, ipv6->PrefixLengthIPAddr);
free(d1); free(d2);
//Adding DNS
if (ipv6->DnsPrimary[0]) {
d1 = strdup(ipv6Str(ipv6->DnsPrimary));
d2 = strdup(ipv6Str(ipv6->DnsSecondary[0] ? ipv6->DnsSecondary : ipv6->DnsPrimary));
update_resolv_conf(6, ifname, d1, d2);
free(d1); free(d2);
}
}
}
//#define QL_OPENWER_NETWORK_SETUP
#ifdef QL_OPENWER_NETWORK_SETUP
static const char *openwrt_lan = "br-lan";
static const char *openwrt_wan = "wwan0";
static int ql_openwrt_system(const char *cmd) {
int i;
int ret = 1;
char shell_cmd[128];
snprintf(shell_cmd, sizeof(shell_cmd), "%s 2>1 > /dev/null", cmd);
for (i = 0; i < 15; i++) {
dbg_time("%s", cmd);
ret = system(shell_cmd);
if (!ret)
break;
sleep(1);
}
return ret;
}
static int ql_openwrt_is_wan(const char *ifname) {
if (openwrt_lan == NULL) {
system("uci show network.wan.ifname");
}
if (strcmp(ifname, openwrt_wan))
return 0;
return 1;
}
static void ql_openwrt_setup_wan(const char *ifname, const IPV4_T *ipv4) {
FILE *fp = NULL;
char config[64];
snprintf(config, sizeof(config), "/tmp/rmnet_%s_ipv4config", ifname);
if (ipv4 == NULL) {
if (ql_openwrt_is_wan(ifname))
ql_openwrt_system("ifdown wan");
return;
}
fp = fopen(config, "w");
if (fp == NULL)
return;
fprintf(fp, "IFNAME=\"%s\"\n", ifname);
fprintf(fp, "PUBLIC_IP=\"%s\"\n", ipv4Str(ipv4->Address));
fprintf(fp, "NETMASK=\"%s\"\n", ipv4Str(ipv4->SubnetMask));
fprintf(fp, "GATEWAY=\"%s\"\n", ipv4Str(ipv4->Gateway));
fprintf(fp, "DNSSERVERS=\"%s", ipv4Str(ipv4->DnsPrimary));
if (ipv4->DnsSecondary != 0)
fprintf(fp, " %s", ipv4Str(ipv4->DnsSecondary));
fprintf(fp, "\"\n");
fclose(fp);
if (!ql_openwrt_is_wan(ifname))
return;
ql_openwrt_system("ifup wan");
}
static void ql_openwrt_setup_wan6(const char *ifname, const IPV6_T *ipv6) {
FILE *fp = NULL;
char config[64];
int first_ifup;
snprintf(config, sizeof(config), "/tmp/rmnet_%s_ipv6config", ifname);
if (ipv6 == NULL) {
if (ql_openwrt_is_wan(ifname))
ql_openwrt_system("ifdown wan6");
return;
}
first_ifup = (access(config, F_OK) != 0);
fp = fopen(config, "w");
if (fp == NULL)
return;
fprintf(fp, "IFNAME=\"%s\"\n", ifname);
fprintf(fp, "PUBLIC_IP=\"%s\"\n", ipv6Str(ipv6->Address));
fprintf(fp, "NETMASK=\"%s\"\n", ipv6Str(ipv6->SubnetMask));
fprintf(fp, "GATEWAY=\"%s\"\n", ipv6Str(ipv6->Gateway));
fprintf(fp, "PrefixLength=\"%d\"\n", ipv6->PrefixLengthIPAddr);
fprintf(fp, "DNSSERVERS=\"%s", ipv6Str(ipv6->DnsPrimary));
if (ipv6->DnsSecondary[0])
fprintf(fp, " %s", ipv6Str(ipv6->DnsSecondary));
fprintf(fp, "\"\n");
fclose(fp);
if (!ql_openwrt_is_wan(ifname))
return;
if (first_ifup)
ql_openwrt_system("ifup wan6");
else
ql_openwrt_system("/etc/init.d/network restart"); //make PC to release old IPV6 address, and RS new IPV6 address
#if 1 //TODO? why need this?
if (openwrt_lan) {
int i;
char shell_cmd[128];
UCHAR Address[16] = {0};
ql_openwrt_system(("ifstatus lan"));
for (i = 0; i < (ipv6->PrefixLengthIPAddr/8); i++)
Address[i] = ipv6->Address[i];
snprintf(shell_cmd, sizeof(shell_cmd), "ip route del %s/%u dev %s", ipv6Str(Address), ipv6->PrefixLengthIPAddr, ifname);
ql_openwrt_system(shell_cmd);
snprintf(shell_cmd, sizeof(shell_cmd), "ip route add %s/%u dev %s", ipv6Str(Address), ipv6->PrefixLengthIPAddr, openwrt_lan);
ql_system(shell_cmd);
}
#endif
}
#endif
void udhcpc_start(PROFILE_T *profile) {
char *ifname = profile->usbnet_adapter;
ql_set_driver_link_state(profile, 1);
if (profile->qmapnet_adapter[0]) {
ifname = profile->qmapnet_adapter;
}
if (profile->rawIP && profile->ipv4.Address && profile->ipv4.Mtu) {
ql_set_mtu(ifname, (profile->ipv4.Mtu));
}
if (strcmp(ifname, profile->usbnet_adapter)) {
ifc_set_state(profile->usbnet_adapter, 1);
if (ifc_get_flags(ifname)&IFF_UP) {
ifc_set_state(ifname, 0);
}
}
ifc_set_state(ifname, 1);
if (profile->ipv4.Address) {
if (profile->PCSCFIpv4Addr1)
dbg_time("pcscf1: %s", ipv4Str(profile->PCSCFIpv4Addr1));
if (profile->PCSCFIpv4Addr2)
dbg_time("pcscf2: %s", ipv4Str(profile->PCSCFIpv4Addr2));
}
if (profile->ipv6.Address[0] && profile->ipv6.PrefixLengthIPAddr) {
if (profile->PCSCFIpv6Addr1[0])
dbg_time("pcscf1: %s", ipv6Str(profile->PCSCFIpv6Addr1));
if (profile->PCSCFIpv6Addr2[0])
dbg_time("pcscf2: %s", ipv6Str(profile->PCSCFIpv6Addr2));
}
#if 1 //for bridge mode, only one public IP, so do udhcpc manually
if (ql_bridge_mode_detect(profile)) {
return;
}
#endif
//because must use udhcpc to obtain IP when working on ETH mode,
//so it is better also use udhcpc to obtain IP when working on IP mode.
//use the same policy for all modules
#if 0
if (profile->rawIP != 0) //mdm9x07/ec25,ec20 R2.0
{
update_ip_address_by_qmi(ifname, &profile->ipv4, &profile->ipv6);
return;
}
#endif
if (profile->ipv4.Address == 0)
goto set_ipv6;
if (profile->no_dhcp || profile->request_ops == &mbim_request_ops) { //lots of mbim modem do not support DHCP
update_ip_address_by_qmi(ifname, &profile->ipv4, NULL);
}
else
/* 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);
#ifdef USE_DHCLIENT
snprintf(udhcpc_cmd, sizeof(udhcpc_cmd), "dhclient -4 -d --no-pid %s", ifname);
dhclient_alive++;
#else
if (access("/usr/share/udhcpc/default.script", X_OK)
&& access("/etc//udhcpc/default.script", X_OK)) {
dbg_time("No default.script found, it should be in '/usr/share/udhcpc/' or '/etc//udhcpc' depend on your udhcpc version!");
}
//-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);
#endif
#if 1 //for OpenWrt
if (!access("/lib/netifd/dhcp.script", X_OK) && !access("/sbin/ifup", X_OK) && !access("/sbin/ifstatus", X_OK)) {
#if 0 //20210415 do not promot these message
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);
#endif
}
#endif
#ifdef USE_DHCLIENT
pthread_create(&udhcpc_thread_id, &udhcpc_thread_attr, udhcpc_thread_function, (void*)strdup(udhcpc_cmd));
sleep(1);
#else
pthread_create(&udhcpc_thread_id, NULL, udhcpc_thread_function, (void*)strdup(udhcpc_cmd));
pthread_join(udhcpc_thread_id, NULL);
if (profile->request_ops == &atc_request_ops) {
profile->udhcpc_ip = 0;
ifc_get_addr(ifname, &profile->udhcpc_ip);
if (profile->udhcpc_ip != profile->ipv4.Address) {
unsigned char *l = (unsigned char *)&profile->udhcpc_ip;
unsigned char *r = (unsigned char *)&profile->ipv4.Address;
dbg_time("ERROR: IP from udhcpc (%d.%d.%d.%d) is different to IP from ATC (%d.%d.%d.%d)!",
l[0], l[1], l[2], l[3], r[0], r[1], r[2], r[3]);
ql_get_netcard_carrier_state(ifname); //miss udhcpc default.script or modem not report usb-net-cdc-linkup
}
}
if (profile->request_ops != &qmi_request_ops) { //only QMI modem support next fixup!
goto set_ipv6;
}
if (ql_raw_ip_mode_check(ifname, profile->ipv4.Address)) {
pthread_create(&udhcpc_thread_id, NULL, udhcpc_thread_function, (void*)strdup(udhcpc_cmd));
pthread_join(udhcpc_thread_id, NULL);
}
if (!ql_netcard_ipv4_address_check(ifname, qmi2addr(profile->ipv4.Address))) {
//no udhcpc's default.script exist, directly set ip and dns
update_ip_address_by_qmi(ifname, &profile->ipv4, NULL);
}
//Add by Demon. check default route
FILE *rt_fp = NULL;
char rt_cmd[128] = {0};
//Check if there is a default route.
snprintf(rt_cmd, sizeof(rt_cmd), "route -n | grep %s | awk '{print $1}' | grep 0.0.0.0", ifname);
rt_fp = popen((const char *)rt_cmd, "r");
if (rt_fp != NULL) {
char buf[20] = {0};
int found_default_rt = 0;
if (fgets(buf, sizeof(buf), rt_fp) != NULL) {
//Find the specified interface
found_default_rt = 1;
}
if (1 == found_default_rt) {
//dbg_time("Route items found for %s", ifname);
}
else {
dbg_time("Warning: No route items found for %s", ifname);
}
pclose(rt_fp);
}
//End by Demon.
#endif
}
#ifdef QL_OPENWER_NETWORK_SETUP
ql_openwrt_setup_wan(ifname, &profile->ipv4);
#endif
set_ipv6:
if (profile->ipv6.Address[0] && profile->ipv6.PrefixLengthIPAddr) {
#if 1
//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];
if (read(forward_fd, forward_state, 2) == -1) {};
if (forward_state[0] == '1') {
//dbg_time("%s enabled, kernel maybe donot send 'Router Solicit'", forward_file);
}
close(forward_fd);
}
update_ip_address_by_qmi(ifname, NULL, &profile->ipv6);
if (profile->ipv6.DnsPrimary[0] || profile->ipv6.DnsSecondary[0]) {
char dns1str[64], dns2str[64];
if (profile->ipv6.DnsPrimary[0]) {
strcpy(dns1str, ipv6Str(profile->ipv6.DnsPrimary));
}
if (profile->ipv6.DnsSecondary[0]) {
strcpy(dns2str, ipv6Str(profile->ipv6.DnsSecondary));
}
update_resolv_conf(6, ifname, profile->ipv6.DnsPrimary[0] ? dns1str : NULL,
profile->ipv6.DnsSecondary[0] != '\0' ? dns2str : NULL);
}
#ifdef QL_OPENWER_NETWORK_SETUP
ql_openwrt_setup_wan6(ifname, &profile->ipv6);
#endif
#else
#ifdef USE_DHCLIENT
snprintf(udhcpc_cmd, sizeof(udhcpc_cmd), "dhclient -6 -d --no-pid %s", ifname);
dhclient_alive++;
#else
/*
DHCPv6: Dibbler - a portable DHCPv6
1. download from http://klub.com.pl/dhcpv6/
2. cross-compile
2.1 ./configure --host=arm-linux-gnueabihf
2.2 copy dibbler-client to your board
3. mkdir -p /var/log/dibbler/ /var/lib/ on your board
4. create /etc/dibbler/client.conf on your board, the content is
log-mode short
log-level 7
iface wwan0 {
ia
option dns-server
}
5. run "dibbler-client start" to get ipV6 address
6. run "route -A inet6 add default dev wwan0" to add default route
*/
snprintf(shell_cmd, sizeof(shell_cmd), "route -A inet6 add default %s", ifname);
ql_system(shell_cmd);
snprintf(udhcpc_cmd, sizeof(udhcpc_cmd), "dibbler-client run");
dibbler_client_alive++;
#endif
pthread_create(&udhcpc_thread_id, &udhcpc_thread_attr, udhcpc_thread_function, (void*)strdup(udhcpc_cmd));
#endif
}
}
void udhcpc_stop(PROFILE_T *profile) {
char *ifname = profile->usbnet_adapter;
char shell_cmd[128];
ql_set_driver_link_state(profile, 0);
if (profile->qmapnet_adapter[0]) {
ifname = profile->qmapnet_adapter;
}
#ifdef USE_DHCLIENT
if (dhclient_alive) {
system("killall dhclient");
dhclient_alive = 0;
}
#endif
if (dibbler_client_alive) {
if (system("killall dibbler-client")) {};
dibbler_client_alive = 0;
}
profile->udhcpc_ip = 0;
//it seems when call netif_carrier_on(), and netcard 's IP is "0.0.0.0", will cause netif_queue_stopped()
if (!access("/sbin/ip", X_OK))
snprintf(shell_cmd, sizeof(shell_cmd), "ip addr flush dev %s", ifname);
else
snprintf(shell_cmd, sizeof(shell_cmd), "ifconfig %s 0.0.0.0", ifname);
ql_system(shell_cmd);
ifc_set_state(ifname, 0);
#ifdef QL_OPENWER_NETWORK_SETUP
ql_openwrt_setup_wan(ifname, NULL);
ql_openwrt_setup_wan6(ifname, NULL);
#endif
}

View File

@ -1,179 +0,0 @@
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/types.h>
#include <net/if.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <endian.h>
#include "libmnl/ifutils.h"
#include "libmnl/dhcp/dhcp.h"
#include "util.h"
#include "QMIThread.h"
static int ql_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;
}
void ql_set_driver_link_state(PROFILE_T *profile, int link_state)
{
char link_file[128];
int fd;
int new_state = 0;
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)
{
char *ifname = profile->usbnet_adapter;
ql_set_driver_link_state(profile, 1);
ql_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);
}
if_link_up(ifname);
#if 1 //for bridge mode, only one public IP, so do udhcpc manually
if (ql_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));
}
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);
}
dbg_time("IPv6 MTU: %d", profile->ipv6.Mtu);
dbg_time("IPv6 Address: %s", ipaddr_to_string_v6(profile->ipv6.Address));
dbg_time("IPv6 Netmask: %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);
}
}
void udhcpc_stop(PROFILE_T *profile)
{
char *ifname = profile->usbnet_adapter;
ql_set_driver_link_state(profile, 0);
if (profile->qmapnet_adapter)
{
ifname = profile->qmapnet_adapter;
}
if_link_down(ifname);
if_flush_v4_addr(ifname);
if_flush_v6_addr(ifname);
}

View File

@ -1,132 +0,0 @@
/******************************************************************************
@file udhcpc.c
@brief call DHCP tools to obtain IP address.
DESCRIPTION
Connectivity Management Tool for USB network adapter of Quectel wireless cellular modules.
INITIALIZATION AND SEQUENCING REQUIREMENTS
None.
---------------------------------------------------------------------------
Copyright (c) 2016 - 2023 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
Quectel Wireless Solution Proprietary and Confidential.
---------------------------------------------------------------------------
******************************************************************************/
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/types.h>
#include <net/if.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <endian.h>
#include "util.h"
#include "QMIThread.h"
#define IFDOWN_SCRIPT "/etc/quectel/ifdown.sh"
#define IFUP_SCRIPT "/etc/quectel/ifup.sh"
static int ql_system(const char *shell_cmd)
{
dbg_time("%s", shell_cmd);
return system(shell_cmd);
}
uint32_t mask_to_prefix_v4(uint32_t mask)
{
uint32_t prefix = 0;
while (mask)
{
mask = mask & (mask - 1);
prefix++;
}
return prefix;
}
uint32_t mask_from_prefix_v4(uint32_t prefix)
{
return ~((1 << (32 - prefix)) - 1);
}
/* mask in int */
uint32_t broadcast_from_mask(uint32_t ip, uint32_t mask)
{
return (ip & mask) | (~mask);
}
const char *ipaddr_to_string_v4(in_addr_t ipaddr, char *buf, size_t size)
{
// static char buf[INET6_ADDRSTRLEN] = {'\0'};
buf[0] = '\0';
uint32_t addr = ipaddr;
return inet_ntop(AF_INET, &addr, buf, size);
}
const char *ipaddr_to_string_v6(uint8_t *ipaddr, char *buf, size_t size)
{
buf[0] = '\0';
return inet_ntop(AF_INET6, ipaddr, buf, size);
}
/**
* For more details see default.script
*
* The main aim of this function is offload ip management to script, CM has not interest in manage IP address.
* just tell script all the info about ip, mask, router, dns...
*/
void udhcpc_start(PROFILE_T *profile)
{
char shell_cmd[1024];
char ip[128];
char subnet[128];
char broadcast[128];
char router[128];
char domain1[128];
char domain2[128];
if (NULL == getenv(IFUP_SCRIPT))
return;
// manage IPv4???
// check rawip ???
snprintf(shell_cmd, sizeof(shell_cmd),
" netiface=%s interface=%s mtu=%u ip=%s subnet=%s broadcast=%s router=%s"
" domain=\"%s %s\" %s",
profile->usbnet_adapter,
profile->qmapnet_adapter ? profile->qmapnet_adapter : profile->usbnet_adapter,
profile->ipv4.Mtu,
ipaddr_to_string_v4(ntohl(profile->ipv4.Address), ip, sizeof(ip)),
ipaddr_to_string_v4(ntohl(profile->ipv4.SubnetMask), subnet, sizeof(subnet)),
ipaddr_to_string_v4(ntohl(broadcast_from_mask(profile->ipv4.Address, profile->ipv4.SubnetMask)),
broadcast, sizeof(broadcast)),
ipaddr_to_string_v4(ntohl(profile->ipv4.Gateway), router, sizeof(router)),
ipaddr_to_string_v4(ntohl(profile->ipv4.DnsPrimary), domain1, sizeof(domain1)),
ipaddr_to_string_v4(ntohl(profile->ipv4.DnsSecondary), domain2, sizeof(domain2)),
getenv(IFUP_SCRIPT));
ql_system(shell_cmd);
// manage IPv6???
}
/**
* For more details see default.script
*
* The main aim of this function is offload ip management to script, CM has not interest in manage IP address.
* just tell script all the info about ip, mask, router, dns...
*/
void udhcpc_stop(PROFILE_T *profile)
{
char shell_cmd[1024];
if (NULL == getenv(IFDOWN_SCRIPT))
return;
snprintf(shell_cmd, sizeof(shell_cmd),
"netiface=%s interface=%s %s",
profile->usbnet_adapter,
profile->qmapnet_adapter ? profile->qmapnet_adapter : profile->usbnet_adapter,
getenv(IFDOWN_SCRIPT));
ql_system(shell_cmd);
}

View File

@ -1,361 +0,0 @@
/******************************************************************************
@file util.c
@brief some utils for this QCM tool.
DESCRIPTION
Connectivity Management Tool for USB network adapter of Quectel wireless cellular modules.
INITIALIZATION AND SEQUENCING REQUIREMENTS
None.
---------------------------------------------------------------------------
Copyright (c) 2016 - 2023 Quectel Wireless Solution, Co., Ltd. All Rights Reserved.
Quectel Wireless Solution Proprietary and Confidential.
---------------------------------------------------------------------------
******************************************************************************/
#include <sys/time.h>
#include <net/if.h>
typedef unsigned short sa_family_t;
#include <linux/un.h>
#if defined(__STDC__)
#include <stdarg.h>
#define __V(x) x
#else
#include <varargs.h>
#define __V(x) (va_alist) va_dcl
#define const
#define volatile
#endif
#include <syslog.h>
#include "QMIThread.h"
pthread_mutex_t cm_command_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cm_command_cond = PTHREAD_COND_INITIALIZER;
unsigned int cm_recv_buf[1024];
int cm_open_dev(const char *dev) {
int fd;
fd = open(dev, O_RDWR | O_NONBLOCK | O_NOCTTY);
if (fd != -1) {
fcntl(fd, F_SETFL, fcntl(fd,F_GETFL) | O_NONBLOCK);
fcntl(fd, F_SETFD, FD_CLOEXEC);
if (!strncmp(dev, "/dev/tty", strlen("/dev/tty")))
{
//disable echo on serial ports
struct termios ios;
memset(&ios, 0, sizeof(ios));
tcgetattr( fd, &ios );
cfmakeraw(&ios);
cfsetispeed(&ios, B115200);
cfsetospeed(&ios, B115200);
tcsetattr( fd, TCSANOW, &ios );
tcflush(fd, TCIOFLUSH);
}
} else {
dbg_time("Failed to open %s, errno: %d (%s)", dev, errno, strerror(errno));
}
return fd;
}
int cm_open_proxy(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("connect %s errno: %d (%s)", name, errno, strerror(errno));
return -1;
}
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse_addr,sizeof(reuse_addr));
fcntl(sockfd, F_SETFL, fcntl(sockfd,F_GETFL) | O_NONBLOCK);
fcntl(sockfd, F_SETFD, FD_CLOEXEC);
dbg_time("connect to %s sockfd = %d", name, sockfd);
return sockfd;
}
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;
if ((unsigned long)p_ts->tv_nsec >= 1000000000UL) {
p_ts->tv_sec += 1;
p_ts->tv_nsec -= 1000000000UL;
}
}
int pthread_cond_timeout_np(pthread_cond_t *cond, pthread_mutex_t * mutex, unsigned msecs) {
if (msecs != 0) {
unsigned i;
unsigned t = msecs/4;
int ret = 0;
if (t == 0)
t = 1;
for (i = 0; i < msecs; i += t) {
struct timespec ts;
setTimespecRelative(&ts, t);
//very old uclibc do not support pthread_condattr_setclock(CLOCK_MONOTONIC)
ret = pthread_cond_timedwait(cond, mutex, &ts); //to advoid system time change
if (ret != ETIMEDOUT) {
if(ret) dbg_time("ret=%d, msecs=%u, t=%u", ret, msecs, t);
break;
}
}
return ret;
} else {
return pthread_cond_wait(cond, mutex);
}
}
const char * get_time(void) {
static char time_buf[128];
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;
}
unsigned long clock_msec(void)
{
struct timespec tm;
clock_gettime( CLOCK_MONOTONIC, &tm);
return (unsigned long)(tm.tv_sec*1000 + (tm.tv_nsec/1000000));
}
FILE *logfilefp = NULL;
void update_resolv_conf(int iptype, const char *ifname, const char *dns1, const char *dns2) {
const char *dns_file = "/etc/resolv.conf";
FILE *dns_fp;
char dns_line[256];
#define MAX_DNS 16
char *dns_info[MAX_DNS];
char dns_tag[64];
int dns_match = 0;
int i;
snprintf(dns_tag, sizeof(dns_tag), "# IPV%d %s", iptype, ifname);
for (i = 0; i < MAX_DNS; i++)
dns_info[i] = NULL;
dns_fp = fopen(dns_file, "r");
if (dns_fp) {
i = 0;
dns_line[sizeof(dns_line)-1] = '\0';
while((fgets(dns_line, sizeof(dns_line)-1, dns_fp)) != NULL) {
if ((strlen(dns_line) > 1) && (dns_line[strlen(dns_line) - 1] == '\n'))
dns_line[strlen(dns_line) - 1] = '\0';
//dbg_time("%s", dns_line);
if (strstr(dns_line, dns_tag)) {
dns_match++;
continue;
}
dns_info[i++] = strdup(dns_line);
if (i == MAX_DNS)
break;
}
fclose(dns_fp);
}
else if (errno != ENOENT) {
dbg_time("fopen %s fail, errno:%d (%s)", dns_file, errno, strerror(errno));
return;
}
if (dns1 == NULL && dns_match == 0)
return;
dns_fp = fopen(dns_file, "w");
if (dns_fp) {
if (dns1)
fprintf(dns_fp, "nameserver %s %s\n", dns1, dns_tag);
if (dns2)
fprintf(dns_fp, "nameserver %s %s\n", dns2, dns_tag);
for (i = 0; i < MAX_DNS && dns_info[i]; i++)
fprintf(dns_fp, "%s\n", dns_info[i]);
fclose(dns_fp);
}
else {
dbg_time("fopen %s fail, errno:%d (%s)", dns_file, errno, strerror(errno));
}
for (i = 0; i < MAX_DNS && dns_info[i]; i++)
free(dns_info[i]);
}
pid_t getpid_by_pdp(int pdp, const char* program_name)
{
glob_t gt;
int ret;
char filter[16];
pid_t pid;
snprintf(filter, sizeof(filter), "-n %d", pdp);
ret = glob("/proc/*/cmdline", GLOB_NOSORT, NULL, &gt);
if (ret != 0) {
dbg_time("glob error, errno = %d(%s)", errno, strerror(errno));
return -1;
} else {
int i = 0, fd = -1;
ssize_t nreads;
char cmdline[512] = {0};
for (i = 0; i < (int)gt.gl_pathc; i++) {
fd = open(gt.gl_pathv[i], O_RDONLY);
if (fd == -1) {
dbg_time("open %s failed, errno = %d(%s)", gt.gl_pathv[i], errno, strerror(errno));
globfree(&gt);
return -1;
}
nreads = read(fd, cmdline, sizeof(cmdline));
if (nreads > 0) {
int pos = 0;
while (pos < nreads-1) {
if (cmdline[pos] == '\0')
cmdline[pos] = ' '; // space
pos++;
}
// printf("%s\n", cmdline);
}
if (strstr(cmdline, program_name) && strstr(cmdline, filter)) {
char path[64] = {0};
char pidstr[64] = {0};
char *p;
dbg_time("%s: %s", gt.gl_pathv[i], cmdline);
strcpy(path, gt.gl_pathv[i]);
p = strstr(gt.gl_pathv[i], "/cmdline");
*p = '\0';
while (*(--p) != '/') ;
strcpy(pidstr, p+1);
pid = atoi(pidstr);
globfree(&gt);
return pid;
}
}
}
globfree(&gt);
return -1;
}
void ql_get_driver_rmnet_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) {
if (errno != ENOTSUP)
dbg_time("ioctl(0x%x, qmap_settings) errno:%d (%s), rc=%d", request, errno, strerror(errno), rc);
}
else {
memcpy(rmnet_info, data, sizeof(*rmnet_info));
}
close(ifc_ctl_sock);
}
void ql_set_driver_qmap_setting(PROFILE_T *profile, QMAP_SETTING *qmap_settings) {
int ifc_ctl_sock;
struct ifreq ifr;
int rc;
int request = 0x89F2;
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 *)qmap_settings;
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);
}
close(ifc_ctl_sock);
}
void no_trunc_strncpy(char *dest, const char *src, size_t dest_size)
{
size_t i = 0;
for (i = 0; i < dest_size && *src; i++) {
*dest++ = *src++;
}
*dest = 0;
}

View File

@ -1,52 +0,0 @@
/**
@file
util.h
@brief
This file provides the definitions, and declares some common APIs for list-algorithm.
*/
#ifndef _UTILS_H_
#define _UTILS_H_
#include <stddef.h>
#include <glob.h>
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 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);
const char * get_time(void);
unsigned long clock_msec(void);
pid_t getpid_by_pdp(int, const char*);
#endif

View File

@ -1,4 +1,3 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=sendat
@ -10,22 +9,17 @@ PKG_SOURCE_DATE:=2023-10-26
PKG_SOURCE_VERSION:=c830885db5bb8ae2dcb10b1bfeab481f14935dd1
PKG_MIRROR_HASH:=898a3e98babcafb9f200b80f840dfc655d44df7471180d093fffd00c10194360
MAKE_PATH:=src
include $(INCLUDE_DIR)/package.mk
define Package/sendat
SECTION:=utils
CATEGORY:=Utilities
SUBMENU :=CPE
TITLE:=Sendat AT
TITLE:=Send AT Commnad
DEPENDS:=+libpthread
endef
define Package/sendat/description
AT Commnad for sendat test
endef
MAKE_PATH:=src
define Package/sendat/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/sendat $(1)/usr/bin/

View File

@ -17,7 +17,6 @@ include $(INCLUDE_DIR)/package.mk
define KernelPackage/pcie_mhi
SUBMENU:=WWAN Support
TITLE:=Kernel pcie driver for MHI device
DEPENDS:=+pciids +pciutils +quectel-CM-5G
FILES:=$(PKG_BUILD_DIR)/pcie_mhi.ko
AUTOLOAD:=$(call AutoLoad,90,pcie_mhi)
endef