mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-04 04:33:56 +08:00
🌴 Sync 2026-03-05 23:51:42
This commit is contained in:
1 parent
97c049ed0a
commit
0acff03804
14253 files changed
+3893239
No files matched your search
@@ -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))
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -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
@@ -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
|
||||
@@ -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,
|
||||
};
|
||||
@@ -0,0 +1,61 @@
|
||||
Release Notes
|
||||
[WCDMA<E_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<E_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<E_QConnectManager_Linux&Android_V1.1.45]
|
||||
Date: 2018/09/13
|
||||
enhancement:
|
||||
1. support EG12 PCIE interface
|
||||
|
||||
[WCDMA<E_QConnectManager_Linux&Android_V1.1.44]
|
||||
Date: 2018/09/10
|
||||
enhancement:
|
||||
1. support setup IPV4&IPV6 data call.
|
||||
|
||||
[WCDMA<E_QConnectManager_Linux&Android_V1.1.43]
|
||||
[WCDMA<E_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<E_QConnectManager_Linux&Android_V1.1.41]
|
||||
Date: 2018/05/24
|
||||
enhancement:
|
||||
1. fix a cdma data call error
|
||||
|
||||
[WCDMA<E_QConnectManager_Linux&Android_V1.1.40]
|
||||
Date: 2018/05/12
|
||||
enhancement:
|
||||
1. support GobiNet's QMAP fucntion and bridge mode.
|
||||
'Meig_WCDMA<E_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
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
#export PATH=/home/zhaopengfei/ruiming/aarch64-himix200-linux/bin:$PATH
|
||||
make clean
|
||||
make CROSS_COMPILE=arm-hisiv500-linux-
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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]);
|
||||
}
|
||||
@@ -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
|
||||
Reference in new issue
Block a user