🌴 Sync 2026-03-05 23:51:42

This commit is contained in:
github-actions[bot] committed 2026-03-05 23:51:42 +08:00
1 parent 97c049ed0a
commit 0acff03804
14253 files changed
+3893239

No files matched your search

+34
View File
@@ -0,0 +1,34 @@
include $(TOPDIR)/rules.mk
PKG_NAME:= meig-cm
PKG_VERSION:=1.2.1
PKG_RELEASE:=1
include $(INCLUDE_DIR)/package.mk
define Package/meig-cm
SECTION:=utils
CATEGORY:=Utilities
TITLE:=meig-cm 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/meig-cm/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/meig-cm $(1)/usr/bin
endef
$(eval $(call BuildPackage,meig-cm))
+229
View File
@@ -0,0 +1,229 @@
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <stdio.h>
#include <ctype.h>
#include "QMIThread.h"
#ifdef CONFIG_GOBINET
// IOCTL to generate a client ID for this service type
#define IOCTL_QMI_GET_SERVICE_FILE 0x8BE0 + 1
// IOCTL to get the VIDPID of the device
#define IOCTL_QMI_GET_DEVICE_VIDPID 0x8BE0 + 2
// IOCTL to get the MEID of the device
#define IOCTL_QMI_GET_DEVICE_MEID 0x8BE0 + 3
static int GobiNetSendQMI(PQCQMIMSG pRequest) {
int ret, fd;
fd = qmiclientId[pRequest->QMIHdr.QMIType];
if (fd <= 0) {
dbg_time("%s QMIType: %d has no clientID", __func__, pRequest->QMIHdr.QMIType);
return -ENODEV;
}
// Always ready to write
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 = open(qcqmi, O_RDWR | O_NONBLOCK | O_NOCTTY);
if (ClientId == -1) {
dbg_time("failed to open %s, errno: %d (%s)", qcqmi, errno, strerror(errno));
return -1;
}
if (ioctl(ClientId, IOCTL_QMI_GET_SERVICE_FILE, QMIType) != 0) {
dbg_time("failed to get ClientID for 0x%02x errno: %d (%s)", QMIType, errno, strerror(errno));
close(ClientId);
ClientId = 0;
}
switch (QMIType) {
case QMUX_TYPE_WDS: dbg_time("Get clientWDS = %d", ClientId); break;
case QMUX_TYPE_DMS: dbg_time("Get clientDMS = %d", ClientId); break;
case QMUX_TYPE_NAS: dbg_time("Get clientNAS = %d", ClientId); break;
case QMUX_TYPE_QOS: dbg_time("Get clientQOS = %d", ClientId); break;
case QMUX_TYPE_WMS: dbg_time("Get clientWMS = %d", ClientId); break;
case QMUX_TYPE_PDS: dbg_time("Get clientPDS = %d", ClientId); break;
case QMUX_TYPE_UIM: dbg_time("Get clientUIM = %d", ClientId); break;
case QMUX_TYPE_WDS_ADMIN: dbg_time("Get clientWDA = %d", ClientId);
break;
default: break;
}
return ClientId;
}
static int GobiNetDeInit(void) {
unsigned int i;
for (i = 0; i < sizeof(qmiclientId)/sizeof(qmiclientId[0]); i++)
{
if (qmiclientId[i] != 0)
{
close(qmiclientId[i]);
qmiclientId[i] = 0;
}
}
return 0;
}
static void * GobiNetThread(void *pData) {
PROFILE_T *profile = (PROFILE_T *)pData;
const char *qcqmi = (const char *)profile->qmichannel;
int wait_for_request_quit = 0;
qmiclientId[QMUX_TYPE_WDS] = GobiNetGetClientID(qcqmi, QMUX_TYPE_WDS);
if (profile->enable_ipv6 || profile->IsDualIPSupported)
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);
if (profile->qmap_mode == 0) //when QMAP enabled, set data format in GobiNet Driver
qmiclientId[QMUX_TYPE_WDS_ADMIN] = GobiNetGetClientID(qcqmi, QMUX_TYPE_WDS_ADMIN);
//donot check clientWDA, there is only one client for WDA, if meig-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 SIGTERM:
case SIGHUP:
case SIGINT:
wait_for_request_quit = 1;
break;
default:
break;
}
}
continue;
}
{
ssize_t nreads;
UCHAR QMIBuf[512];
PQCQMIMSG pResponse = (PQCQMIMSG)QMIBuf;
nreads = read(fd, &pResponse->MUXMsg, sizeof(QMIBuf) - sizeof(QCQMI_HDR));
if (nreads <= 0)
{
dbg_time("%s read=%d errno: %d (%s)", __func__, (int)nreads, errno, strerror(errno));
break;
}
for (i = 0; i < sizeof(qmiclientId)/sizeof(qmiclientId[0]); i++)
{
if (qmiclientId[i] == fd)
{
pResponse->QMIHdr.QMIType = i;
}
}
pResponse->QMIHdr.IFType = USB_CTL_MSG_TYPE_QMI;
pResponse->QMIHdr.Length = cpu_to_le16(nreads + sizeof(QCQMI_HDR) - 1);
pResponse->QMIHdr.CtlFlags = 0x00;
pResponse->QMIHdr.ClientId = fd & 0xFF;
QmiThreadRecvQMI(pResponse);
}
}
}
__GobiNetThread_quit:
GobiNetDeInit();
qmidevice_send_event_to_main(RIL_INDICATE_DEVICE_DISCONNECTED);
QmiThreadRecvQMI(NULL); //main thread may pending on QmiThreadSendQMI()
dbg_time("%s exit", __func__);
pthread_exit(NULL);
return NULL;
}
#else
static int GobiNetSendQMI(PQCQMIMSG pRequest) {return -1;}
static void * GobiNetThread(void *pData) {dbg_time("please set CONFIG_GOBINET"); return NULL;}
#endif
const struct qmi_device_ops gobi_qmidev_ops = {
.deinit = GobiNetDeInit,
.send = GobiNetSendQMI,
.read = GobiNetThread,
};
+377
View File
@@ -0,0 +1,377 @@
/*===========================================================================
M P Q C T L. H
DESCRIPTION:
This module contains QMI QCTL module.
INITIALIZATION AND SEQUENCING REQUIREMENTS:
Copyright (C) 2011 by Qualcomm Technologies, Incorporated. All Rights Reserved.
===========================================================================*/
#ifndef MPQCTL_H
#define MPQCTL_H
#include "MPQMI.h"
#pragma pack(push, 1)
// ================= QMICTL ==================
// QMICTL Control Flags
#define QMICTL_CTL_FLAG_CMD 0x00
#define QMICTL_CTL_FLAG_RSP 0x01
#define QMICTL_CTL_FLAG_IND 0x02
#if 0
typedef struct _QMICTL_TRANSACTION_ITEM
{
LIST_ENTRY List;
UCHAR TransactionId; // QMICTL transaction id
PVOID Context; // Adapter or IocDev
PIRP Irp;
} QMICTL_TRANSACTION_ITEM, *PQMICTL_TRANSACTION_ITEM;
#endif
typedef struct _QCQMICTL_MSG_HDR
{
UCHAR CtlFlags; // 00-cmd, 01-rsp, 10-ind
UCHAR TransactionId;
USHORT QMICTLType;
USHORT Length;
} __attribute__ ((packed)) QCQMICTL_MSG_HDR, *PQCQMICTL_MSG_HDR;
#define QCQMICTL_MSG_HDR_SIZE sizeof(QCQMICTL_MSG_HDR)
typedef struct _QCQMICTL_MSG_HDR_RESP
{
UCHAR CtlFlags; // 00-cmd, 01-rsp, 10-ind
UCHAR TransactionId;
USHORT QMICTLType;
USHORT Length;
UCHAR TLVType; // 0x02 - result code
USHORT TLVLength; // 4
USHORT QMUXResult; // QMI_RESULT_SUCCESS
// QMI_RESULT_FAILURE
USHORT QMUXError; // QMI_ERR_INVALID_ARG
// QMI_ERR_NO_MEMORY
// QMI_ERR_INTERNAL
// QMI_ERR_FAULT
} __attribute__ ((packed)) QCQMICTL_MSG_HDR_RESP, *PQCQMICTL_MSG_HDR_RESP;
typedef struct _QCQMICTL_MSG
{
UCHAR CtlFlags; // 00-cmd, 01-rsp, 10-ind
UCHAR TransactionId;
USHORT QMICTLType;
USHORT Length;
UCHAR Payload;
} __attribute__ ((packed)) QCQMICTL_MSG, *PQCQMICTL_MSG;
// TLV Header
typedef struct _QCQMICTL_TLV_HDR
{
UCHAR TLVType;
USHORT TLVLength;
} __attribute__ ((packed)) QCQMICTL_TLV_HDR, *PQCQMICTL_TLV_HDR;
#define QCQMICTL_TLV_HDR_SIZE sizeof(QCQMICTL_TLV_HDR)
// QMICTL Type
#define QMICTL_SET_INSTANCE_ID_REQ 0x0020
#define QMICTL_SET_INSTANCE_ID_RESP 0x0020
#define QMICTL_GET_VERSION_REQ 0x0021
#define QMICTL_GET_VERSION_RESP 0x0021
#define QMICTL_GET_CLIENT_ID_REQ 0x0022
#define QMICTL_GET_CLIENT_ID_RESP 0x0022
#define QMICTL_RELEASE_CLIENT_ID_REQ 0x0023
#define QMICTL_RELEASE_CLIENT_ID_RESP 0x0023
#define QMICTL_REVOKE_CLIENT_ID_IND 0x0024
#define QMICTL_INVALID_CLIENT_ID_IND 0x0025
#define QMICTL_SET_DATA_FORMAT_REQ 0x0026
#define QMICTL_SET_DATA_FORMAT_RESP 0x0026
#define QMICTL_SYNC_REQ 0x0027
#define QMICTL_SYNC_RESP 0x0027
#define QMICTL_SYNC_IND 0x0027
#define QMICTL_FLAG_REQUEST 0x00
#define QMICTL_FLAG_RESPONSE 0x01
#define QMICTL_FLAG_INDICATION 0x02
// QMICTL Message Definitions
typedef struct _QMICTL_SET_INSTANCE_ID_REQ_MSG
{
UCHAR CtlFlags; // QMICTL_FLAG_REQUEST
UCHAR TransactionId;
USHORT QMICTLType; // QMICTL_SET_INSTANCE_ID_REQ
USHORT Length; // 4
UCHAR TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER
USHORT TLVLength; // 1
UCHAR Value; // Host-unique QMI instance for this device driver
} __attribute__ ((packed)) QMICTL_SET_INSTANCE_ID_REQ_MSG, *PQMICTL_SET_INSTANCE_ID_REQ_MSG;
typedef struct _QMICTL_SET_INSTANCE_ID_RESP_MSG
{
UCHAR CtlFlags; // QMICTL_FLAG_RESPONSE
UCHAR TransactionId;
USHORT QMICTLType; // QMICTL_SET_INSTANCE_ID_RESP
USHORT Length;
UCHAR TLVType; // QCTLV_TYPE_RESULT_CODE
USHORT TLVLength; // 0x0004
USHORT QMIResult;
USHORT QMIError;
UCHAR TLV2Type; // QCTLV_TYPE_REQUIRED_PARAMETER
USHORT TLV2Length; // 0x0002
USHORT QMI_ID; // Upper byte is assigned by MSM,
// lower assigned by host
} __attribute__ ((packed)) QMICTL_SET_INSTANCE_ID_RESP_MSG, *PQMICTL_SET_INSTANCE_ID_RESP_MSG;
typedef struct _QMICTL_GET_VERSION_REQ_MSG
{
UCHAR CtlFlags; // QMICTL_FLAG_REQUEST
UCHAR TransactionId;
USHORT QMICTLType; // QMICTL_GET_VERSION_REQ
USHORT Length; // 0
UCHAR TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER
USHORT TLVLength; // var
UCHAR QMUXTypes; // List of one byte QMUX_TYPE values
// 0xFF returns a list of versions for all
// QMUX_TYPEs implemented on the device
} __attribute__ ((packed)) QMICTL_GET_VERSION_REQ_MSG, *PQMICTL_GET_VERSION_REQ_MSG;
typedef struct _QMUX_TYPE_VERSION_STRUCT
{
UCHAR QMUXType;
USHORT MajorVersion;
USHORT MinorVersion;
} __attribute__ ((packed)) QMUX_TYPE_VERSION_STRUCT, *PQMUX_TYPE_VERSION_STRUCT;
typedef struct _ADDENDUM_VERSION_PREAMBLE
{
UCHAR LabelLength;
UCHAR Label;
} __attribute__ ((packed)) ADDENDUM_VERSION_PREAMBLE, *PADDENDUM_VERSION_PREAMBLE;
#define QMICTL_GET_VERSION_RSP_TLV_TYPE_VERSION 0x01
#define QMICTL_GET_VERSION_RSP_TLV_TYPE_ADD_VERSION 0x10
typedef struct _QMICTL_GET_VERSION_RESP_MSG
{
UCHAR CtlFlags; // QMICTL_FLAG_RESPONSE
UCHAR TransactionId;
USHORT QMICTLType; // QMICTL_GET_VERSION_RESP
USHORT Length;
UCHAR TLVType; // QCTLV_TYPE_RESULT_CODE
USHORT TLVLength; // 0x0004
USHORT QMIResult;
USHORT QMIError;
UCHAR TLV2Type; // QCTLV_TYPE_REQUIRED_PARAMETER
USHORT TLV2Length; // var
UCHAR NumElements; // Num of QMUX_TYPE_VERSION_STRUCT
QMUX_TYPE_VERSION_STRUCT TypeVersion[0];
} __attribute__ ((packed)) QMICTL_GET_VERSION_RESP_MSG, *PQMICTL_GET_VERSION_RESP_MSG;
typedef struct _QMICTL_GET_CLIENT_ID_REQ_MSG
{
UCHAR CtlFlags; // QMICTL_FLAG_REQUEST
UCHAR TransactionId;
USHORT QMICTLType; // QMICTL_GET_CLIENT_ID_REQ
USHORT Length;
UCHAR TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER
USHORT TLVLength; // 1
UCHAR QMIType; // QMUX type
} __attribute__ ((packed)) QMICTL_GET_CLIENT_ID_REQ_MSG, *PQMICTL_GET_CLIENT_ID_REQ_MSG;
typedef struct _QMICTL_GET_CLIENT_ID_RESP_MSG
{
UCHAR CtlFlags; // QMICTL_FLAG_RESPONSE
UCHAR TransactionId;
USHORT QMICTLType; // QMICTL_GET_CLIENT_ID_RESP
USHORT Length;
UCHAR TLVType; // QCTLV_TYPE_RESULT_CODE
USHORT TLVLength; // 0x0004
USHORT QMIResult; // result code
USHORT QMIError; // error code
UCHAR TLV2Type; // QCTLV_TYPE_REQUIRED_PARAMETER
USHORT TLV2Length; // 2
UCHAR QMIType;
UCHAR ClientId;
} __attribute__ ((packed)) QMICTL_GET_CLIENT_ID_RESP_MSG, *PQMICTL_GET_CLIENT_ID_RESP_MSG;
typedef struct _QMICTL_RELEASE_CLIENT_ID_REQ_MSG
{
UCHAR CtlFlags; // QMICTL_FLAG_REQUEST
UCHAR TransactionId;
USHORT QMICTLType; // QMICTL_RELEASE_CLIENT_ID_REQ
USHORT Length;
UCHAR TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER
USHORT TLVLength; // 0x0002
UCHAR QMIType;
UCHAR ClientId;
} __attribute__ ((packed)) QMICTL_RELEASE_CLIENT_ID_REQ_MSG, *PQMICTL_RELEASE_CLIENT_ID_REQ_MSG;
typedef struct _QMICTL_RELEASE_CLIENT_ID_RESP_MSG
{
UCHAR CtlFlags; // QMICTL_FLAG_RESPONSE
UCHAR TransactionId;
USHORT QMICTLType; // QMICTL_RELEASE_CLIENT_ID_RESP
USHORT Length;
UCHAR TLVType; // QCTLV_TYPE_RESULT_CODE
USHORT TLVLength; // 0x0004
USHORT QMIResult; // result code
USHORT QMIError; // error code
UCHAR TLV2Type; // QCTLV_TYPE_REQUIRED_PARAMETER
USHORT TLV2Length; // 2
UCHAR QMIType;
UCHAR ClientId;
} __attribute__ ((packed)) QMICTL_RELEASE_CLIENT_ID_RESP_MSG, *PQMICTL_RELEASE_CLIENT_ID_RESP_MSG;
typedef struct _QMICTL_REVOKE_CLIENT_ID_IND_MSG
{
UCHAR CtlFlags; // QMICTL_FLAG_INDICATION
UCHAR TransactionId;
USHORT QMICTLType; // QMICTL_REVOKE_CLIENT_ID_IND
USHORT Length;
UCHAR TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER
USHORT TLVLength; // 0x0002
UCHAR QMIType;
UCHAR ClientId;
} __attribute__ ((packed)) QMICTL_REVOKE_CLIENT_ID_IND_MSG, *PQMICTL_REVOKE_CLIENT_ID_IND_MSG;
typedef struct _QMICTL_INVALID_CLIENT_ID_IND_MSG
{
UCHAR CtlFlags; // QMICTL_FLAG_INDICATION
UCHAR TransactionId;
USHORT QMICTLType; // QMICTL_REVOKE_CLIENT_ID_IND
USHORT Length;
UCHAR TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER
USHORT TLVLength; // 0x0002
UCHAR QMIType;
UCHAR ClientId;
} __attribute__ ((packed)) QMICTL_INVALID_CLIENT_ID_IND_MSG, *PQMICTL_INVALID_CLIENT_ID_IND_MSG;
typedef struct _QMICTL_SET_DATA_FORMAT_REQ_MSG
{
UCHAR CtlFlags; // QMICTL_FLAG_REQUEST
UCHAR TransactionId;
USHORT QMICTLType; // QMICTL_SET_DATA_FORMAT_REQ
USHORT Length;
UCHAR TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER
USHORT TLVLength; // 1
UCHAR DataFormat; // 0-default; 1-QoS hdr present
} __attribute__ ((packed)) QMICTL_SET_DATA_FORMAT_REQ_MSG, *PQMICTL_SET_DATA_FORMAT_REQ_MSG;
#ifdef QC_IP_MODE
#define SET_DATA_FORMAT_TLV_TYPE_LINK_PROTO 0x10
#define SET_DATA_FORMAT_LINK_PROTO_ETH 0x0001
#define SET_DATA_FORMAT_LINK_PROTO_IP 0x0002
typedef struct _QMICTL_SET_DATA_FORMAT_TLV_LINK_PROT
{
UCHAR TLVType; // Link-Layer Protocol
USHORT TLVLength; // 2
USHORT LinkProt; // 0x1: ETH; 0x2: IP
} QMICTL_SET_DATA_FORMAT_TLV_LINK_PROT, *PQMICTL_SET_DATA_FORMAT_TLV_LINK_PROT;
#ifdef QCMP_UL_TLP
#define SET_DATA_FORMAT_TLV_TYPE_UL_TLP 0x11
typedef struct _QMICTL_SET_DATA_FORMAT_TLV_UL_TLP
{
UCHAR TLVType; // 0x11, Uplink TLP Setting
USHORT TLVLength; // 1
UCHAR UlTlpSetting; // 0x0: Disable; 0x01: Enable
} QMICTL_SET_DATA_FORMAT_TLV_UL_TLP, *PQMICTL_SET_DATA_FORMAT_TLV_UL_TLP;
#endif // QCMP_UL_TLP
#ifdef QCMP_DL_TLP
#define SET_DATA_FORMAT_TLV_TYPE_DL_TLP 0x13
typedef struct _QMICTL_SET_DATA_FORMAT_TLV_DL_TLP
{
UCHAR TLVType; // 0x11, Uplink TLP Setting
USHORT TLVLength; // 1
UCHAR DlTlpSetting; // 0x0: Disable; 0x01: Enable
} QMICTL_SET_DATA_FORMAT_TLV_DL_TLP, *PQMICTL_SET_DATA_FORMAT_TLV_DL_TLP;
#endif // QCMP_DL_TLP
#endif // QC_IP_MODE
#ifdef MP_QCQOS_ENABLED
#define SET_DATA_FORMAT_TLV_TYPE_QOS_SETTING 0x12
typedef struct _QMICTL_SET_DATA_FORMAT_TLV_QOS_SETTING
{
UCHAR TLVType; // 0x12, QoS setting
USHORT TLVLength; // 1
UCHAR QosSetting; // 0x0: Disable; 0x01: Enable
} QMICTL_SET_DATA_FORMAT_TLV_QOS_SETTING, *PQMICTL_SET_DATA_FORMAT_TLV_QOS_SETTING;
#endif // MP_QCQOS_ENABLED
typedef struct _QMICTL_SET_DATA_FORMAT_RESP_MSG
{
UCHAR CtlFlags; // QMICTL_FLAG_RESPONSE
UCHAR TransactionId;
USHORT QMICTLType; // QMICTL_SET_DATA_FORMAT_RESP
USHORT Length;
UCHAR TLVType; // QCTLV_TYPE_RESULT_CODE
USHORT TLVLength; // 0x0004
USHORT QMIResult; // result code
USHORT QMIError; // error code
} __attribute__ ((packed)) QMICTL_SET_DATA_FORMAT_RESP_MSG, *PQMICTL_SET_DATA_FORMAT_RESP_MSG;
typedef struct _QMICTL_SYNC_REQ_MSG
{
UCHAR CtlFlags; // QMICTL_FLAG_REQUEST
UCHAR TransactionId;
USHORT QMICTLType; // QMICTL_CTL_SYNC_REQ
USHORT Length; // 0
} __attribute__ ((packed)) QMICTL_SYNC_REQ_MSG, *PQMICTL_SYNC_REQ_MSG;
typedef struct _QMICTL_SYNC_RESP_MSG
{
UCHAR CtlFlags; // QMICTL_FLAG_RESPONSE
UCHAR TransactionId;
USHORT QMICTLType; // QMICTL_CTL_SYNC_RESP
USHORT Length;
UCHAR TLVType; // QCTLV_TYPE_RESULT_CODE
USHORT TLVLength; // 0x0004
USHORT QMIResult;
USHORT QMIError;
} __attribute__ ((packed)) QMICTL_SYNC_RESP_MSG, *PQMICTL_SYNC_RESP_MSG;
typedef struct _QMICTL_SYNC_IND_MSG
{
UCHAR CtlFlags; // QMICTL_FLAG_INDICATION
UCHAR TransactionId;
USHORT QMICTLType; // QMICTL_REVOKE_CLIENT_ID_IND
USHORT Length;
} __attribute__ ((packed)) QMICTL_SYNC_IND_MSG, *PQMICTL_SYNC_IND_MSG;
typedef struct _QMICTL_MSG
{
union
{
// Message Header
QCQMICTL_MSG_HDR QMICTLMsgHdr;
QCQMICTL_MSG_HDR_RESP QMICTLMsgHdrRsp;
// QMICTL Message
QMICTL_SET_INSTANCE_ID_REQ_MSG SetInstanceIdReq;
QMICTL_SET_INSTANCE_ID_RESP_MSG SetInstanceIdRsp;
QMICTL_GET_VERSION_REQ_MSG GetVersionReq;
QMICTL_GET_VERSION_RESP_MSG GetVersionRsp;
QMICTL_GET_CLIENT_ID_REQ_MSG GetClientIdReq;
QMICTL_GET_CLIENT_ID_RESP_MSG GetClientIdRsp;
QMICTL_RELEASE_CLIENT_ID_REQ_MSG ReleaseClientIdReq;
QMICTL_RELEASE_CLIENT_ID_RESP_MSG ReleaseClientIdRsp;
QMICTL_REVOKE_CLIENT_ID_IND_MSG RevokeClientIdInd;
QMICTL_INVALID_CLIENT_ID_IND_MSG InvalidClientIdInd;
QMICTL_SET_DATA_FORMAT_REQ_MSG SetDataFormatReq;
QMICTL_SET_DATA_FORMAT_RESP_MSG SetDataFormatRsp;
QMICTL_SYNC_REQ_MSG SyncReq;
QMICTL_SYNC_RESP_MSG SyncRsp;
QMICTL_SYNC_IND_MSG SyncInd;
};
} __attribute__ ((packed)) QMICTL_MSG, *PQMICTL_MSG;
#pragma pack(pop)
#endif // MPQCTL_H
+301
View File
@@ -0,0 +1,301 @@
/*===========================================================================
M P Q M I. H
DESCRIPTION:
This module contains forward references to the QMI module.
INITIALIZATION AND SEQUENCING REQUIREMENTS:
Copyright (C) 2011 by Qualcomm Technologies, Incorporated. All Rights Reserved.
===========================================================================*/
/*===========================================================================
EDIT HISTORY FOR FILE
$Header: //depot/QMI/win/qcdrivers/ndis/MPQMI.h#3 $
when who what, where, why
-------- --- ----------------------------------------------------------
11/20/04 hg Initial version.
===========================================================================*/
#ifndef USBQMI_H
#define USBQMI_H
typedef char CHAR;
typedef unsigned char UCHAR;
typedef unsigned short USHORT;
typedef int INT;
typedef unsigned int UINT;
typedef long LONG;
typedef unsigned int ULONG;
typedef unsigned long long ULONG64;
typedef char *PCHAR;
typedef unsigned char *PUCHAR;
typedef int *PINT;
typedef int BOOL;
#define TRUE (1 == 1)
#define FALSE (1 != 1)
#define QMICTL_SUPPORTED_MAJOR_VERSION 1
#define QMICTL_SUPPORTED_MINOR_VERSION 0
#pragma pack(push, 1)
// ========= USB Control Message ==========
#define USB_CTL_MSG_TYPE_QMI 0x01
// USB Control Message
typedef struct _QCUSB_CTL_MSG_HDR
{
UCHAR IFType;
} __attribute__ ((packed)) QCUSB_CTL_MSG_HDR, *PQCUSB_CTL_MSG_HDR;
#define QCUSB_CTL_MSG_HDR_SIZE sizeof(QCUSB_CTL_MSG_HDR)
typedef struct _QCUSB_CTL_MSG
{
UCHAR IFType;
UCHAR Message;
} __attribute__ ((packed)) QCUSB_CTL_MSG, *PQCUSB_CTL_MSG;
#define QCTLV_TYPE_REQUIRED_PARAMETER 0x01
#define QCTLV_TYPE_RESULT_CODE 0x02
// ================= QMI ==================
// Define QMI Type
typedef enum _QMI_SERVICE_TYPE
{
QMUX_TYPE_CTL = 0x00,
QMUX_TYPE_WDS = 0x01,
QMUX_TYPE_DMS = 0x02,
QMUX_TYPE_NAS = 0x03,
QMUX_TYPE_QOS = 0x04,
QMUX_TYPE_WMS = 0x05,
QMUX_TYPE_PDS = 0x06,
QMUX_TYPE_UIM = 0x0B,
QMUX_TYPE_WDS_IPV6 = 0x11,
QMUX_TYPE_WDS_ADMIN = 0x1A,
QMUX_TYPE_MAX = 0xFF,
QMUX_TYPE_ALL = 0xFF
} QMI_SERVICE_TYPE;
typedef enum _QMI_RESULT_CODE_TYPE
{
QMI_RESULT_SUCCESS = 0x0000,
QMI_RESULT_FAILURE = 0x0001
} QMI_RESULT_CODE_TYPE;
typedef enum _QMI_ERROR_CODE_TYPE
{
QMI_ERR_NONE = 0x0000
,QMI_ERR_MALFORMED_MSG = 0x0001
,QMI_ERR_NO_MEMORY = 0x0002
,QMI_ERR_INTERNAL = 0x0003
,QMI_ERR_ABORTED = 0x0004
,QMI_ERR_CLIENT_IDS_EXHAUSTED = 0x0005
,QMI_ERR_UNABORTABLE_TRANSACTION = 0x0006
,QMI_ERR_INVALID_CLIENT_ID = 0x0007
,QMI_ERR_NO_THRESHOLDS = 0x0008
,QMI_ERR_INVALID_HANDLE = 0x0009
,QMI_ERR_INVALID_PROFILE = 0x000A
,QMI_ERR_INVALID_PINID = 0x000B
,QMI_ERR_INCORRECT_PIN = 0x000C
,QMI_ERR_NO_NETWORK_FOUND = 0x000D
,QMI_ERR_CALL_FAILED = 0x000E
,QMI_ERR_OUT_OF_CALL = 0x000F
,QMI_ERR_NOT_PROVISIONED = 0x0010
,QMI_ERR_MISSING_ARG = 0x0011
,QMI_ERR_ARG_TOO_LONG = 0x0013
,QMI_ERR_INVALID_TX_ID = 0x0016
,QMI_ERR_DEVICE_IN_USE = 0x0017
,QMI_ERR_OP_NETWORK_UNSUPPORTED = 0x0018
,QMI_ERR_OP_DEVICE_UNSUPPORTED = 0x0019
,QMI_ERR_NO_EFFECT = 0x001A
,QMI_ERR_NO_FREE_PROFILE = 0x001B
,QMI_ERR_INVALID_PDP_TYPE = 0x001C
,QMI_ERR_INVALID_TECH_PREF = 0x001D
,QMI_ERR_INVALID_PROFILE_TYPE = 0x001E
,QMI_ERR_INVALID_SERVICE_TYPE = 0x001F
,QMI_ERR_INVALID_REGISTER_ACTION = 0x0020
,QMI_ERR_INVALID_PS_ATTACH_ACTION = 0x0021
,QMI_ERR_AUTHENTICATION_FAILED = 0x0022
,QMI_ERR_PIN_BLOCKED = 0x0023
,QMI_ERR_PIN_PERM_BLOCKED = 0x0024
,QMI_ERR_SIM_NOT_INITIALIZED = 0x0025
,QMI_ERR_MAX_QOS_REQUESTS_IN_USE = 0x0026
,QMI_ERR_INCORRECT_FLOW_FILTER = 0x0027
,QMI_ERR_NETWORK_QOS_UNAWARE = 0x0028
,QMI_ERR_INVALID_QOS_ID = 0x0029
,QMI_ERR_INVALID_ID = 0x0029
,QMI_ERR_REQUESTED_NUM_UNSUPPORTED = 0x002A
,QMI_ERR_INTERFACE_NOT_FOUND = 0x002B
,QMI_ERR_FLOW_SUSPENDED = 0x002C
,QMI_ERR_INVALID_DATA_FORMAT = 0x002D
,QMI_ERR_GENERAL = 0x002E
,QMI_ERR_UNKNOWN = 0x002F
,QMI_ERR_INVALID_ARG = 0x0030
,QMI_ERR_INVALID_INDEX = 0x0031
,QMI_ERR_NO_ENTRY = 0x0032
,QMI_ERR_DEVICE_STORAGE_FULL = 0x0033
,QMI_ERR_DEVICE_NOT_READY = 0x0034
,QMI_ERR_NETWORK_NOT_READY = 0x0035
,QMI_ERR_CAUSE_CODE = 0x0036
,QMI_ERR_MESSAGE_NOT_SENT = 0x0037
,QMI_ERR_MESSAGE_DELIVERY_FAILURE = 0x0038
,QMI_ERR_INVALID_MESSAGE_ID = 0x0039
,QMI_ERR_ENCODING = 0x003A
,QMI_ERR_AUTHENTICATION_LOCK = 0x003B
,QMI_ERR_INVALID_TRANSITION = 0x003C
,QMI_ERR_NOT_A_MCAST_IFACE = 0x003D
,QMI_ERR_MAX_MCAST_REQUESTS_IN_USE = 0x003E
,QMI_ERR_INVALID_MCAST_HANDLE = 0x003F
,QMI_ERR_INVALID_IP_FAMILY_PREF = 0x0040
,QMI_ERR_SESSION_INACTIVE = 0x0041
,QMI_ERR_SESSION_INVALID = 0x0042
,QMI_ERR_SESSION_OWNERSHIP = 0x0043
,QMI_ERR_INSUFFICIENT_RESOURCES = 0x0044
,QMI_ERR_DISABLED = 0x0045
,QMI_ERR_INVALID_OPERATION = 0x0046
,QMI_ERR_INVALID_QMI_CMD = 0x0047
,QMI_ERR_TPDU_TYPE = 0x0048
,QMI_ERR_SMSC_ADDR = 0x0049
,QMI_ERR_INFO_UNAVAILABLE = 0x004A
,QMI_ERR_SEGMENT_TOO_LONG = 0x004B
,QMI_ERR_SEGMENT_ORDER = 0x004C
,QMI_ERR_BUNDLING_NOT_SUPPORTED = 0x004D
,QMI_ERR_OP_PARTIAL_FAILURE = 0x004E
,QMI_ERR_POLICY_MISMATCH = 0x004F
,QMI_ERR_SIM_FILE_NOT_FOUND = 0x0050
,QMI_ERR_EXTENDED_INTERNAL = 0x0051
,QMI_ERR_ACCESS_DENIED = 0x0052
,QMI_ERR_HARDWARE_RESTRICTED = 0x0053
,QMI_ERR_ACK_NOT_SENT = 0x0054
,QMI_ERR_INJECT_TIMEOUT = 0x0055
,QMI_ERR_INCOMPATIBLE_STATE = 0x005A
,QMI_ERR_FDN_RESTRICT = 0x005B
,QMI_ERR_SUPS_FAILURE_CAUSE = 0x005C
,QMI_ERR_NO_RADIO = 0x005D
,QMI_ERR_NOT_SUPPORTED = 0x005E
,QMI_ERR_NO_SUBSCRIPTION = 0x005F
,QMI_ERR_CARD_CALL_CONTROL_FAILED = 0x0060
,QMI_ERR_NETWORK_ABORTED = 0x0061
,QMI_ERR_MSG_BLOCKED = 0x0062
,QMI_ERR_INVALID_SESSION_TYPE = 0x0064
,QMI_ERR_INVALID_PB_TYPE = 0x0065
,QMI_ERR_NO_SIM = 0x0066
,QMI_ERR_PB_NOT_READY = 0x0067
,QMI_ERR_PIN_RESTRICTION = 0x0068
,QMI_ERR_PIN2_RESTRICTION = 0x0069
,QMI_ERR_PUK_RESTRICTION = 0x006A
,QMI_ERR_PUK2_RESTRICTION = 0x006B
,QMI_ERR_PB_ACCESS_RESTRICTED = 0x006C
,QMI_ERR_PB_DELETE_IN_PROG = 0x006D
,QMI_ERR_PB_TEXT_TOO_LONG = 0x006E
,QMI_ERR_PB_NUMBER_TOO_LONG = 0x006F
,QMI_ERR_PB_HIDDEN_KEY_RESTRICTION = 0x0070
} QMI_ERROR_CODE_TYPE;
#define QCQMI_CTL_FLAG_SERVICE 0x80
#define QCQMI_CTL_FLAG_CTL_POINT 0x00
typedef struct _QCQMI_HDR
{
UCHAR IFType;
USHORT Length;
UCHAR CtlFlags; // reserved
UCHAR QMIType;
UCHAR ClientId;
} __attribute__ ((packed)) QCQMI_HDR, *PQCQMI_HDR;
#define QCQMI_HDR_SIZE (sizeof(QCQMI_HDR)-1)
typedef struct _QCQMI
{
UCHAR IFType;
USHORT Length;
UCHAR CtlFlags; // reserved
UCHAR QMIType;
UCHAR ClientId;
UCHAR SDU;
} __attribute__ ((packed)) QCQMI, *PQCQMI;
typedef struct _QMI_SERVICE_VERSION
{
USHORT Major;
USHORT Minor;
USHORT AddendumMajor;
USHORT AddendumMinor;
} __attribute__ ((packed)) QMI_SERVICE_VERSION, *PQMI_SERVICE_VERSION;
// ================= QMUX ==================
#define QMUX_MSG_OVERHEAD_BYTES 4 // Type(USHORT) Length(USHORT) -- header
#define QMUX_BROADCAST_CID 0xFF
typedef struct _QCQMUX_HDR
{
UCHAR CtlFlags; // 0: single QMUX Msg; 1:
USHORT TransactionId;
} __attribute__ ((packed)) QCQMUX_HDR, *PQCQMUX_HDR;
typedef struct _QCQMUX
{
UCHAR CtlFlags; // 0: single QMUX Msg; 1:
USHORT TransactionId;
UCHAR Message; // Type(2), Length(2), Value
} __attribute__ ((packed)) QCQMUX, *PQCQMUX;
#define QCQMUX_HDR_SIZE sizeof(QCQMUX_HDR)
typedef struct _QCQMUX_MSG_HDR
{
USHORT Type;
USHORT Length;
} __attribute__ ((packed)) QCQMUX_MSG_HDR, *PQCQMUX_MSG_HDR;
#define QCQMUX_MSG_HDR_SIZE sizeof(QCQMUX_MSG_HDR)
typedef struct _QCQMUX_MSG_HDR_RESP
{
USHORT Type;
USHORT Length;
UCHAR TLVType; // 0x02 - result code
USHORT TLVLength; // 4
USHORT QMUXResult; // QMI_RESULT_SUCCESS
// QMI_RESULT_FAILURE
USHORT QMUXError; // QMI_ERR_INVALID_ARG
// QMI_ERR_NO_MEMORY
// QMI_ERR_INTERNAL
// QMI_ERR_FAULT
} __attribute__ ((packed)) QCQMUX_MSG_HDR_RESP, *PQCQMUX_MSG_HDR_RESP;
typedef struct _QCQMUX_TLV
{
UCHAR Type;
USHORT Length;
UCHAR Value;
} __attribute__ ((packed)) QCQMUX_TLV, *PQCQMUX_TLV;
typedef struct _QMI_TLV_HDR
{
UCHAR TLVType;
USHORT TLVLength;
} __attribute__ ((packed)) QMI_TLV_HDR, *PQMI_TLV_HDR;
// QMUX Message Definitions -- QMI SDU
#define QMUX_CTL_FLAG_SINGLE_MSG 0x00
#define QMUX_CTL_FLAG_COMPOUND_MSG 0x01
#define QMUX_CTL_FLAG_TYPE_CMD 0x00
#define QMUX_CTL_FLAG_TYPE_RSP 0x02
#define QMUX_CTL_FLAG_TYPE_IND 0x04
#define QMUX_CTL_FLAG_MASK_COMPOUND 0x01
#define QMUX_CTL_FLAG_MASK_TYPE 0x06 // 00-cmd, 01-rsp, 10-ind
#pragma pack(pop)
#endif // USBQMI_H
+426
View File
@@ -0,0 +1,426 @@
#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),
};
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_nas_Type[] = {
// ======================= NAS ==============================
qmi_name_item(QMINAS_SET_EVENT_REPORT_REQ), // 0x0002
qmi_name_item(QMINAS_SET_EVENT_REPORT_RESP), // 0x0002
qmi_name_item(QMINAS_EVENT_REPORT_IND), // 0x0002
qmi_name_item(QMINAS_GET_SIGNAL_STRENGTH_REQ), // 0x0020
qmi_name_item(QMINAS_GET_SIGNAL_STRENGTH_RESP), // 0x0020
qmi_name_item(QMINAS_PERFORM_NETWORK_SCAN_REQ), // 0x0021
qmi_name_item(QMINAS_PERFORM_NETWORK_SCAN_RESP), // 0x0021
qmi_name_item(QMINAS_INITIATE_NW_REGISTER_REQ), // 0x0022
qmi_name_item(QMINAS_INITIATE_NW_REGISTER_RESP), // 0x0022
qmi_name_item(QMINAS_INITIATE_ATTACH_REQ), // 0x0023
qmi_name_item(QMINAS_INITIATE_ATTACH_RESP), // 0x0023
qmi_name_item(QMINAS_GET_SERVING_SYSTEM_REQ), // 0x0024
qmi_name_item(QMINAS_GET_SERVING_SYSTEM_RESP), // 0x0024
qmi_name_item(QMINAS_SERVING_SYSTEM_IND), // 0x0024
qmi_name_item(QMINAS_GET_HOME_NETWORK_REQ), // 0x0025
qmi_name_item(QMINAS_GET_HOME_NETWORK_RESP), // 0x0025
qmi_name_item(QMINAS_GET_PREFERRED_NETWORK_REQ), // 0x0026
qmi_name_item(QMINAS_GET_PREFERRED_NETWORK_RESP), // 0x0026
qmi_name_item(QMINAS_SET_PREFERRED_NETWORK_REQ), // 0x0027
qmi_name_item(QMINAS_SET_PREFERRED_NETWORK_RESP), // 0x0027
qmi_name_item(QMINAS_GET_FORBIDDEN_NETWORK_REQ), // 0x0028
qmi_name_item(QMINAS_GET_FORBIDDEN_NETWORK_RESP), // 0x0028
qmi_name_item(QMINAS_SET_FORBIDDEN_NETWORK_REQ), // 0x0029
qmi_name_item(QMINAS_SET_FORBIDDEN_NETWORK_RESP), // 0x0029
qmi_name_item(QMINAS_SET_TECHNOLOGY_PREF_REQ), // 0x002A
qmi_name_item(QMINAS_SET_TECHNOLOGY_PREF_RESP), // 0x002A
qmi_name_item(QMINAS_GET_RF_BAND_INFO_REQ), // 0x0031
qmi_name_item(QMINAS_GET_RF_BAND_INFO_RESP), // 0x0031
qmi_name_item(QMINAS_GET_PLMN_NAME_REQ), // 0x0044
qmi_name_item(QMINAS_GET_PLMN_NAME_RESP), // 0x0044
qmi_name_item(MEIG_PACKET_TRANSFER_START_IND), // 0X100
qmi_name_item(MEIG_PACKET_TRANSFER_END_IND), // 0X101
qmi_name_item(QMINAS_GET_SYS_INFO_REQ), // 0x004D
qmi_name_item(QMINAS_GET_SYS_INFO_RESP), // 0x004D
qmi_name_item(QMINAS_SYS_INFO_IND), // 0x004D
};
static const QMI_NAME_T qmux_wms_Type[] = {
// ======================= WMS ==============================
qmi_name_item(QMIWMS_SET_EVENT_REPORT_REQ), // 0x0001
qmi_name_item(QMIWMS_SET_EVENT_REPORT_RESP), // 0x0001
qmi_name_item(QMIWMS_EVENT_REPORT_IND), // 0x0001
qmi_name_item(QMIWMS_RAW_SEND_REQ), // 0x0020
qmi_name_item(QMIWMS_RAW_SEND_RESP), // 0x0020
qmi_name_item(QMIWMS_RAW_WRITE_REQ), // 0x0021
qmi_name_item(QMIWMS_RAW_WRITE_RESP), // 0x0021
qmi_name_item(QMIWMS_RAW_READ_REQ), // 0x0022
qmi_name_item(QMIWMS_RAW_READ_RESP), // 0x0022
qmi_name_item(QMIWMS_MODIFY_TAG_REQ), // 0x0023
qmi_name_item(QMIWMS_MODIFY_TAG_RESP), // 0x0023
qmi_name_item(QMIWMS_DELETE_REQ), // 0x0024
qmi_name_item(QMIWMS_DELETE_RESP), // 0x0024
qmi_name_item(QMIWMS_GET_MESSAGE_PROTOCOL_REQ), // 0x0030
qmi_name_item(QMIWMS_GET_MESSAGE_PROTOCOL_RESP), // 0x0030
qmi_name_item(QMIWMS_LIST_MESSAGES_REQ), // 0x0031
qmi_name_item(QMIWMS_LIST_MESSAGES_RESP), // 0x0031
qmi_name_item(QMIWMS_GET_SMSC_ADDRESS_REQ), // 0x0034
qmi_name_item(QMIWMS_GET_SMSC_ADDRESS_RESP), // 0x0034
qmi_name_item(QMIWMS_SET_SMSC_ADDRESS_REQ), // 0x0035
qmi_name_item(QMIWMS_SET_SMSC_ADDRESS_RESP), // 0x0035
qmi_name_item(QMIWMS_GET_STORE_MAX_SIZE_REQ), // 0x0036
qmi_name_item(QMIWMS_GET_STORE_MAX_SIZE_RESP), // 0x0036
};
static const QMI_NAME_T qmux_wds_admin_Type[] = {
qmi_name_item(QMIWDS_ADMIN_SET_DATA_FORMAT_REQ), // 0x0020
qmi_name_item(QMIWDS_ADMIN_SET_DATA_FORMAT_RESP), // 0x0020
qmi_name_item(QMIWDS_ADMIN_GET_DATA_FORMAT_REQ), // 0x0021
qmi_name_item(QMIWDS_ADMIN_GET_DATA_FORMAT_RESP), // 0x0021
qmi_name_item(QMIWDS_ADMIN_SET_QMAP_SETTINGS_REQ), // 0x002B
qmi_name_item(QMIWDS_ADMIN_SET_QMAP_SETTINGS_RESP), // 0x002B
qmi_name_item(QMIWDS_ADMIN_GET_QMAP_SETTINGS_REQ), // 0x002C
qmi_name_item(QMIWDS_ADMIN_GET_QMAP_SETTINGS_RESP), // 0x002C
};
static const QMI_NAME_T qmux_uim_Type[] = {
qmi_name_item( QMIUIM_READ_TRANSPARENT_REQ), // 0x0020
qmi_name_item( QMIUIM_READ_TRANSPARENT_RESP), // 0x0020
qmi_name_item( QMIUIM_READ_TRANSPARENT_IND), // 0x0020
qmi_name_item( QMIUIM_READ_RECORD_REQ), // 0x0021
qmi_name_item( QMIUIM_READ_RECORD_RESP), // 0x0021
qmi_name_item( QMIUIM_READ_RECORD_IND), // 0x0021
qmi_name_item( QMIUIM_WRITE_TRANSPARENT_REQ), // 0x0022
qmi_name_item( QMIUIM_WRITE_TRANSPARENT_RESP), // 0x0022
qmi_name_item( QMIUIM_WRITE_TRANSPARENT_IND), // 0x0022
qmi_name_item( QMIUIM_WRITE_RECORD_REQ), // 0x0023
qmi_name_item( QMIUIM_WRITE_RECORD_RESP), // 0x0023
qmi_name_item( QMIUIM_WRITE_RECORD_IND), // 0x0023
qmi_name_item( QMIUIM_SET_PIN_PROTECTION_REQ), // 0x0025
qmi_name_item( QMIUIM_SET_PIN_PROTECTION_RESP), // 0x0025
qmi_name_item( QMIUIM_SET_PIN_PROTECTION_IND), // 0x0025
qmi_name_item( QMIUIM_VERIFY_PIN_REQ), // 0x0026
qmi_name_item( QMIUIM_VERIFY_PIN_RESP), // 0x0026
qmi_name_item( QMIUIM_VERIFY_PIN_IND), // 0x0026
qmi_name_item( QMIUIM_UNBLOCK_PIN_REQ), // 0x0027
qmi_name_item( QMIUIM_UNBLOCK_PIN_RESP), // 0x0027
qmi_name_item( QMIUIM_UNBLOCK_PIN_IND), // 0x0027
qmi_name_item( QMIUIM_CHANGE_PIN_REQ), // 0x0028
qmi_name_item( QMIUIM_CHANGE_PIN_RESP), // 0x0028
qmi_name_item( QMIUIM_CHANGE_PIN_IND), // 0x0028
qmi_name_item( QMIUIM_DEPERSONALIZATION_REQ), // 0x0029
qmi_name_item( QMIUIM_DEPERSONALIZATION_RESP), // 0x0029
qmi_name_item( QMIUIM_EVENT_REG_REQ), // 0x002E
qmi_name_item( QMIUIM_EVENT_REG_RESP), // 0x002E
qmi_name_item( QMIUIM_GET_CARD_STATUS_REQ), // 0x002F
qmi_name_item( QMIUIM_GET_CARD_STATUS_RESP), // 0x002F
qmi_name_item( QMIUIM_STATUS_CHANGE_IND), // 0x0032
};
static const char * qmi_name_get(const QMI_NAME_T *table, size_t size, int type, const char *tag) {
static char unknow[40];
size_t i;
if (qmux_CtlFlags == table) {
if (!strcmp(tag, "_REQ"))
tag = "_CMD";
else if (!strcmp(tag, "_RESP"))
tag = "_RSP";
}
for (i = 0; i < size; i++) {
if (table[i].type == (UINT)type) {
if (!tag || (strstr(table[i].name, tag)))
return table[i].name;
}
}
sprintf(unknow, "unknow_%x", type);
return unknow;
}
#define QMI_NAME(table, type) qmi_name_get(table, sizeof(table) / sizeof(table[0]), type, 0)
#define QMUX_NAME(table, type, tag) qmi_name_get(table, sizeof(table) / sizeof(table[0]), type, tag)
void dump_tlv(PQCQMUX_MSG_HDR pQMUXMsgHdr) {
int TLVFind = 0;
int i;
//dbg("QCQMUX_TLV-----------------------------------\n");
//dbg("{Type,\tLength,\tValue}\n");
while (1) {
PQMI_TLV_HDR TLVHdr = GetTLV(pQMUXMsgHdr, 0x1000 + (++TLVFind));
if (TLVHdr == NULL)
break;
//if ((TLVHdr->TLVType == 0x02) && ((USHORT *)(TLVHdr+1))[0])
{
dbg("{%02x,\t%04x,\t", TLVHdr->TLVType, le16_to_cpu(TLVHdr->TLVLength));
for (i = 0; i < le16_to_cpu(TLVHdr->TLVLength); i++) {
dbg("%02x ", ((UCHAR *)(TLVHdr+1))[i]);
}
dbg("}\n");
}
} // while
}
void dump_ctl(PQCQMICTL_MSG_HDR CTLHdr) {
const char *tag;
//dbg("QCQMICTL_MSG--------------------------------------------\n");
//dbg("CtlFlags: %02x\t\t%s\n", CTLHdr->CtlFlags, QMI_NAME(qmi_ctl_CtlFlags, CTLHdr->CtlFlags));
dbg("TransactionId: %02x\n", CTLHdr->TransactionId);
switch (CTLHdr->CtlFlags) {
case QMICTL_FLAG_REQUEST: tag = "_REQ"; break;
case QMICTL_FLAG_RESPONSE: tag = "_RESP"; break;
case QMICTL_FLAG_INDICATION: tag = "_IND"; break;
default: tag = 0; break;
}
dbg("QMICTLType: %04x\t%s\n", le16_to_cpu(CTLHdr->QMICTLType),
QMUX_NAME(qmux_ctl_QMICTLType, le16_to_cpu(CTLHdr->QMICTLType), tag));
dbg("Length: %04x\n", le16_to_cpu(CTLHdr->Length));
dump_tlv((PQCQMUX_MSG_HDR)(&CTLHdr->QMICTLType));
}
int dump_qmux(QMI_SERVICE_TYPE serviceType, PQCQMUX_HDR QMUXHdr) {
PQCQMUX_MSG_HDR QMUXMsgHdr = (PQCQMUX_MSG_HDR) (QMUXHdr + 1);
CHAR *tag;
//dbg("QCQMUX--------------------------------------------\n");
switch (QMUXHdr->CtlFlags&QMUX_CTL_FLAG_MASK_TYPE) {
case QMUX_CTL_FLAG_TYPE_CMD: tag = "_REQ"; break;
case QMUX_CTL_FLAG_TYPE_RSP: tag = "_RESP"; break;
case QMUX_CTL_FLAG_TYPE_IND: tag = "_IND"; break;
default: tag = 0; break;
}
//dbg("CtlFlags: %02x\t\t%s\n", QMUXHdr->CtlFlags, QMUX_NAME(qmux_CtlFlags, QMUXHdr->CtlFlags, tag));
dbg("TransactionId: %04x\n", le16_to_cpu(QMUXHdr->TransactionId));
//dbg("QCQMUX_MSG_HDR-----------------------------------\n");
switch (serviceType) {
case QMUX_TYPE_DMS:
dbg("Type: %04x\t%s\n", le16_to_cpu(QMUXMsgHdr->Type),
QMUX_NAME(qmux_dms_Type, le16_to_cpu(QMUXMsgHdr->Type), tag));
break;
case QMUX_TYPE_NAS:
dbg("Type: %04x\t%s\n", le16_to_cpu(QMUXMsgHdr->Type),
QMUX_NAME(qmux_nas_Type, le16_to_cpu(QMUXMsgHdr->Type), tag));
break;
case QMUX_TYPE_WDS:
dbg("Type: %04x\t%s\n", le16_to_cpu(QMUXMsgHdr->Type),
QMUX_NAME(qmux_wds_Type, le16_to_cpu(QMUXMsgHdr->Type), tag));
break;
case QMUX_TYPE_WMS:
dbg("Type: %04x\t%s\n", le16_to_cpu(QMUXMsgHdr->Type),
QMUX_NAME(qmux_wms_Type, le16_to_cpu(QMUXMsgHdr->Type), tag));
break;
case QMUX_TYPE_WDS_ADMIN:
dbg("Type: %04x\t%s\n", le16_to_cpu(QMUXMsgHdr->Type),
QMUX_NAME(qmux_wds_admin_Type, le16_to_cpu(QMUXMsgHdr->Type), tag));
break;
case QMUX_TYPE_UIM:
dbg("Type: %04x\t%s\n", le16_to_cpu(QMUXMsgHdr->Type),
QMUX_NAME(qmux_uim_Type, le16_to_cpu(QMUXMsgHdr->Type), tag));
break;
case QMUX_TYPE_PDS:
case QMUX_TYPE_QOS:
case QMUX_TYPE_CTL:
default:
dbg("Type: %04x\t%s\n", le16_to_cpu(QMUXMsgHdr->Type), "PDS/QOS/CTL/unknown!");
break;
}
dbg("Length: %04x\n", le16_to_cpu(QMUXMsgHdr->Length));
dump_tlv(QMUXMsgHdr);
return 0;
}
void dump_qmi(void *dataBuffer, int dataLen)
{
PQCQMI_HDR QMIHdr = (PQCQMI_HDR)dataBuffer;
PQCQMUX_HDR QMUXHdr = (PQCQMUX_HDR) (QMIHdr + 1);
PQCQMICTL_MSG_HDR CTLHdr = (PQCQMICTL_MSG_HDR) (QMIHdr + 1);
int i;
if (!debug_qmi)
return;
pthread_mutex_lock(&dumpQMIMutex);
line[0] = 0;
for (i = 0; i < dataLen; i++) {
dbg("%02x ", ((unsigned char *)dataBuffer)[i]);
}
dbg_time("%s", line);
line[0] = 0;
//dbg("QCQMI_HDR-----------------------------------------");
//dbg("IFType: %02x\t\t%s", QMIHdr->IFType, QMI_NAME(qmi_IFType, QMIHdr->IFType));
//dbg("Length: %04x", le16_to_cpu(QMIHdr->Length));
//dbg("CtlFlags: %02x\t\t%s", QMIHdr->CtlFlags, QMI_NAME(qmi_CtlFlags, QMIHdr->CtlFlags));
//dbg("QMIType: %02x\t\t%s", QMIHdr->QMIType, QMI_NAME(qmi_QMIType, QMIHdr->QMIType));
//dbg("ClientId: %02x", QMIHdr->ClientId);
if (QMIHdr->QMIType == QMUX_TYPE_CTL) {
dump_ctl(CTLHdr);
} else {
dump_qmux(QMIHdr->QMIType, QMUXHdr);
}
dbg_time("%s", line);
pthread_mutex_unlock(&dumpQMIMutex);
}
+3322
View File
File diff suppressed because it is too large. Load diff
+25
View File
@@ -0,0 +1,25 @@
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
MEIG_CM_SRC=QmiWwanCM.c GobiNetCM.c main.c MPQMUX.c QMIThread.c util.c udhcpc.c qmap_bridge_mode.c mbim-cm.c device.c
release: clean qmi-proxy
$(CC) -Wall -s ${MEIG_CM_SRC} -o meig-cm -lpthread -ldl
debug: clean
$(CC) -Wall -g -DCM_DEBUG ${MEIG_CM_SRC} -o meig-cm -lpthread -ldl
qmi-proxy:
$(CC) -Wall -s meig-qmi-proxy.c -o meig-qmi-proxy -lpthread -ldl
clean:
rm -rf meig-cm *~
rm -rf meig-qmi-proxy
File diff suppressed because it is too large. Load diff
+228
View File
@@ -0,0 +1,228 @@
#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_DEFAULT_PDP 1
//#define CONFIG_IMSI_ICCID
#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 <sys/poll.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <stddef.h>
#include "MPQMI.h"
#include "MPQCTL.h"
#include "MPQMUX.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_1XRTT 0x00010000
#define WWAN_DATA_CLASS_1XEVDO 0x00020000
#define WWAN_DATA_CLASS_1XEVDO_REVA 0x00040000
#define WWAN_DATA_CLASS_1XEVDV 0x00080000
#define WWAN_DATA_CLASS_3XRTT 0x00100000
#define WWAN_DATA_CLASS_1XEVDO_REVB 0x00200000 /* for future use */
#define WWAN_DATA_CLASS_UMB 0x00400000
#define WWAN_DATA_CLASS_CUSTOM 0x80000000
struct wwan_data_class_str {
ULONG class;
CHAR *str;
};
#pragma pack(push, 1)
typedef struct _QCQMIMSG {
QCQMI_HDR QMIHdr;
union {
QMICTL_MSG CTLMsg;
QMUX_MSG MUXMsg;
};
} __attribute__ ((packed)) QCQMIMSG, *PQCQMIMSG;
typedef struct __IPV4 {
uint32_t Address;
uint32_t Gateway;
uint32_t SubnetMask;
uint32_t DnsPrimary;
uint32_t DnsSecondary;
uint32_t Mtu;
} IPV4_T;
typedef struct __IPV6 {
UCHAR Address[16];
UCHAR Gateway[16];
UCHAR SubnetMask[16];
UCHAR DnsPrimary[16];
UCHAR DnsSecondary[16];
UCHAR PrefixLengthIPAddr;
UCHAR PrefixLengthGateway;
ULONG Mtu;
} IPV6_T;
#define IpFamilyV4 (0x04)
#define IpFamilyV6 (0x06)
struct __PROFILE;
struct qmi_device_ops {
int (*init)(struct __PROFILE *profile);
int (*deinit)(void);
int (*send)(PQCQMIMSG pRequest);
void* (*read)(void *pData);
// int (*thread_read)(struct __PROFILE *profile);
// int (*init)(struct __PROFILE *profile);
// int (*open)(struct __PROFILE *profile);
// int (*close)(struct __PROFILE *profile);
// int (*reopen)(struct __PROFILE *profile);
// int (*start_network)(struct __PROFILE *profile);
// int (*stop_network)(struct __PROFILE *profile);
// int (*query_network)(struct __PROFILE *profile);
};
extern int (*qmidev_send)(PQCQMIMSG pRequest);
typedef struct __PROFILE {
char *qmichannel;
char *usbnet_adapter;
char *qmapnet_adapter;
char *driver_name;
int qmap_mode;
int qmap_version;
const char *apn;
const char *user;
const char *password;
const char *pincode;
int auth;
int pdp;
int IsDualIPSupported;
int curIpFamily;
int rawIP;
int muxid;
IPV4_T ipv4;
IPV6_T ipv6;
int enable_ipv6;
int ipv4_flag;
int ipv6_flag;
int apntype;
const struct qmi_device_ops *qmi_ops;
} PROFILE_T;
typedef enum {
SIM_ABSENT = 0,
SIM_NOT_READY = 1,
SIM_READY = 2, /* SIM_READY means the radio state is RADIO_STATE_SIM_READY */
SIM_PIN = 3,
SIM_PUK = 4,
SIM_NETWORK_PERSONALIZATION = 5,
SIM_BAD = 6,
} SIM_Status;
#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
extern int pthread_cond_timeout_np(pthread_cond_t *cond, pthread_mutex_t * mutex, unsigned msecs);
extern int QmiThreadSendQMI(PQCQMIMSG pRequest, PQCQMIMSG *ppResponse);
extern int QmiThreadSendQMITimeout(PQCQMIMSG pRequest, PQCQMIMSG *ppResponse, unsigned msecs);
extern void QmiThreadRecvQMI(PQCQMIMSG pResponse);
extern void udhcpc_start(PROFILE_T *profile);
extern void udhcpc_stop(PROFILE_T *profile);
extern void dump_qmi(void *dataBuffer, int dataLen);
extern void qmidevice_send_event_to_main(int triger_event);
extern int requestSetEthMode(PROFILE_T *profile);
extern int requestGetSIMStatus(SIM_Status *pSIMStatus);
extern int requestEnterSimPin(const CHAR *pPinCode);
extern int requestGetICCID(void);
extern int requestGetIMSI(void);
extern int requestRegistrationState(UCHAR *pPSAttachedState);
extern int requestQueryDataCall(UCHAR *pConnectionStatus, int curIpFamily);
extern int requestSetupDataCall(PROFILE_T *profile, int curIpFamily);
extern int requestDeactivateDefaultPDP(PROFILE_T *profile, int curIpFamily);
extern int requestSetProfile(PROFILE_T *profile);
extern int requestGetProfile(PROFILE_T *profile);
extern int requestBaseBandVersion(const char **pp_reversion);
extern int requestGetIPAddress(PROFILE_T *profile, int curIpFamily);
extern int requestSetOperatingMode(UCHAR OperatingMode);
extern void cond_setclock_attr(pthread_cond_t *cond, clockid_t clock);
extern int mbim_main(PROFILE_T *profile);
extern int varify_driver(PROFILE_T *profile);
extern BOOL qmidevice_detect(char *qmichannel, char *usbnet_adapter, unsigned bufsize);
extern int meig_bridge_mode_detect(PROFILE_T *profile);
extern int meig_enable_qmi_wwan_rawip_mode(PROFILE_T *profile);
extern int meig_driver_type_detect(PROFILE_T *profile);
extern int meig_qmap_mode_detect(PROFILE_T *profile);
extern const struct qmi_device_ops gobi_qmidev_ops;
extern const struct qmi_device_ops qmiwwan_qmidev_ops;
#define qmidev_is_gobinet(_qmichannel) (strncmp(_qmichannel, "/dev/qcqmi", strlen("/dev/qcqmi")) == 0)
#define qmidev_is_qmiwwan(_qmichannel) (strncmp(_qmichannel, "/dev/cdc-wdm", strlen("/dev/cdc-wdm")) == 0)
#define qmidev_is_pciemhi(_qmichannel) (strncmp(_qmichannel, "/dev/mhi_", strlen("/dev/mhi_")) == 0)
#define driver_is_qmi(_drv_name) (strncasecmp(_drv_name, "qmi_wwan", strlen("qmi_wwan")) == 0)
#define driver_is_mbim(_drv_name) (strncasecmp(_drv_name, "cdc_mbim", strlen("cdc_mbim")) == 0)
extern FILE *logfilefp;
extern int debug_qmi;
extern int qmidevice_control_fd[2];
extern int qmiclientId[QMUX_TYPE_WDS_ADMIN + 1];
extern USHORT le16_to_cpu(USHORT v16);
extern UINT le32_to_cpu (UINT v32);
extern UINT meig_swap32(UINT v32);
extern USHORT cpu_to_le16(USHORT v16);
extern UINT cpu_to_le32(UINT v32);
extern void update_resolv_conf(int iptype, const char *ifname, const char *dns1, const char *dns2);
#define CM_MAX_BUFF 256
#define strset(k, v) {if (k) free(k); k = strdup(v);}
#define mfree(v) {if (v) {free(v); v = NULL;}
#ifdef CM_DEBUG
#define dbg_time(fmt, args...) do { \
fprintf(stdout, "[%s-%04d: %s] " fmt "\n", __FILE__, __LINE__, get_time(), ##args); \
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); \
if (logfilefp) fprintf(logfilefp, "[%s] " fmt "\n", get_time(), ##args); \
} while(0);
#endif
#endif
+371
View File
@@ -0,0 +1,371 @@
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <stdio.h>
#include <ctype.h>
typedef unsigned short sa_family_t;
#include <linux/un.h>
#include "QMIThread.h"
#ifdef CONFIG_QMIWWAN
static int cdc_wdm_fd = -1;
static UCHAR GetQCTLTransactionId(void) {
static int TransactionId = 0;
if (++TransactionId > 0xFF)
TransactionId = 1;
return TransactionId;
}
typedef USHORT (*CUSTOMQCTL)(PQMICTL_MSG pCTLMsg, void *arg);
static PQCQMIMSG ComposeQCTLMsg(USHORT QMICTLType, CUSTOMQCTL customQctlMsgFunction, void *arg) {
UCHAR QMIBuf[WDM_DEFAULT_BUFSIZE];
PQCQMIMSG pRequest = (PQCQMIMSG)QMIBuf;
int Length;
pRequest->QMIHdr.IFType = USB_CTL_MSG_TYPE_QMI;
pRequest->QMIHdr.CtlFlags = 0x00;
pRequest->QMIHdr.QMIType = QMUX_TYPE_CTL;
pRequest->QMIHdr.ClientId= 0x00;
pRequest->CTLMsg.QMICTLMsgHdr.CtlFlags = QMICTL_FLAG_REQUEST;
pRequest->CTLMsg.QMICTLMsgHdr.TransactionId = GetQCTLTransactionId();
pRequest->CTLMsg.QMICTLMsgHdr.QMICTLType = cpu_to_le16(QMICTLType);
if (customQctlMsgFunction)
pRequest->CTLMsg.QMICTLMsgHdr.Length = cpu_to_le16(customQctlMsgFunction(&pRequest->CTLMsg, arg) - sizeof(QCQMICTL_MSG_HDR));
else
pRequest->CTLMsg.QMICTLMsgHdr.Length = cpu_to_le16(0x0000);
pRequest->QMIHdr.Length = cpu_to_le16(le16_to_cpu(pRequest->CTLMsg.QMICTLMsgHdr.Length) + sizeof(QCQMICTL_MSG_HDR) + sizeof(QCQMI_HDR) - 1);
Length = le16_to_cpu(pRequest->QMIHdr.Length) + 1;
pRequest = (PQCQMIMSG)malloc(Length);
if (pRequest == NULL) {
dbg_time("%s fail to malloc", __func__);
} else {
memcpy(pRequest, QMIBuf, Length);
}
return pRequest;
}
static USHORT CtlGetVersionReq(PQMICTL_MSG QCTLMsg, void *arg) {
QCTLMsg->GetVersionReq.TLVType = QCTLV_TYPE_REQUIRED_PARAMETER;
QCTLMsg->GetVersionReq.TLVLength = cpu_to_le16(0x0001);
QCTLMsg->GetVersionReq.QMUXTypes = QMUX_TYPE_ALL;
return sizeof(QMICTL_GET_VERSION_REQ_MSG);
}
static USHORT CtlGetClientIdReq(PQMICTL_MSG QCTLMsg, void *arg) {
QCTLMsg->GetClientIdReq.TLVType = QCTLV_TYPE_REQUIRED_PARAMETER;
QCTLMsg->GetClientIdReq.TLVLength = cpu_to_le16(0x0001);
QCTLMsg->GetClientIdReq.QMIType = ((UCHAR *)arg)[0];
return sizeof(QMICTL_GET_CLIENT_ID_REQ_MSG);
}
static USHORT CtlReleaseClientIdReq(PQMICTL_MSG QCTLMsg, void *arg) {
QCTLMsg->ReleaseClientIdReq.TLVType = QCTLV_TYPE_REQUIRED_PARAMETER;
QCTLMsg->ReleaseClientIdReq.TLVLength = cpu_to_le16(0x0002);
QCTLMsg->ReleaseClientIdReq.QMIType = ((UCHAR *)arg)[0];
QCTLMsg->ReleaseClientIdReq.ClientId = ((UCHAR *)arg)[1] ;
return sizeof(QMICTL_RELEASE_CLIENT_ID_REQ_MSG);
}
static int QmiWwanSendQMI(PQCQMIMSG pRequest) {
struct pollfd pollfds[]= {{cdc_wdm_fd, POLLOUT, 0}};
int ret;
if (cdc_wdm_fd == -1) {
dbg_time("%s cdc_wdm_fd = -1", __func__);
return -ENODEV;
}
if (pRequest->QMIHdr.QMIType == QMUX_TYPE_WDS_IPV6)
pRequest->QMIHdr.QMIType = QMUX_TYPE_WDS;
do {
ret = poll(pollfds, sizeof(pollfds)/sizeof(pollfds[0]), 5000);
} while ((ret < 0) && (errno == EINTR));
if (pollfds[0].revents & POLLOUT) {
ssize_t nwrites = le16_to_cpu(pRequest->QMIHdr.Length) + 1;
ret = write(cdc_wdm_fd, pRequest, nwrites);
if (ret == nwrites) {
ret = 0;
} else {
dbg_time("%s write=%d, errno: %d (%s)", __func__, ret, errno, strerror(errno));
}
} else {
dbg_time("%s poll=%d, revents = 0x%x, errno: %d (%s)", __func__, ret, pollfds[0].revents, errno, strerror(errno));
}
return ret;
}
static int QmiWwanGetClientID(UCHAR QMIType) {
PQCQMIMSG pResponse;
QmiThreadSendQMI(ComposeQCTLMsg(QMICTL_GET_CLIENT_ID_REQ, CtlGetClientIdReq, &QMIType), &pResponse);
if (pResponse) {
USHORT QMUXResult = cpu_to_le16(pResponse->CTLMsg.QMICTLMsgHdrRsp.QMUXResult); // QMI_RESULT_SUCCESS
USHORT QMUXError = cpu_to_le16(pResponse->CTLMsg.QMICTLMsgHdrRsp.QMUXError); // QMI_ERR_INVALID_ARG
//UCHAR QMIType = pResponse->CTLMsg.GetClientIdRsp.QMIType;
UCHAR ClientId = pResponse->CTLMsg.GetClientIdRsp.ClientId;
if (!QMUXResult && !QMUXError && (QMIType == pResponse->CTLMsg.GetClientIdRsp.QMIType)) {
switch (QMIType) {
case QMUX_TYPE_WDS: dbg_time("Get clientWDS = %d", ClientId); break;
case QMUX_TYPE_DMS: dbg_time("Get clientDMS = %d", ClientId); break;
case QMUX_TYPE_NAS: dbg_time("Get clientNAS = %d", ClientId); break;
case QMUX_TYPE_QOS: dbg_time("Get clientQOS = %d", ClientId); break;
case QMUX_TYPE_WMS: dbg_time("Get clientWMS = %d", ClientId); break;
case QMUX_TYPE_PDS: dbg_time("Get clientPDS = %d", ClientId); break;
case QMUX_TYPE_UIM: dbg_time("Get clientUIM = %d", ClientId); break;
case QMUX_TYPE_WDS_ADMIN: dbg_time("Get clientWDA = %d", ClientId);
break;
default: break;
}
return ClientId;
}
}
return 0;
}
static int QmiWwanReleaseClientID(QMI_SERVICE_TYPE QMIType, UCHAR ClientId) {
UCHAR argv[] = {QMIType, ClientId};
QmiThreadSendQMI(ComposeQCTLMsg(QMICTL_RELEASE_CLIENT_ID_REQ, CtlReleaseClientIdReq, argv), NULL);
return 0;
}
static int QmiWwanInit(PROFILE_T *profile) {
unsigned i;
int ret;
PQCQMIMSG pResponse;
if (profile->qmap_mode == 0 || profile->qmap_mode == 1)
{
for (i = 0; i < 10; i++) {
ret = QmiThreadSendQMITimeout(ComposeQCTLMsg(QMICTL_SYNC_REQ, NULL, NULL), NULL, 1 * 1000);
if (!ret)
break;
sleep(1);
}
if (ret)
return ret;
}
QmiThreadSendQMI(ComposeQCTLMsg(QMICTL_GET_VERSION_REQ, CtlGetVersionReq, NULL), &pResponse);
if (profile->qmap_mode) {
if (pResponse) {
if (pResponse->CTLMsg.QMICTLMsgHdrRsp.QMUXResult == 0 && pResponse->CTLMsg.QMICTLMsgHdrRsp.QMUXError == 0) {
uint8_t NumElements = 0;
for (NumElements = 0; NumElements < pResponse->CTLMsg.GetVersionRsp.NumElements; NumElements++) {
#if 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 || profile->IsDualIPSupported)
qmiclientId[QMUX_TYPE_WDS_IPV6] = QmiWwanGetClientID(QMUX_TYPE_WDS);
qmiclientId[QMUX_TYPE_DMS] = QmiWwanGetClientID(QMUX_TYPE_DMS);
qmiclientId[QMUX_TYPE_NAS] = QmiWwanGetClientID(QMUX_TYPE_NAS);
qmiclientId[QMUX_TYPE_UIM] = QmiWwanGetClientID(QMUX_TYPE_UIM);
if (profile->qmap_mode == 0 || profile->qmap_mode == 1)
qmiclientId[QMUX_TYPE_WDS_ADMIN] = QmiWwanGetClientID(QMUX_TYPE_WDS_ADMIN);
return 0;
}
static int QmiWwanDeInit(void) {
unsigned int i;
for (i = 0; i < sizeof(qmiclientId)/sizeof(qmiclientId[0]); i++)
{
if (qmiclientId[i] != 0)
{
QmiWwanReleaseClientID(i, qmiclientId[i]);
qmiclientId[i] = 0;
}
}
return 0;
}
#define MEIG_QMI_PROXY "meig-qmi-proxy"
static int qmi_proxy_open(const char *name) {
int sockfd = -1;
int reuse_addr = 1;
struct sockaddr_un sockaddr;
socklen_t alen;
/*Create server socket*/
(sockfd = socket(AF_LOCAL, SOCK_STREAM, 0));
if (sockfd < 0)
return sockfd;
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.sun_family = AF_LOCAL;
sockaddr.sun_path[0] = 0;
memcpy(sockaddr.sun_path + 1, name, strlen(name) );
alen = strlen(name) + offsetof(struct sockaddr_un, sun_path) + 1;
if(connect(sockfd, (struct sockaddr *)&sockaddr, alen) < 0) {
close(sockfd);
dbg_time("%s connect %s errno: %d (%s)\n", __func__, name, errno, strerror(errno));
return -1;
}
(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse_addr,sizeof(reuse_addr)));
dbg_time("connect to %s sockfd = %d\n", name, sockfd);
return sockfd;
}
static ssize_t qmi_proxy_read (int fd, void *buf, size_t size) {
ssize_t nreads;
PQCQMI_HDR pHdr = (PQCQMI_HDR)buf;
nreads = read(fd, pHdr, sizeof(QCQMI_HDR));
if (nreads == sizeof(QCQMI_HDR)) {
nreads += read(fd, pHdr+1, le16_to_cpu(pHdr->Length) + 1 - sizeof(QCQMI_HDR));
}
return nreads;
}
static void * QmiWwanThread(void *pData) {
PROFILE_T *profile = (PROFILE_T *)pData;
const char *cdc_wdm = (const char *)profile->qmichannel;
int wait_for_request_quit = 0;
if (profile->qmap_mode == 0 || profile->qmap_mode == 1)
cdc_wdm_fd = open(cdc_wdm, O_RDWR | O_NONBLOCK | O_NOCTTY);
else
cdc_wdm_fd = qmi_proxy_open(MEIG_QMI_PROXY);
if (cdc_wdm_fd == -1) {
dbg_time("%s Failed to open %s, errno: %d (%s)", __func__, cdc_wdm, errno, strerror(errno));
qmidevice_send_event_to_main(RIL_INDICATE_DEVICE_DISCONNECTED);
pthread_exit(NULL);
return NULL;
}
fcntl(cdc_wdm_fd, F_SETFL, fcntl(cdc_wdm_fd,F_GETFL) | O_NONBLOCK);
fcntl(cdc_wdm_fd, F_SETFD, FD_CLOEXEC);
dbg_time("cdc_wdm_fd = %d", cdc_wdm_fd);
qmidevice_send_event_to_main(RIL_INDICATE_DEVICE_CONNECTED);
while (1) {
struct pollfd pollfds[] = {{qmidevice_control_fd[1], POLLIN, 0}, {cdc_wdm_fd, POLLIN, 0}};
int ne, ret, nevents = sizeof(pollfds)/sizeof(pollfds[0]);
do {
ret = poll(pollfds, nevents, 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 SIGTERM:
case SIGHUP:
case SIGINT:
wait_for_request_quit = 1;
break;
default:
break;
}
}
}
if (fd == cdc_wdm_fd) {
ssize_t nreads;
UCHAR QMIBuf[512];
PQCQMIMSG pResponse = (PQCQMIMSG)QMIBuf;
if (profile->qmap_mode == 0 || profile->qmap_mode == 1)
nreads = read(fd, QMIBuf, sizeof(QMIBuf));
else
nreads = qmi_proxy_read(fd, QMIBuf, sizeof(QMIBuf));
//dbg_time("%s read=%d errno: %d (%s)", __func__, (int)nreads, errno, strerror(errno));
if (nreads <= 0) {
dbg_time("%s read=%d errno: %d (%s)", __func__, (int)nreads, errno, strerror(errno));
break;
}
if (nreads != (le16_to_cpu(pResponse->QMIHdr.Length) + 1)) {
dbg_time("%s nreads=%d, pQCQMI->QMIHdr.Length = %d", __func__, (int)nreads, le16_to_cpu(pResponse->QMIHdr.Length));
continue;
}
QmiThreadRecvQMI(pResponse);
}
}
}
__QmiWwanThread_quit:
if (cdc_wdm_fd != -1) { close(cdc_wdm_fd); cdc_wdm_fd = -1; }
qmidevice_send_event_to_main(RIL_INDICATE_DEVICE_DISCONNECTED);
QmiThreadRecvQMI(NULL); //main thread may pending on QmiThreadSendQMI()
dbg_time("%s exit", __func__);
pthread_exit(NULL);
return NULL;
}
#else
static int QmiWwanSendQMI(PQCQMIMSG pRequest) {return -1;}
static int QmiWwanInit(PROFILE_T *profile) {return -1;}
static int QmiWwanDeInit(void) {return -1;}
static void * QmiWwanThread(void *pData) {dbg_time("please set CONFIG_QMIWWAN"); return NULL;}
#endif
const struct qmi_device_ops qmiwwan_qmidev_ops = {
.init = QmiWwanInit,
.deinit = QmiWwanDeInit,
.send = QmiWwanSendQMI,
.read = QmiWwanThread,
};
+61
View File
@@ -0,0 +1,61 @@
Release Notes
[WCDMA&LTE_QConnectManager_Linux&Android_V1.2.1]
Date: 2019/02/26
enhancement:
1. Implement help message.
root@ubuntu:# ./meig-cm -h
[02-26_10:39:21:353] Usage: ./meig-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: ./meig-cm
[02-26_10:39:21:353] Example 2: ./meig-cm -s 3gnet
[02-26_10:39:21:353] Example 3: ./meig-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. meig-cm now support three dialing methods: IPV4 only, IPV6 only, IPV4V6.
./meig-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 Meig FAE to get qmi_wwan.c patch.
when enable QMI_WWAN's QMAP IP Mux function, must run 'meig-qmi-proxy -d /dev/cdc-wdmX' before meig-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.
'Meig_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
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
#export PATH=/home/zhaopengfei/ruiming/aarch64-himix200-linux/bin:$PATH
make clean
make CROSS_COMPILE=arm-hisiv500-linux-
+63
View File
@@ -0,0 +1,63 @@
#!/bin/sh
# Busybox udhcpc dispatcher script. Copyright (C) 2009 by Axel Beckert.
#
# Based on the busybox example scripts and the old udhcp source
# package default.* scripts.
RESOLV_CONF="/etc/resolv.conf"
case $1 in
bound|renew)
[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
[ -n "$subnet" ] && NETMASK="netmask $subnet"
/sbin/ifconfig $interface $ip $BROADCAST $NETMASK
if [ -n "$router" ]; then
echo "$0: Resetting default routes"
while /sbin/route del default gw 0.0.0.0 dev $interface; do :; done
metric=0
for i in $router; do
/sbin/route add default gw $i dev $interface metric $metric
metric=$(($metric + 1))
done
fi
# Update resolver configuration file
R=""
[ -n "$domain" ] && R="domain $domain
"
for i in $dns; do
echo "$0: Adding DNS $i"
R="${R}nameserver $i
"
done
if [ ! -x /sbin/resolvconf ]; then
echo -n "$R" | resolvconf -a "${interface}.udhcpc"
else
echo -n "$R" > "$RESOLV_CONF"
fi
;;
deconfig)
if [ -x /sbin/resolvconf ]; then
resolvconf -d "${interface}.udhcpc"
fi
/sbin/ifconfig $interface 0.0.0.0
;;
leasefail)
echo "$0: Lease failed: $message"
;;
nak)
echo "$0: Received a NAK: $message"
;;
*)
echo "$0: Unknown udhcpc command: $1";
exit 1;
;;
esac
+231
View File
@@ -0,0 +1,231 @@
#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 "QMIThread.h"
#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)
{
FILE *fp = NULL;
int hexnum;
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);
hexnum = strtol(buff, &endptr, 16);
if (errno == ERANGE && (hexnum == LONG_MAX || hexnum == LONG_MIN))
goto error;
/* if there is no digit in buff */
if (endptr == buff)
goto error;
return (int)hexnum;
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
*/
int dir_get_child(const char *dirname, char *buff, unsigned bufsize)
{
struct dirent *entptr = NULL;
DIR *dirptr = opendir(dirname);
if (!dirptr)
goto error;
while ((entptr = readdir(dirptr))) {
if (entptr->d_name[0] == '.')
continue;
snprintf(buff, bufsize, "%s", entptr->d_name);
break;
}
closedir(dirptr);
return 0;
error:
buff[0] = '\0';
if (dirptr) closedir(dirptr);
return -1;
}
int conf_get_val(const char *fname, const char *key)
{
char buff[CM_MAX_BUFF] = {'\0'};
FILE *fp = fopen(fname, "r");
if (!fp)
goto error;
while (fgets(buff, CM_MAX_BUFF, fp)) {
char prefix[CM_MAX_BUFF] = {'\0'};
char tail[CM_MAX_BUFF] = {'\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);
}
}
error:
fclose(fp);
return CM_INVALID_VAL;
}
/* To detect the device info of the modem.
* return:
* FALSE -> fail
* TRUE -> ok
*/
BOOL qmidevice_detect(char *qmichannel, char *usbnet_adapter, unsigned bufsize) {
struct dirent* ent = NULL;
DIR *pDir;
const char *rootdir = "/sys/bus/usb/devices";
struct {
char path[255*2];
char uevent[255*3];
} *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) {
int idVendor;
int idProduct;
char netcard[32+1] = {'\0'};
char device[32+1] = {'\0'};
char devname[32+1+6] = {'\0'};
snprintf(pl->path, sizeof(pl->path), "%s/%s/idVendor", rootdir, ent->d_name);
idVendor = file_get_value(pl->path);
snprintf(pl->path, sizeof(pl->path), "%s/%s/idProduct", rootdir, ent->d_name);
idProduct = file_get_value(pl->path);
if (idVendor != 0x05c6 && idVendor != 0x2c7c && idVendor != 0x2dee)
continue;
dbg_time("Find %s/%s idVendor=0x%x idProduct=0x%x", rootdir, ent->d_name, idVendor, idProduct);
/* get network interface */
snprintf(pl->path, sizeof(pl->path), "%s/%s:1.4/net", rootdir, ent->d_name);
dir_get_child(pl->path, netcard, sizeof(netcard));
if (netcard[0] == '\0')
continue;
if (usbnet_adapter[0] && strcmp(usbnet_adapter, netcard))
continue;
snprintf(pl->path, sizeof(pl->path), "%s/%s:1.4/GobiQMI", rootdir, ent->d_name);
if (access(pl->path, R_OK)) {
snprintf(pl->path, sizeof(pl->path), "%s/%s:1.4/usbmisc", rootdir, ent->d_name);
if (access(pl->path, R_OK)) {
snprintf(pl->path, sizeof(pl->path), "%s/%s:1.4/usb", rootdir, ent->d_name);
if (access(pl->path, R_OK)) {
dbg_time("no GobiQMI/usbmic/usb found in %s/%s:1.4", rootdir, ent->d_name);
continue;
}
}
}
/* get device */
dir_get_child(pl->path, device, sizeof(device));
if (device[0] == '\0')
continue;
/* There is a chance that, no device(qcqmiX|cdc-wdmX) is generated. We should warn user about that! */
snprintf(devname, sizeof(devname), "/dev/%s", device);
if (access(devname, R_OK | F_OK) && errno == ENOENT) {
int major;
int minor;
int ret;
dbg_time("%s access failed, errno: %d (%s)", devname, errno, strerror(errno));
snprintf(pl->uevent, sizeof(pl->uevent), "%s/%s/uevent", pl->path, device);
major = conf_get_val(pl->uevent, "MAJOR");
minor = conf_get_val(pl->uevent, "MINOR");
if(major == CM_INVALID_VAL || minor == CM_INVALID_VAL)
dbg_time("get major and minor failed");
ret = mknod(devname, S_IFCHR|0666, (((major & 0xfff) << 8) | (minor & 0xff) | ((minor & 0xfff00) << 12)));
if (ret)
dbg_time("please mknod %s c %d %d", devname, major, minor);
}
if (netcard[0] && device[0]) {
snprintf(qmichannel, bufsize, "/dev/%s", device);
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;
}
#define USB_CLASS_COMM 2
#define USB_CLASS_VENDOR_SPEC 0xff
#define USB_CDC_SUBCLASS_MBIM 0x0e
/*
* To check whether the system load the wrong driver:
* error1: usbnet 2(MBIM) match the QMI driver(qmi_wwan|GobiNet)
* error2: usbnet 0(QMI) match the MBIM driver(cdc_mbim)
* return:
* 0 for ok, or ignorance
* others for failure or error
*/
int varify_driver(PROFILE_T *profile)
{
char path[CM_MAX_PATHLEN+1] = {'\0'};
int bInterfaceClass = -1;
snprintf(path, sizeof(path), "/sys/class/net/%s/device/bInterfaceClass", profile->usbnet_adapter);
bInterfaceClass = file_get_value(path);
/* QMI_WWAN */
if (driver_is_qmi(profile->driver_name) && bInterfaceClass != USB_CLASS_VENDOR_SPEC) {
dbg_time("module register driver %s, but at+qcfg=\"usbnet\" is not QMI mode!", profile->driver_name);
return 1;
}
/* CDC_MBIM */
if (driver_is_mbim(profile->driver_name) && bInterfaceClass != USB_CLASS_COMM) {
dbg_time("module register driver %s, but at+qcfg=\"usbnet\" is not MBIM mode!", profile->driver_name);
return 1;
}
return 0;
}
+90
View File
@@ -0,0 +1,90 @@
#ifdef ANDROID
/*
* Copyright 2008, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include "QMIThread.h"
#ifdef USE_NDK
extern int (*ifc_init)(void);
extern void (*ifc_close)(void);
extern int (*do_dhcp)(const char *iname);
extern void (*get_dhcp_info)(uint32_t *ipaddr, uint32_t *gateway, uint32_t *prefixLength,
uint32_t *dns1, uint32_t *dns2, uint32_t *server,
uint32_t *lease);
extern int (*property_set)(const char *key, const char *value);
#else
#include <cutils/properties.h>
#include <netutils/ifc.h>
extern int do_dhcp(const char *iname);
extern void get_dhcp_info(uint32_t *ipaddr, uint32_t *gateway, uint32_t *prefixLength,
uint32_t *dns1, uint32_t *dns2, uint32_t *server,
uint32_t *lease);
#endif
static const char *ipaddr_to_string(in_addr_t addr)
{
struct in_addr in_addr;
in_addr.s_addr = addr;
return inet_ntoa(in_addr);
}
void do_dhcp_request(PROFILE_T *profile) {
#ifdef USE_NDK
if (!ifc_init ||!ifc_close ||!do_dhcp || !get_dhcp_info || !property_set) {
return;
}
#endif
char *ifname = profile->usbnet_adapter;
uint32_t ipaddr, gateway, prefixLength, dns1, dns2, server, lease;
char propKey[128];
#if 0
if (profile->rawIP && ((profile->IPType==0x04 && profile->ipv4.Address)))
{
snprintf(propKey, sizeof(propKey), "net.%s.dns1", ifname);
property_set(propKey, profile->ipv4.DnsPrimary ? ipaddr_to_string(meig_swap32(profile->ipv4.DnsPrimary)) : "8.8.8.8");
snprintf(propKey, sizeof(propKey), "net.%s.dns2", ifname);
property_set(propKey, profile->ipv4.DnsSecondary ? ipaddr_to_string(meig_swap32(profile->ipv4.DnsSecondary)) : "8.8.8.8");
snprintf(propKey, sizeof(propKey), "net.%s.gw", ifname);
property_set(propKey, profile->ipv4.Gateway ? ipaddr_to_string(meig_swap32(profile->ipv4.Gateway)) : "0.0.0.0");
return;
}
#endif
if(ifc_init()) {
dbg_time("failed to ifc_init(%s): %s\n", ifname, strerror(errno));
}
if (do_dhcp(ifname) < 0) {
dbg_time("failed to do_dhcp(%s): %s\n", ifname, strerror(errno));
}
ifc_close();
get_dhcp_info(&ipaddr, &gateway, &prefixLength, &dns1, &dns2, &server, &lease);
snprintf(propKey, sizeof(propKey), "net.%s.gw", ifname);
property_set(propKey, gateway ? ipaddr_to_string(gateway) : "0.0.0.0");
}
#endif
+796
View File
@@ -0,0 +1,796 @@
#include "QMIThread.h"
#include <sys/wait.h>
#include <sys/utsname.h>
#include <sys/time.h>
#include <dirent.h>
#include "util.h"
//#define CONFIG_EXIT_WHEN_DIAL_FAILED
//#define CONFIG_BACKGROUND_WHEN_GET_IP
//#define CONFIG_PID_FILE_FORMAT "/var/run/meig-cm-%s.pid" //for example /var/run/meig-cm-wwan0.pid
#define MAJOR 1
#define MINOR 3
#define REVISION 8
/*
* Generally, we do not modify version info, so several modifications will share the same version code.
* SUBVERSION is used for customized modification to distinguise this version from previous one.
* SUBVERSION adds up before you send the code to customers and it should be set to 0 if VERSION_STRING info is changed.
*/
#define SUBVERSION 0
#define STRINGIFY_HELPER(v) #v
#define STRINGIFY(v) STRINGIFY_HELPER(v)
#define VERSION_STRING() STRINGIFY(MAJOR) "." \
STRINGIFY(MINOR) "." \
STRINGIFY(REVISION)
int debug_qmi = 0;
int main_loop = 0;
int qmidevice_control_fd[2];
static int signal_control_fd[2];
extern const struct qmi_device_ops gobi_qmidev_ops;
extern const struct qmi_device_ops qmiwwan_qmidev_ops;
extern int meig_ifconfig(int argc, char *argv[]);
#ifdef CONFIG_BACKGROUND_WHEN_GET_IP
static int daemon_pipe_fd[2];
static void meig_prepare_daemon(void) {
pid_t daemon_child_pid;
if (pipe(daemon_pipe_fd) < 0) {
dbg_time("%s Faild to create daemon_pipe_fd: %d (%s)", __func__, errno, strerror(errno));
return;
}
daemon_child_pid = fork();
if (daemon_child_pid > 0) {
struct pollfd pollfds[] = {{daemon_pipe_fd[0], POLLIN, 0}, {0, POLLIN, 0}};
int ne, ret, nevents = sizeof(pollfds)/sizeof(pollfds[0]);
int signo;
//dbg_time("father");
close(daemon_pipe_fd[1]);
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;
}
pollfds[1].fd = signal_control_fd[1];
while (1) {
do {
ret = poll(pollfds, nevents, -1);
} while ((ret < 0) && (errno == EINTR));
if (ret < 0) {
dbg_time("%s poll=%d, errno: %d (%s)", __func__, ret, errno, strerror(errno));
goto __daemon_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("poll fd = %d, events = 0x%04x", fd, revents);
if (revents & POLLHUP)
goto __daemon_quit;
}
if ((revents & POLLIN) && read(fd, &signo, sizeof(signo)) == sizeof(signo)) {
if (signal_control_fd[1] == fd) {
if (signo == SIGCHLD) {
int status;
int pid = waitpid(daemon_child_pid, &status, 0);
dbg_time("waitpid pid=%d, status=%x", pid, status);
goto __daemon_quit;
} else {
kill(daemon_child_pid, signo);
}
} else if (daemon_pipe_fd[0] == fd) {
//dbg_time("daemon_pipe_signo = %d", signo);
goto __daemon_quit;
}
}
}
}
__daemon_quit:
//dbg_time("father exit");
_exit(0);
} else if (daemon_child_pid == 0) {
close(daemon_pipe_fd[0]);
//dbg_time("child", getpid());
} else {
close(daemon_pipe_fd[0]);
close(daemon_pipe_fd[1]);
dbg_time("%s Faild to create daemon_child_pid: %d (%s)", __func__, errno, strerror(errno));
}
}
static void meig_enter_daemon(int signo) {
if (daemon_pipe_fd[1] > 0)
if (signo) {
write(daemon_pipe_fd[1], &signo, sizeof(signo));
sleep(1);
}
close(daemon_pipe_fd[1]);
daemon_pipe_fd[1] = -1;
setsid();
}
#endif
//UINT ifc_get_addr(const char *ifname);
static void usbnet_link_change(int link, PROFILE_T *profile) {
static int s_link = -1;
int curIpFamily = profile->enable_ipv6 ? IpFamilyV6 : IpFamilyV4;
if (s_link == link)
return;
s_link = link;
if (link) {
requestGetIPAddress(profile, curIpFamily);
if (profile->IsDualIPSupported)
requestGetIPAddress(profile, IpFamilyV6);
udhcpc_start(profile);
} else {
udhcpc_stop(profile);
}
#ifdef CONFIG_BACKGROUND_WHEN_GET_IP
if (link && daemon_pipe_fd[1] > 0) {
int timeout = 6;
while (timeout-- /*&& ifc_get_addr(profile->usbnet_adapter) == 0*/) {
sleep(1);
}
meig_enter_daemon(SIGUSR1);
}
#endif
}
static int check_ipv4_address(PROFILE_T *now_profile) {
PROFILE_T new_profile_v;
PROFILE_T *new_profile = &new_profile_v;
memcpy(new_profile, now_profile, sizeof(PROFILE_T));
if (requestGetIPAddress(new_profile, 0x04) == 0) {
if (new_profile->ipv4.Address != now_profile->ipv4.Address || debug_qmi) {
unsigned char *l = (unsigned char *)&now_profile->ipv4.Address;
unsigned char *r = (unsigned char *)&new_profile->ipv4.Address;
dbg_time("localIP: %d.%d.%d.%d VS remoteIP: %d.%d.%d.%d",
l[3], l[2], l[1], l[0], r[3], r[2], r[1], r[0]);
}
return (new_profile->ipv4.Address == now_profile->ipv4.Address);
}
return 0;
}
static void main_send_event_to_qmidevice(int triger_event) {
write(qmidevice_control_fd[0], &triger_event, sizeof(triger_event));
}
static void send_signo_to_main(int signo) {
write(signal_control_fd[0], &signo, sizeof(signo));
}
void qmidevice_send_event_to_main(int triger_event) {
write(qmidevice_control_fd[1], &triger_event, sizeof(triger_event));
}
#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];
char filename[MAX_PATH];
int linksize;
snprintf(linkname, MAX_PATH, "%s/%s", dir, file);
linksize = readlink(linkname, filename, MAX_PATH);
if (linksize <= 0)
return 0;
filename[linksize] = 0;
if (strcmp(filename, qmichannel))
return 0;
dbg_time("%s -> %s", linkname, filename);
return 1;
}
static int is_brother_process(const char *dir, const char *file, void *argv[])
{
//const char *myself = (const char *)argv[0];
char linkname[MAX_PATH];
char filename[MAX_PATH];
int linksize;
int i = 0, kill_timeout = 15;
pid_t pid;
//dbg_time("%s", file);
while (file[i]) {
if (!isdigit(file[i]))
break;
i++;
}
if (file[i]) {
//dbg_time("%s not digit", file);
return 0;
}
snprintf(linkname, MAX_PATH, "%s/%s/exe", dir, file);
linksize = readlink(linkname, filename, MAX_PATH);
if (linksize <= 0)
return 0;
filename[linksize] = 0;
pid = atoi(file);
if (pid >= getpid())
return 0;
snprintf(linkname, MAX_PATH, "%s/%s/fd", dir, file);
if (!ls_dir(linkname, is_same_linkfile, argv))
return 0;
dbg_time("%s/%s/exe -> %s", dir, file, filename);
while (kill_timeout-- && !kill(pid, 0))
{
kill(pid, SIGTERM);
sleep(1);
}
if (!kill(pid, 0))
{
dbg_time("force kill %s/%s/exe -> %s", dir, file, filename);
kill(pid, SIGKILL);
sleep(1);
}
return 1;
}
static int kill_brothers(const char *qmichannel)
{
char myself[MAX_PATH];
int filenamesize;
void *argv[2] = {myself, (void *)qmichannel};
filenamesize = readlink("/proc/self/exe", myself, MAX_PATH);
if (filenamesize <= 0)
return 0;
myself[filenamesize] = 0;
if (ls_dir("/proc", is_brother_process, argv))
sleep(1);
return 0;
}
static void meig_sigaction(int signo) {
if (SIGCHLD == signo)
waitpid(-1, NULL, WNOHANG);
else if (SIGALRM == signo)
send_signo_to_main(SIGUSR1);
else
{
if (SIGTERM == signo || SIGHUP == signo || SIGINT == signo)
main_loop = 0;
send_signo_to_main(signo);
main_send_event_to_qmidevice(signo); //main may be wating qmi response
}
}
pthread_t gQmiThreadID;
static int usage(const char *progname) {
dbg_time("Usage: %s [options]", progname);
dbg_time("-s [apn [user password auth]] Set apn/user/password/auth get from your network provider");
dbg_time("-p pincode Verify sim card pin if sim card is locked");
dbg_time("-f logfilename Save log message of this program to file");
dbg_time("-i interface Specify network interface(default auto-detect)");
dbg_time("-4 IPv4 protocol");
dbg_time("-6 IPv6 protocol");
dbg_time("-m muxID Specify muxid when set multi-pdn data connection.");
dbg_time("-n channelID Specify channelID when set multi-pdn data connection(default 1).");
dbg_time("[Examples]");
dbg_time("Example 1: %s ", progname);
dbg_time("Example 2: %s -s 3gnet ", progname);
dbg_time("Example 3: %s -s 3gnet carl 1234 0 -p 1234 -f gobinet_log.txt", progname);
return 0;
}
int qmi_main(PROFILE_T *profile)
{
int triger_event = 0;
int signo;
#ifdef CONFIG_SIM
SIM_Status SIMStatus;
#endif
UCHAR PSAttachedState;
UCHAR IPv4ConnectionStatus = 0xff; //unknow state
UCHAR IPV6ConnectionStatus = 0xff; //unknow state
int qmierr = 0;
char * save_usbnet_adapter = NULL;
signal(SIGUSR1, meig_sigaction);
signal(SIGUSR2, meig_sigaction);
signal(SIGINT, meig_sigaction);
signal(SIGTERM, meig_sigaction);
signal(SIGHUP, meig_sigaction);
signal(SIGCHLD, meig_sigaction);
signal(SIGALRM, meig_sigaction);
#ifdef CONFIG_BACKGROUND_WHEN_GET_IP
meig_prepare_daemon();
#endif
if (socketpair( AF_LOCAL, SOCK_STREAM, 0, signal_control_fd) < 0 ) {
dbg_time("%s Faild to create main_control_fd: %d (%s)", __func__, errno, strerror(errno));
return -1;
}
if ( socketpair( AF_LOCAL, SOCK_STREAM, 0, qmidevice_control_fd ) < 0 ) {
dbg_time("%s Failed to create thread control socket pair: %d (%s)", __func__, errno, strerror(errno));
return 0;
}
//sudo apt-get install udhcpc
//sudo apt-get remove ModemManager
__main_loop:
while (!profile->qmichannel) {
char qmichannel[32+1] = {'\0'};
char usbnet_adapter[32+1] = {'\0'};
if (!qmidevice_detect(qmichannel, usbnet_adapter, sizeof(qmichannel))) {
dbg_time("qmidevice_detect failed");
continue;
} else {
if (!(profile->qmichannel))
strset(profile->qmichannel, qmichannel);
if (!(profile->usbnet_adapter))
strset(profile->usbnet_adapter, usbnet_adapter);
break;
}
if (main_loop) {
int wait_for_device = 3000;
dbg_time("Wait for Meig modules connect");
while (wait_for_device && main_loop) {
wait_for_device -= 100;
usleep(100*1000);
}
continue;
}
dbg_time("Cannot find qmichannel(%s) usbnet_adapter(%s) for Meig modules", profile->qmichannel, profile->usbnet_adapter);
return -ENODEV;
}
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;
meig_qmap_mode_detect(profile);
dbg_time("[zpf]qmap_mode=%d", profile->qmap_mode);
if (profile->qmap_mode == 0 || profile->qmap_mode == 1)
kill_brothers(profile->qmichannel);
if (pthread_create( &gQmiThreadID, 0, profile->qmi_ops->read, (void *)profile) != 0) {
dbg_time("%s Failed to create QMIThread: %d (%s)", __func__, errno, strerror(errno));
return 0;
}
if ((read(qmidevice_control_fd[0], &triger_event, sizeof(triger_event)) != sizeof(triger_event))
|| (triger_event != RIL_INDICATE_DEVICE_CONNECTED)) {
dbg_time("%s Failed to init QMIThread: %d (%s)", __func__, errno, strerror(errno));
return 0;
}
if (profile->qmi_ops->init && profile->qmi_ops->init(profile)) {
dbg_time("%s Failed to qmi init: %d (%s)", __func__, errno, strerror(errno));
return 0;
}
#ifdef CONFIG_VERSION
requestBaseBandVersion(NULL);
#endif
requestSetEthMode(profile);
#ifdef CONFIG_SIM
qmierr = requestGetSIMStatus(&SIMStatus);
while (qmierr == QMI_ERR_OP_DEVICE_UNSUPPORTED) {
sleep(1);
qmierr = requestGetSIMStatus(&SIMStatus);
}
if ((SIMStatus == SIM_PIN) && profile->pincode) {
requestEnterSimPin(profile->pincode);
}
#ifdef CONFIG_IMSI_ICCID
if (SIMStatus == SIM_READY) {
requestGetICCID();
requestGetIMSI();
}
#endif
#endif
#ifdef CONFIG_APN
if (profile->apn || profile->user || profile->password) {
requestSetProfile(profile);
}
requestGetProfile(profile);
#endif
requestRegistrationState(&PSAttachedState);
if (!requestQueryDataCall(&IPv4ConnectionStatus, IpFamilyV4) && (QWDS_PKT_DATA_CONNECTED == IPv4ConnectionStatus)){
usbnet_link_change(1, profile);
} else
usbnet_link_change(0, profile);
send_signo_to_main(SIGUSR1);
#ifdef CONFIG_PID_FILE_FORMAT
{
char cmd[255];
sprintf(cmd, "echo %d > " CONFIG_PID_FILE_FORMAT, getpid(), profile->usbnet_adapter);
system(cmd);
}
#endif
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]);
UCHAR *pConnectionStatus = (profile->enable_ipv6) ? &IPV6ConnectionStatus : &IPv4ConnectionStatus;
int curIpFamily = (profile->enable_ipv6) ? IpFamilyV6 : IpFamilyV4;
do {
ret = poll(pollfds, nevents, 15*1000);
} while ((ret < 0) && (errno == EINTR));
if (ret == 0)
{
send_signo_to_main(SIGUSR2);
continue;
}
if (ret <= 0) {
dbg_time("%s poll=%d, errno: %d (%s)", __func__, ret, errno, strerror(errno));
goto __main_quit;
}
for (ne = 0; ne < nevents; ne++) {
int fd = pollfds[ne].fd;
short revents = pollfds[ne].revents;
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 SIGUSR1:
requestQueryDataCall(pConnectionStatus, curIpFamily);
if (QWDS_PKT_DATA_CONNECTED != *pConnectionStatus)
{
usbnet_link_change(0, profile);
requestRegistrationState(&PSAttachedState);
if (PSAttachedState == 1) {
qmierr = requestSetupDataCall(profile, curIpFamily);
if ((qmierr > 0) && profile->user && profile->user[0] && profile->password && profile->password[0]) {
int old_auto = profile->auth;
//may be fail because wrong auth mode, try pap->chap, or chap->pap
profile->auth = (profile->auth == 1) ? 2 : 1;
qmierr = requestSetupDataCall(profile, curIpFamily);
if (qmierr)
profile->auth = old_auto; //still fail, restore old auth moe
}
//succssful setup data call
if (!qmierr && profile->IsDualIPSupported) {
requestSetupDataCall(profile, IpFamilyV6);
}
if (!qmierr)
continue;
}
#ifdef CONFIG_EXIT_WHEN_DIAL_FAILED
kill(getpid(), SIGTERM);
#endif
alarm(5); //try to setup data call 5 seconds later
}
break;
case SIGUSR2:
if (QWDS_PKT_DATA_CONNECTED == *pConnectionStatus)
requestQueryDataCall(pConnectionStatus, curIpFamily);
//local ip is different with remote ip
if (QWDS_PKT_DATA_CONNECTED == IPv4ConnectionStatus && check_ipv4_address(profile) == 0) {
requestDeactivateDefaultPDP(profile, curIpFamily);
*pConnectionStatus = QWDS_PKT_DATA_DISCONNECTED;
}
if (QWDS_PKT_DATA_CONNECTED != *pConnectionStatus)
send_signo_to_main(SIGUSR1);
break;
case SIGTERM:
case SIGHUP:
case SIGINT:
if (QWDS_PKT_DATA_CONNECTED == *pConnectionStatus) {
requestDeactivateDefaultPDP(profile, curIpFamily);
if (profile->IsDualIPSupported)
requestDeactivateDefaultPDP(profile, IpFamilyV6);
}
usbnet_link_change(0, profile);
if (profile->qmi_ops->deinit)
profile->qmi_ops->deinit();
main_send_event_to_qmidevice(RIL_REQUEST_QUIT);
goto __main_quit;
break;
default:
break;
}
}
}
if (fd == qmidevice_control_fd[0]) {
if (read(fd, &triger_event, sizeof(triger_event)) == sizeof(triger_event)) {
switch (triger_event) {
case RIL_INDICATE_DEVICE_DISCONNECTED:
usbnet_link_change(0, profile);
if (main_loop)
{
if (pthread_join(gQmiThreadID, NULL)) {
dbg_time("%s Error joining to listener thread (%s)", __func__, strerror(errno));
}
profile->qmichannel = NULL;
profile->usbnet_adapter = save_usbnet_adapter;
goto __main_loop;
}
goto __main_quit;
break;
case RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED:
requestRegistrationState(&PSAttachedState);
if (PSAttachedState == 1 && QWDS_PKT_DATA_DISCONNECTED == *pConnectionStatus)
send_signo_to_main(SIGUSR1);
break;
case RIL_UNSOL_DATA_CALL_LIST_CHANGED:
{
UCHAR oldConnectionStatus = *pConnectionStatus;
requestQueryDataCall(pConnectionStatus, curIpFamily);
if (profile->IsDualIPSupported)
requestQueryDataCall(&IPV6ConnectionStatus, IpFamilyV6);
if (QWDS_PKT_DATA_CONNECTED != *pConnectionStatus)
{
usbnet_link_change(0, profile);
//connected change to disconnect
if (oldConnectionStatus == QWDS_PKT_DATA_CONNECTED)
send_signo_to_main(SIGUSR1);
} else if (QWDS_PKT_DATA_CONNECTED == *pConnectionStatus) {
usbnet_link_change(1, profile);
if (oldConnectionStatus == QWDS_PKT_DATA_CONNECTED) { //receive two CONNECT IND?
send_signo_to_main(SIGUSR2);
}
}
}
break;
default:
break;
}
}
}
}
}
__main_quit:
usbnet_link_change(0, profile);
if (pthread_join(gQmiThreadID, NULL)) {
dbg_time("%s Error joining to listener thread (%s)", __func__, strerror(errno));
}
close(signal_control_fd[0]);
close(signal_control_fd[1]);
close(qmidevice_control_fd[0]);
close(qmidevice_control_fd[1]);
dbg_time("%s exit", __func__);
if (logfilefp)
fclose(logfilefp);
#ifdef CONFIG_PID_FILE_FORMAT
{
char cmd[255];
sprintf(cmd, "rm " CONFIG_PID_FILE_FORMAT, profile.usbnet_adapter);
system(cmd);
}
#endif
return 0;
}
#define has_more_argv() ((opt < argc) && (argv[opt][0] != '-'))
int main(int argc, char *argv[])
{
int opt = 1;
char * save_usbnet_adapter = NULL;
PROFILE_T profile;
dbg_time("Meig_QConnectManager_Linux_V%s", VERSION_STRING());
memset(&profile, 0x00, sizeof(profile));
profile.pdp = CONFIG_DEFAULT_PDP;
if (!strcmp(argv[argc-1], "&"))
argc--;
opt = 1;
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())
profile.auth = argv[opt++][0] - '0';
break;
case 'm':
if (has_more_argv())
profile.muxid = argv[opt++][0] - '0';
break;
case 'p':
if (has_more_argv())
profile.pincode = argv[opt++];
break;
case 'n':
if (has_more_argv())
profile.pdp = argv[opt++][0] - '0';
break;
case 'f':
if (has_more_argv())
{
const char * filename = argv[opt++];
logfilefp = fopen(filename, "a+");
if (!logfilefp) {
dbg_time("Fail to open %s, errno: %d(%s)", filename, errno, strerror(errno));
}
}
break;
case 'i':
if (has_more_argv())
profile.usbnet_adapter = save_usbnet_adapter = argv[opt++];
break;
case 'v':
debug_qmi = 1;
break;
case 'l':
main_loop = 1;
break;
case '4':
profile.ipv4_flag = 1;
break;
case '6':
profile.ipv6_flag = 1;
break;
case 'd':
if (has_more_argv()) {
profile.qmichannel = argv[opt++];
if (qmidev_is_pciemhi(profile.qmichannel))
profile.usbnet_adapter = "mhi0.1";
}
break;
default:
return usage(argv[0]);
break;
}
}
if (profile.ipv4_flag == 1 && profile.ipv6_flag == 1) {
profile.IsDualIPSupported |= (1 << IpFamilyV6);
} else if (profile.ipv6_flag) {
profile.enable_ipv6 = 1;
}
if (profile.ipv4_flag != 1 && profile.ipv6_flag != 1) { // default enable IPv4
profile.ipv4_flag = 1;
}
if (!(profile.qmichannel) || !(profile.usbnet_adapter)) {
char qmichannel[32+1] = {'\0'};
char usbnet_adapter[32+1] = {'\0'};
if (profile.usbnet_adapter)
strcpy(usbnet_adapter, profile.usbnet_adapter);
if (!qmidevice_detect(qmichannel, usbnet_adapter, sizeof(qmichannel))) {
dbg_time("qmidevice_detect failed");
goto error;
}
if (!(profile.qmichannel))
strset(profile.qmichannel, qmichannel);
if (!(profile.usbnet_adapter))
strset(profile.usbnet_adapter, usbnet_adapter);
}
meig_qmap_mode_detect(&profile);
if (varify_driver(&profile))
return -1;
if (driver_is_mbim(profile.driver_name) || !strncmp(profile.qmichannel, "/dev/mhi_MBIM", strlen("/dev/mhi_MBIM"))) {
dbg_time("Modem works in MBIM mode");
return mbim_main(&profile);
} else {
dbg_time("Modem works in QMI mode");
return qmi_main(&profile);
}
error:
return -1;
}
File diff suppressed because it is too large. Load diff
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large. Load diff
+494
View File
@@ -0,0 +1,494 @@
/* ifconfig
*
* Similar to the standard Unix ifconfig, but with only the necessary
* parts for AF_INET, and without any printing of if info (for now).
*
* Bjorn Wesen, Axis Communications AB
*
*
* Authors of the original ifconfig was:
* Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* $Id: ifconfig.c,v 1.12 2001/08/10 06:02:23 mjn3 Exp $
*
*/
/*
* Heavily modified by Manuel Novoa III Mar 6, 2001
*
* From initial port to busybox, removed most of the redundancy by
* converting to a table-driven approach. Added several (optional)
* args missing from initial port.
*
* Still missing: media, tunnel.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // strcmp and friends
#include <ctype.h> // isdigit and friends
#include <stddef.h> /* offsetof */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <linux/if.h>
#include <net/if_arp.h>
#include <linux/if_ether.h>
#include "QMIThread.h"
#ifdef BB_FEATURE_IFCONFIG_SLIP
#include <linux/if_slip.h>
#endif
#define LOG_TAG "IFCONFIG"
/* I don't know if this is needed for busybox or not. Anyone? */
#define QUESTIONABLE_ALIAS_CASE
/* Defines for glibc2.0 users. */
#ifndef SIOCSIFTXQLEN
#define SIOCSIFTXQLEN 0x8943
#define SIOCGIFTXQLEN 0x8942
#endif
/* ifr_qlen is ifru_ivalue, but it isn't present in 2.0 kernel headers */
#ifndef ifr_qlen
#define ifr_qlen ifr_ifru.ifru_mtu
#endif
#ifndef IFF_DYNAMIC
#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */
#endif
/*
* Here are the bit masks for the "flags" member of struct options below.
* N_ signifies no arg prefix; M_ signifies arg prefixed by '-'.
* CLR clears the flag; SET sets the flag; ARG signifies (optional) arg.
*/
#define N_CLR 0x01
#define M_CLR 0x02
#define N_SET 0x04
#define M_SET 0x08
#define N_ARG 0x10
#define M_ARG 0x20
#define M_MASK (M_CLR | M_SET | M_ARG)
#define N_MASK (N_CLR | N_SET | N_ARG)
#define SET_MASK (N_SET | M_SET)
#define CLR_MASK (N_CLR | M_CLR)
#define SET_CLR_MASK (SET_MASK | CLR_MASK)
#define ARG_MASK (M_ARG | N_ARG)
/*
* Here are the bit masks for the "arg_flags" member of struct options below.
*/
/*
* cast type:
* 00 int
* 01 char *
* 02 HOST_COPY in_ether
* 03 HOST_COPY INET_resolve
*/
#define A_CAST_TYPE 0x03
/*
* map type:
* 00 not a map type (mem_start, io_addr, irq)
* 04 memstart (unsigned long)
* 08 io_addr (unsigned short)
* 0C irq (unsigned char)
*/
#define A_MAP_TYPE 0x0C
#define A_ARG_REQ 0x10 /* Set if an arg is required. */
#define A_NETMASK 0x20 /* Set if netmask (check for multiple sets). */
#define A_SET_AFTER 0x40 /* Set a flag at the end. */
#define A_COLON_CHK 0x80 /* Is this needed? See below. */
/*
* These defines are for dealing with the A_CAST_TYPE field.
*/
#define A_CAST_CHAR_PTR 0x01
#define A_CAST_RESOLVE 0x01
#define A_CAST_HOST_COPY 0x02
#define A_CAST_HOST_COPY_IN_ETHER A_CAST_HOST_COPY
#define A_CAST_HOST_COPY_RESOLVE (A_CAST_HOST_COPY | A_CAST_RESOLVE)
/*
* These defines are for dealing with the A_MAP_TYPE field.
*/
#define A_MAP_ULONG 0x04 /* memstart */
#define A_MAP_USHORT 0x08 /* io_addr */
#define A_MAP_UCHAR 0x0C /* irq */
/*
* Define the bit masks signifying which operations to perform for each arg.
*/
#define ARG_METRIC (A_ARG_REQ /*| A_CAST_INT*/)
#define ARG_MTU (A_ARG_REQ /*| A_CAST_INT*/)
#define ARG_TXQUEUELEN (A_ARG_REQ /*| A_CAST_INT*/)
#define ARG_MEM_START (A_ARG_REQ | A_MAP_ULONG)
#define ARG_IO_ADDR (A_ARG_REQ | A_MAP_USHORT)
#define ARG_IRQ (A_ARG_REQ | A_MAP_UCHAR)
#define ARG_DSTADDR (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE)
#define ARG_NETMASK (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_NETMASK)
#define ARG_BROADCAST (A_ARG_REQ | A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER)
#define ARG_HW (A_ARG_REQ | A_CAST_HOST_COPY_IN_ETHER)
#define ARG_POINTOPOINT (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER)
#define ARG_KEEPALIVE (A_ARG_REQ | A_CAST_CHAR_PTR)
#define ARG_OUTFILL (A_ARG_REQ | A_CAST_CHAR_PTR)
#define ARG_HOSTNAME (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER | A_COLON_CHK)
/*
* Set up the tables. Warning! They must have corresponding order!
*/
struct arg1opt {
const char *name;
unsigned short selector;
unsigned short ifr_offset;
};
struct options {
const char *name;
const unsigned char flags;
const unsigned char arg_flags;
const unsigned short selector;
};
#define ifreq_offsetof(x) offsetof(struct ifreq, x)
static const struct arg1opt Arg1Opt[] = {
{"SIOCSIFMETRIC", SIOCSIFMETRIC, ifreq_offsetof(ifr_metric)},
{"SIOCSIFMTU", SIOCSIFMTU, ifreq_offsetof(ifr_mtu)},
{"SIOCSIFTXQLEN", SIOCSIFTXQLEN, ifreq_offsetof(ifr_qlen)},
{"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)},
{"SIOCSIFNETMASK", SIOCSIFNETMASK, ifreq_offsetof(ifr_netmask)},
{"SIOCSIFBRDADDR", SIOCSIFBRDADDR, ifreq_offsetof(ifr_broadaddr)},
#ifdef BB_FEATURE_IFCONFIG_HW
{"SIOCSIFHWADDR", SIOCSIFHWADDR, ifreq_offsetof(ifr_hwaddr)},
#endif
{"SIOCSIFDSTADDR", SIOCSIFDSTADDR, ifreq_offsetof(ifr_dstaddr)},
#ifdef SIOCSKEEPALIVE
{"SIOCSKEEPALIVE", SIOCSKEEPALIVE, ifreq_offsetof(ifr_data)},
#endif
#ifdef SIOCSOUTFILL
{"SIOCSOUTFILL", SIOCSOUTFILL, ifreq_offsetof(ifr_data)},
#endif
#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
{"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.mem_start)},
{"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.base_addr)},
{"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.irq)},
#endif
/* Last entry if for unmatched (possibly hostname) arg. */
{"SIOCSIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr)},
};
static const struct options OptArray[] = {
{"metric", N_ARG, ARG_METRIC, 0},
{"mtu", N_ARG, ARG_MTU, 0},
{"txqueuelen", N_ARG, ARG_TXQUEUELEN, 0},
{"dstaddr", N_ARG, ARG_DSTADDR, 0},
{"netmask", N_ARG, ARG_NETMASK, 0},
{"broadcast", N_ARG | M_CLR, ARG_BROADCAST, IFF_BROADCAST},
#ifdef BB_FEATURE_IFCONFIG_HW
{"hw", N_ARG, ARG_HW, 0},
#endif
{"pointopoint", N_ARG | M_CLR, ARG_POINTOPOINT, IFF_POINTOPOINT},
#ifdef SIOCSKEEPALIVE
{"keepalive", N_ARG, ARG_KEEPALIVE, 0},
#endif
#ifdef SIOCSOUTFILL
{"outfill", N_ARG, ARG_OUTFILL, 0},
#endif
#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
{"mem_start", N_ARG, ARG_MEM_START, 0},
{"io_addr", N_ARG, ARG_IO_ADDR, 0},
{"irq", N_ARG, ARG_IRQ, 0},
#endif
{"arp", N_CLR | M_SET, 0, IFF_NOARP},
{"trailers", N_CLR | M_SET, 0, IFF_NOTRAILERS},
{"promisc", N_SET | M_CLR, 0, IFF_PROMISC},
{"multicast", N_SET | M_CLR, 0, IFF_MULTICAST},
{"allmulti", N_SET | M_CLR, 0, IFF_ALLMULTI},
{"dynamic", N_SET | M_CLR, 0, IFF_DYNAMIC},
{"up", N_SET , 0, (IFF_UP | IFF_RUNNING)},
{"down", N_CLR , 0, IFF_UP},
{ NULL, 0, ARG_HOSTNAME, (IFF_UP | IFF_RUNNING)}
};
/*
* A couple of prototypes.
*/
#ifdef BB_FEATURE_IFCONFIG_HW
static int in_ether(char *bufp, struct sockaddr *sap);
#endif
#ifdef BB_FEATURE_IFCONFIG_STATUS
extern int interface_opt_a;
extern int display_interfaces(char *ifname);
#endif
/*
* Our main function.
*/
int meig_ifconfig(int argc, char **argv)
{
struct ifreq ifr;
struct sockaddr_in sai;
#ifdef BB_FEATURE_IFCONFIG_HW
struct sockaddr sa;
#endif
const struct arg1opt *a1op;
const struct options *op;
int sockfd; /* socket fd we use to manipulate stuff with */
int goterr;
int selector;
char *p;
char host[128];
unsigned char mask;
unsigned char did_flags;
goterr = 0;
did_flags = 0;
#ifdef BB_FEATURE_IFCONFIG_STATUS
if ((argc > 0) && (strcmp(*argv,"-a") == 0)) {
interface_opt_a = 1;
--argc;
++argv;
}
#endif
if(argc <= 1) {
#ifdef BB_FEATURE_IFCONFIG_STATUS
return display_interfaces(argc ? *argv : NULL);
#else
//error_msg_and_die( "ifconfig was not compiled with interface status display support.");
#endif
}
/* Create a channel to the NET kernel. */
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
//perror_msg_and_die("socket");
}
/* get interface name */
strncpy(ifr.ifr_name, *argv, IFNAMSIZ);
/* Process the remaining arguments. */
while (*++argv != (char *) NULL) {
p = *argv;
mask = N_MASK;
if (*p == '-') { /* If the arg starts with '-'... */
++p; /* advance past it and */
mask = M_MASK; /* set the appropriate mask. */
}
for (op = OptArray ; op->name ; op++) { /* Find table entry. */
if (strcmp(p,op->name) == 0) { /* If name matches... */
if ((mask &= op->flags)) { /* set the mask and go. */
goto FOUND_ARG;;
}
/* If we get here, there was a valid arg with an */
/* invalid '-' prefix. */
++goterr;
goto __LOOP;
}
}
/* We fell through, so treat as possible hostname. */
a1op = Arg1Opt + (sizeof(Arg1Opt) / sizeof(Arg1Opt[0])) - 1;
mask = op->arg_flags;
goto HOSTNAME;
FOUND_ARG:
if (mask & ARG_MASK) {
mask = op->arg_flags;
a1op = Arg1Opt + (op - OptArray);
if (mask & A_NETMASK & did_flags) {
//show_usage();
}
if (*++argv == NULL) {
if (mask & A_ARG_REQ) {
//show_usage();
} else {
--argv;
mask &= A_SET_AFTER; /* just for broadcast */
}
} else { /* got an arg so process it */
HOSTNAME:
did_flags |= (mask & A_NETMASK);
if (mask & A_CAST_HOST_COPY) {
#ifdef BB_FEATURE_IFCONFIG_HW
if (mask & A_CAST_RESOLVE) {
#endif
strncpy(host, *argv, (sizeof host));
sai.sin_family = AF_INET;
sai.sin_port = 0;
if (!strcmp(host, "default")) {
/* Default is special, meaning 0.0.0.0. */
sai.sin_addr.s_addr = INADDR_ANY;
} else if (inet_aton(host, &sai.sin_addr) == 0) {
/* It's not a dotted quad. */
++goterr;
continue;
}
p = (char *) &sai;
#ifdef BB_FEATURE_IFCONFIG_HW
} else { /* A_CAST_HOST_COPY_IN_ETHER */
/* This is the "hw" arg case. */
if (strcmp("ether", *argv) || (*++argv == NULL)) {
//show_usage();
}
strncpy(host, *argv, (sizeof host));
if (in_ether(host, &sa)) {
fprintf(stderr, "invalid hw-addr %s\n", host);
++goterr;
continue;
}
p = (char *) &sa;
}
#endif
memcpy((((char *)(&ifr)) + a1op->ifr_offset),
p, sizeof(struct sockaddr));
} else {
unsigned int i = strtoul(*argv,NULL,0);
p = ((char *)(&ifr)) + a1op->ifr_offset;
#ifdef BB_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ
if (mask & A_MAP_TYPE) {
if (ioctl(sockfd, SIOCGIFMAP, &ifr) < 0) {
++goterr;
continue;
}
if ((mask & A_MAP_UCHAR) == A_MAP_UCHAR) {
*((unsigned char *) p) = i;
} else if (mask & A_MAP_USHORT) {
*((unsigned short *) p) = i;
} else {
*((unsigned long *) p) = i;
}
} else
#endif
if (mask & A_CAST_CHAR_PTR) {
*((caddr_t *) p) = (caddr_t) i;
} else { /* A_CAST_INT */
*((int *) p) = i;
}
}
if (ioctl(sockfd, a1op->selector, &ifr) < 0) {
++goterr;
continue;
}
#ifdef QUESTIONABLE_ALIAS_CASE
if (mask & A_COLON_CHK) {
/*
* Don't do the set_flag() if the address is an alias with
* a - at the end, since it's deleted already! - Roman
*
* Should really use regex.h here, not sure though how well
* it'll go with the cross-platform support etc.
*/
char *ptr;
short int found_colon = 0;
for (ptr = ifr.ifr_name; *ptr; ptr++ ) {
if (*ptr == ':') {
found_colon++;
}
}
if (found_colon && *(ptr - 1) == '-') {
continue;
}
}
#endif
}
if (!(mask & A_SET_AFTER)) {
continue;
}
mask = N_SET;
}
if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
printf("SIOCGIFFLAGS");
++goterr;
} else {
selector = op->selector;
if (mask & SET_MASK) {
ifr.ifr_flags |= selector;
} else {
ifr.ifr_flags &= ~selector;
}
if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
printf("SIOCSIFFLAGS");
++goterr;
}
}
__LOOP:
dbg_time("func = %s, line = %d", __func__, __LINE__);
} /* end of while-loop */
dbg_time("func = %s, line = %d, goterr = %d", __func__, __LINE__, goterr);
return goterr;
}
#ifdef BB_FEATURE_IFCONFIG_HW
/* Input an Ethernet address and convert to binary. */
static int
in_ether(char *bufp, struct sockaddr *sap)
{
unsigned char *ptr;
int i, j;
unsigned char val;
unsigned char c;
sap->sa_family = ARPHRD_ETHER;
ptr = sap->sa_data;
for (i = 0 ; i < ETH_ALEN ; i++) {
val = 0;
/* We might get a semicolon here - not required. */
if (i && (*bufp == ':')) {
bufp++;
}
for (j=0 ; j<2 ; j++) {
c = *bufp;
if (c >= '0' && c <= '9') {
c -= '0';
} else if (c >= 'a' && c <= 'f') {
c -= ('a' - 10);
} else if (c >= 'A' && c <= 'F') {
c -= ('A' - 10);
} else if (j && (c == ':' || c == 0)) {
break;
} else {
return -1;
}
++bufp;
val <<= 4;
val += c;
}
*ptr++ = val;
}
return (int) (*bufp); /* Error if we don't end at end of string. */
}
#endif
+264
View File
@@ -0,0 +1,264 @@
#include "QMIThread.h"
static size_t meig_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 meig_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;
}
static int meig_iface_is_in_bridge(const char *iface) {
char filename[256];
snprintf(filename, sizeof(filename), "/sys/class/net/%s/brport", iface);
return (access(filename, F_OK) == 0 || errno != ENOENT);
}
int meig_bridge_mode_detect(PROFILE_T *profile) {
const char *ifname = profile->qmapnet_adapter ? profile->qmapnet_adapter : profile->usbnet_adapter;
const char *driver;
char bridge_mode[128];
char bridge_ipv4[128];
char ipv4[128];
char buf[64];
size_t n;
int in_bridge;
driver = profile->driver_name;
snprintf(bridge_mode, sizeof(bridge_mode), "/sys/class/net/%s/bridge_mode", ifname);
snprintf(bridge_ipv4, sizeof(bridge_ipv4), "/sys/class/net/%s/bridge_ipv4", ifname);
if (access(bridge_mode, F_OK) && errno == ENOENT) {
snprintf(bridge_mode, sizeof(bridge_mode), "/sys/module/%s/parameters/bridge_mode", driver);
snprintf(bridge_ipv4, sizeof(bridge_ipv4), "/sys/module/%s/parameters/bridge_ipv4", driver);
if (access(bridge_mode, F_OK) && errno == ENOENT) {
bridge_mode[0] = '\0';
}
}
in_bridge = meig_iface_is_in_bridge(ifname);
if (in_bridge) {
dbg_time("notice: iface %s had add to bridge\n", ifname);
} else {
return 0;
}
if (in_bridge && bridge_mode[0] == '\0') {
dbg_time("warnning: can not find bride_mode file for %s\n", ifname);
return 1;
}
n = meig_fread(bridge_mode, buf, sizeof(buf));
if (in_bridge) {
if (n <= 0 || buf[0] == '0') {
dbg_time("warnning: should set 1 to bride_mode file for %s\n", ifname);
return 1;
}
}
else {
if (buf[0] == '0') {
return 0;
}
}
memset(ipv4, 0, sizeof(ipv4));
if (strstr(bridge_ipv4, "/sys/class/net/") || profile->qmap_mode == 0 || profile->qmap_mode == 1) {
snprintf(ipv4, sizeof(ipv4), "0x%x", profile->ipv4.Address);
dbg_time("echo '%s' > %s", ipv4, bridge_ipv4);
meig_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);
meig_fwrite(bridge_ipv4, ipv4, strlen(ipv4));
}
return 1;
}
int meig_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 = meig_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 meig_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;
}
int meig_qmap_mode_detect(PROFILE_T *profile) {
char buf[128];
int n;
char qmap_netcard[128];
struct {
char filename[255 * 2];
char linkname[255 * 2];
} *pl;
pl = (typeof(pl)) malloc(sizeof(*pl));
snprintf(pl->linkname, sizeof(pl->linkname), "/sys/class/net/%s/device/driver", profile->usbnet_adapter);
n = readlink(pl->linkname, pl->filename, sizeof(pl->filename));
pl->filename[n] = '\0';
while (pl->filename[n] != '/')
n--;
strset(profile->driver_name, &pl->filename[n+1]);
if (qmidev_is_gobinet(profile->qmichannel))
{
snprintf(pl->filename, sizeof(pl->filename), "/sys/class/net/%s/qmap_mode", profile->usbnet_adapter);
n = meig_fread(pl->filename, buf, sizeof(buf));
if (n > 0) {
profile->qmap_mode = atoi(buf);
if (profile->qmap_mode > 1) {
profile->muxid = profile->pdp + 0x80; //muxis is 0x8X for PDN-X
sprintf(qmap_netcard, "%s.%d", profile->usbnet_adapter, profile->pdp);
profile->qmapnet_adapter = strdup(qmap_netcard);
} if (profile->qmap_mode == 1) {
profile->muxid = 0x81;
profile->qmapnet_adapter = strdup(profile->usbnet_adapter);
}
}
}
else if(qmidev_is_qmiwwan(profile->qmichannel))
{
snprintf(pl->filename, sizeof(pl->filename), "/sys/module/%s/parameters/qmap_mode", profile->driver_name);
if (access(pl->filename, R_OK) == 0) {
//Meig Style QMAP qmi_wwan.c
if (meig_fread(pl->filename, buf, sizeof(buf))) {
profile->qmap_mode = atoi(buf);
if (profile->qmap_mode > 1) {
profile->muxid = profile->pdp + 0x80; //muxis is 0x8X for PDN-X
sprintf(qmap_netcard, "%s.%d", profile->usbnet_adapter, profile->pdp);
profile->qmapnet_adapter = strdup(qmap_netcard);
#if 1 //TODO Ubuntu qmi_wwan 1-1.3:1.4 wwp0s26u1u3i4: renamed from wwan0
if (access(qmap_netcard, R_OK) && errno == ENOENT) {
sprintf(qmap_netcard, "%s.%d", "wwan0", profile->pdp);
free(profile->qmapnet_adapter);
profile->qmapnet_adapter = strdup(qmap_netcard);
}
#endif
}
else if (profile->qmap_mode == 1) {
profile->muxid = 0x81;
profile->qmapnet_adapter = strdup(profile->usbnet_adapter);
}
}
else if (errno != ENOENT) {
dbg_time("fail to access %s, errno: %d (%s)", pl->filename, errno, strerror(errno));
}
else {
snprintf(pl->filename, sizeof(pl->filename), "/sys/class/net/qmimux%d", profile->pdp - 1);
if (access(pl->filename, R_OK) == 0) {
//upstream Kernel Style QMAP qmi_wwan.c
snprintf(pl->filename, sizeof(pl->filename), "/sys/class/net/%s/qmi/add_mux", profile->usbnet_adapter);
n = meig_fread(pl->filename, buf, sizeof(buf));
if (n >= 3) {
profile->qmap_mode = n/3;
if (profile->qmap_mode > 1) {
//PDN-X map to qmimux-X
profile->muxid = (buf[3*(profile->pdp - 1) + 0] - '0')*16 + (buf[3*(profile->pdp - 1) + 1] - '0');
sprintf(qmap_netcard, "qmimux%d", profile->pdp - 1);
profile->qmapnet_adapter = strdup(qmap_netcard);
} else if (profile->qmap_mode == 1){
profile->muxid = (buf[3*0 + 0] - '0')*16 + (buf[3*0 + 1] - '0');
sprintf(qmap_netcard, "qmimux%d", 0);
profile->qmapnet_adapter = strdup(qmap_netcard);
}
}
}
}
}
else if (errno != ENOENT) {
dbg_time("fail to access %s, errno: %d (%s)", pl->filename, errno, strerror(errno));
}
}
else if (qmidev_is_pciemhi(profile->qmichannel)) {
profile->qmap_mode = 1;
profile->muxid = 0x81;
profile->qmapnet_adapter = strdup(profile->usbnet_adapter);
}
if (profile->qmap_mode) {
dbg_time("qmap_mode = %d, muxid = 0x%02x, qmap_netcard = %s",
profile->qmap_mode, profile->muxid, profile->qmapnet_adapter);
}
free(pl);
return 0;
}
+306
View File
@@ -0,0 +1,306 @@
#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"
static int meig_system(const char *shell_cmd) {
dbg_time("%s", shell_cmd);
return system(shell_cmd);
}
static void meig_set_mtu(const char *ifname, int ifru_mtu) {
int inet_sock;
struct ifreq ifr;
inet_sock = socket(AF_INET, SOCK_DGRAM, 0);
if (inet_sock > 0) {
strcpy(ifr.ifr_name, ifname);
if (!ioctl(inet_sock, SIOCGIFMTU, &ifr)) {
if (ifr.ifr_ifru.ifru_mtu != ifru_mtu) {
dbg_time("change mtu %d -> %d", ifr.ifr_ifru.ifru_mtu , ifru_mtu);
ifr.ifr_ifru.ifru_mtu = ifru_mtu;
ioctl(inet_sock, SIOCSIFMTU, &ifr);
}
}
close(inet_sock);
}
}
static void* udhcpc_thread_function(void* arg) {
FILE * udhcpc_fp;
char *udhcpc_cmd = (char *)arg;
if (udhcpc_cmd == NULL)
return NULL;
dbg_time("%s", udhcpc_cmd);
udhcpc_fp = popen(udhcpc_cmd, "r");
free(udhcpc_cmd);
if (udhcpc_fp) {
char buf[0xff];
buf[sizeof(buf)-1] = '\0';
while((fgets(buf, sizeof(buf)-1, udhcpc_fp)) != NULL) {
if ((strlen(buf) > 1) && (buf[strlen(buf) - 1] == '\n'))
buf[strlen(buf) - 1] = '\0';
dbg_time("%s", buf);
}
pclose(udhcpc_fp);
}
return NULL;
}
//#define USE_DHCLIENT
#ifdef USE_DHCLIENT
static int dhclient_alive = 0;
#endif
static int dibbler_client_alive = 0;
void udhcpc_start(PROFILE_T *profile) {
char *ifname = profile->usbnet_adapter;
char shell_cmd[128];
if (profile->qmapnet_adapter) {
ifname = profile->qmapnet_adapter;
}
if (profile->rawIP && profile->ipv4.Address && profile->ipv4.Mtu) {
meig_set_mtu(ifname, (profile->ipv4.Mtu));
}
if (strcmp(ifname, profile->usbnet_adapter)) {
snprintf(shell_cmd, sizeof(shell_cmd), "ifconfig %s up", profile->usbnet_adapter);
meig_system(shell_cmd);
}
snprintf(shell_cmd, sizeof(shell_cmd), "ifconfig %s up", ifname);
meig_system(shell_cmd);
#if 1 //for bridge mode, only one public IP, so do udhcpc manually
if (meig_bridge_mode_detect(profile)) {
return;
}
#endif
/* Do DHCP using Routing Discovery Protocol */
/* This is needed for IPv6 */
//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
//zpf
#if 1
if (profile->rawIP != 0) //mdm9x07/ec25,ec20 R2.0
{
if (profile->ipv4.Address) {
unsigned char *ip = (unsigned char *)&profile->ipv4.Address;
unsigned char *gw = (unsigned char *)&profile->ipv4.Gateway;
unsigned char *netmask = (unsigned char *)&profile->ipv4.SubnetMask;
unsigned char *dns1 = (unsigned char *)&profile->ipv4.DnsPrimary;
unsigned char *dns2 = (unsigned char *)&profile->ipv4.DnsSecondary;
snprintf(shell_cmd, sizeof(shell_cmd), "ifconfig %s %d.%d.%d.%d netmask %d.%d.%d.%d",ifname,
ip[3], ip[2], ip[1], ip[0], netmask[3], netmask[2], netmask[1], netmask[0]);
meig_system(shell_cmd);
//Resetting default routes
snprintf(shell_cmd, sizeof(shell_cmd), "route del default gw 0.0.0.0 dev %s", ifname);
while(!system(shell_cmd));
snprintf(shell_cmd, sizeof(shell_cmd), "route add default gw %d.%d.%d.%d dev %s metric 0", gw[3], gw[2], gw[1], gw[0], ifname);
meig_system(shell_cmd);
//Adding DNS
if (profile->ipv4.DnsSecondary == 0)
profile->ipv4.DnsSecondary = profile->ipv4.DnsPrimary;
if (dns1[0]) {
dbg_time("Adding DNS %d.%d.%d.%d %d.%d.%d.%d", dns1[3], dns1[2], dns1[1], dns1[0], dns2[3], dns2[2], dns2[1], dns2[0]);
snprintf(shell_cmd, sizeof(shell_cmd), "echo -n \"nameserver %d.%d.%d.%d\nnameserver %d.%d.%d.%d\n\" > /etc/resolv.conf",
dns1[3], dns1[2], dns1[1], dns1[0], dns2[3], dns2[2], dns2[1], dns2[0]);
system(shell_cmd);
}
}
/*
if (profile->ipv6.Address[0] && profile->ipv6.PrefixLengthIPAddr) {
unsigned char *ip = (unsigned char *)&profile->ipv4.Address;
#if 1
snprintf(shell_cmd, sizeof(shell_cmd), "ifconfig %s inet6 add %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x/%d",
ifname, ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7], ip[8], ip[9], ip[10], ip[11], ip[12], ip[13], ip[14], ip[15], profile->ipv6.PrefixLengthIPAddr);
#else
snprintf(shell_cmd, sizeof(shell_cmd), "ip -6 addr add %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x/%d dev %s",
ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7], ip[8], ip[9], ip[10], ip[11], ip[12], ip[13], ip[14], ip[15], profile->ipv6.PrefixLengthIPAddr, ifname);
#endif
meig_system(shell_cmd);
snprintf(shell_cmd, sizeof(shell_cmd), "route -A inet6 add default dev %s", ifname);
meig_system(shell_cmd);
}
*/
return;
}
#endif
/* Do DHCP using busybox tools */
{
char udhcpc_cmd[128];
pthread_attr_t udhcpc_thread_attr;
pthread_t udhcpc_thread_id;
pthread_attr_init(&udhcpc_thread_attr);
pthread_attr_setdetachstate(&udhcpc_thread_attr, PTHREAD_CREATE_DETACHED);
if (profile->ipv4.Address) {
#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)) {
dbg_time("Fail to access /usr/share/udhcpc/default.script, errno: %d (%s)", errno, strerror(errno));
}
//-f,--foreground Run in foreground
//-b,--background Background if lease is not obtained
//-n,--now Exit if lease is not obtained
//-q,--quit Exit after obtaining lease
//-t,--retries N Send up to N discover packets (default 3)
snprintf(udhcpc_cmd, sizeof(udhcpc_cmd), "busybox udhcpc -f -n -q -t 5 -i %s", ifname);
#endif
#if 1 //for OpenWrt
if (!access("/lib/netifd/dhcp.script", X_OK) && !access("/sbin/ifup", X_OK) && !access("/sbin/ifstatus", X_OK)) {
dbg_time("you are use OpenWrt?");
dbg_time("should not calling udhcpc manually?");
dbg_time("should modify /etc/config/network as below?");
dbg_time("config interface wan");
dbg_time("\toption ifname %s", ifname);
dbg_time("\toption proto dhcp");
dbg_time("should use \"/sbin/ifstaus wan\" to check %s 's status?", ifname);
}
#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);
#endif
}
if (profile->ipv6.Address[0] && profile->ipv6.PrefixLengthIPAddr) {
const unsigned char *d = (unsigned char *)&profile->ipv6.Address;
#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];
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);
}
snprintf(shell_cmd, sizeof(shell_cmd),
"ip -%d address add %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x/%u dev %s",
6, d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15],
profile->ipv6.PrefixLengthIPAddr, ifname);
meig_system(shell_cmd);
//ping6 www.qq.com
d = (unsigned char *)&profile->ipv6.Gateway;
snprintf(shell_cmd, sizeof(shell_cmd),
"ip -%d route add default via %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x dev %s",
6, d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15],
ifname);
meig_system(shell_cmd);
if (profile->ipv6.DnsPrimary[0] || profile->ipv6.DnsSecondary[0]) {
char dns1str[128], dns2str[128];
if (profile->ipv6.DnsPrimary[0]) {
d = profile->ipv6.DnsPrimary;
snprintf(dns1str, sizeof(dns1str), "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
}
if (profile->ipv6.DnsSecondary[0]) {
d = profile->ipv6.DnsSecondary;
snprintf(dns2str, sizeof(dns2str), "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
}
update_resolv_conf(6, ifname, profile->ipv6.DnsPrimary[0] ? dns1str : NULL, profile->ipv6.DnsSecondary ? dns2str : NULL);
}
#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);
meig_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];
if (profile->qmapnet_adapter) {
ifname = profile->qmapnet_adapter;
}
#ifdef USE_DHCLIENT
if (dhclient_alive) {
system("killall dhclient");
dhclient_alive = 0;
}
#endif
if (dibbler_client_alive) {
system("killall dibbler-client");
dibbler_client_alive = 0;
}
snprintf(shell_cmd, sizeof(shell_cmd), "ifconfig %s down", ifname);
meig_system(shell_cmd);
snprintf(shell_cmd, sizeof(shell_cmd), "ifconfig %s 0.0.0.0", ifname);
meig_system(shell_cmd);
}
+208
View File
@@ -0,0 +1,208 @@
#include <sys/time.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"
/*
* Use clock_gettime instead of gettimeofday
* -- Warnning:
* There is a risk that, the system may sync time at anytime.
* if gettimeofday may returns just before the sync time point,
* the funtion pthread_cond_timedwait will failed.
* -- use clock_gettime to get relative time will avoid the risk.
*/
void setTimespecRelative(struct timespec *p_ts, long long msec)
{
struct timespec ts;
/*
CLOCK_REALTIME system time from 1970-1-1
CLOCK_MONOTONIC system start time, cannot be changed
CLOCK_PROCESS_CPUTIME_ID the process running time
CLOCK_THREAD_CPUTIME_ID the thread running time
*/
clock_gettime(CLOCK_MONOTONIC, &ts);
p_ts->tv_sec = ts.tv_sec + (msec / 1000);
p_ts->tv_nsec = ts.tv_nsec + (msec % 1000) * 1000L * 1000L;
}
int pthread_cond_timeout_np(pthread_cond_t *cond, pthread_mutex_t * mutex, unsigned msecs) {
if (msecs != 0) {
struct timespec ts;
setTimespecRelative(&ts, msecs);
return pthread_cond_timedwait(cond, mutex, &ts);
} else {
return pthread_cond_wait(cond, mutex);
}
}
void cond_setclock_attr(pthread_cond_t *cond, clockid_t clock)
{
/* set relative time, for pthread_cond_timedwait */
pthread_condattr_t attr;
pthread_condattr_init (&attr);
pthread_condattr_setclock(&attr, clock);
pthread_cond_init(cond, &attr);
pthread_condattr_destroy (&attr);
}
const char * get_time(void) {
static char time_buf[50];
struct timeval tv;
time_t time;
suseconds_t millitm;
struct tm *ti;
gettimeofday (&tv, NULL);
time= tv.tv_sec;
millitm = (tv.tv_usec + 500) / 1000;
if (millitm == 1000) {
++time;
millitm = 0;
}
ti = localtime(&time);
sprintf(time_buf, "%02d-%02d_%02d:%02d:%02d:%03d", ti->tm_mon+1, ti->tm_mday, ti->tm_hour, ti->tm_min, ti->tm_sec, (int)millitm);
return time_buf;
}
FILE *logfilefp = NULL;
const int i = 1;
#define is_bigendian() ( (*(char*)&i) == 0 )
USHORT le16_to_cpu(USHORT v16) {
USHORT tmp = v16;
if (is_bigendian()) {
unsigned char *s = (unsigned char *)(&v16);
unsigned char *d = (unsigned char *)(&tmp);
d[0] = s[1];
d[1] = s[0];
}
return tmp;
}
UINT le32_to_cpu (UINT v32) {
UINT tmp = v32;
if (is_bigendian()) {
unsigned char *s = (unsigned char *)(&v32);
unsigned char *d = (unsigned char *)(&tmp);
d[0] = s[3];
d[1] = s[2];
d[2] = s[1];
d[3] = s[0];
}
return tmp;
}
UINT meig_swap32(UINT v32) {
UINT tmp = v32;
{
unsigned char *s = (unsigned char *)(&v32);
unsigned char *d = (unsigned char *)(&tmp);
d[0] = s[3];
d[1] = s[2];
d[2] = s[1];
d[3] = s[0];
}
return tmp;
}
USHORT cpu_to_le16(USHORT v16) {
USHORT tmp = v16;
if (is_bigendian()) {
unsigned char *s = (unsigned char *)(&v16);
unsigned char *d = (unsigned char *)(&tmp);
d[0] = s[1];
d[1] = s[0];
}
return tmp;
}
UINT cpu_to_le32 (UINT v32) {
UINT tmp = v32;
if (is_bigendian()) {
unsigned char *s = (unsigned char *)(&v32);
unsigned char *d = (unsigned char *)(&tmp);
d[0] = s[3];
d[1] = s[2];
d[2] = s[1];
d[3] = s[0];
}
return tmp;
}
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]);
}
+55
View File
@@ -0,0 +1,55 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _UTILS_H_
#define _UTILS_H_
#include <stddef.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);
#endif