blob: 645cd38abbbe35e957a1df431525304a70682b3b [file] [log] [blame]
// Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <wchar.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <fcntl.h>
#include <errno.h>
#include <assert.h>
#include <pthread.h>
#include "cm.h"
#include "dhclient.h"
extern int device_open(GDEV_ID_P pID);
extern int device_close(GDEV_ID_P pID);
extern void cmd_signal_event(int dev_idx, unsigned short event, char *data, int len);
#if defined(CONFIG_DM_INTERFACE)
int send_dm_tool(void *data, int len);
int dm_ind_connetion(int connect, int success);
#endif
char *StatusStr[] = {
"UnInitialized",
"RF_OFF_HW_SW",
"RF_OFF_HW",
"RF_OFF_SW",
"Ready",
"Scanning",
"Connecting",
"Data_Connected"
};
char *ConnStatusStr[] = {
"Ranging",
"SBC",
"EAP_authentication_Device",
"EAP_authentication_User",
"3_way_handshake",
"Registration",
"De_registration",
"Registered",
"DSX"
};
static char *StatusReasonStr[] = {
"Normal",
"Fail_to_connect_to_NW",
"Fail_to_connect_Ranging",
"Fail_to_connect_SBC",
"Fail_to_connect_EAP_AUTH_Device",
"Fail_to_connect_EAP_AUTH_user",
"Fail_to_connect_3_Way_Handshake",
"Fail_to_connect_REG",
"Fail_to_connect_datapath"
};
static void print_disconnect_reason(u8 *data, int len)
{
char *msg = "disconnected by unknown reason";
/*
Reason(1 byte) :
Disconnect Reason
0x00 : disconnected by DREG
0x01 : disconnected by MS
0x02 : disconnected by OoZ
0x03 : disconnected by all other reason
*/
switch (*data) {
case 0x00:
msg = "disconnected by DREG";
break;
case 0x01:
msg = "disconnected by MS";
break;
case 0x02:
msg = "disconnected by OoZ";
break;
case 0x03:
msg = "disconnected by all other reason";
break;
}
cm_printf("%s\n", msg);
}
static void ind_recv_hci_packet(GDEV_ID_P pID, char *buf, int len)
{
unsigned short event;
unsigned short length;
unsigned char *data, *p;
hci_t *hci = (hci_t *) buf;
cm_common_conf_t *pconf = &cm_common_conf;
#if defined(CONFIG_DM_INTERFACE)
if (pconf->dm_interface_enable && pconf->dm_interface_cfd > 0)
send_dm_tool(buf, len);
#endif
event = _B2H(hci->cmd_evt);
length = _B2H(hci->length);
data = hci->data;
switch (event) {
case WIMAX_DISCONN_IND:
print_disconnect_reason(data, length);
break;
case WIMAX_IP_RENEW_IND:
dh_stop_dhclient(pID->deviceIndex);
dh_start_dhclient(pID->deviceIndex);
break;
case WIMAX_CLI_RSP:
case WIMAX_MANAGER_MSG:
#if 1
data[length] = 0;
p = &data[WIMAX_PRINT_PAD];
cm_flag_printf("%s", p);
#else
length -= WIMAX_PRINT_PAD;
data += WIMAX_PRINT_PAD;
cm_printf("%s", data);
//fwrite(data, 1, length, stdout);
//fflush(stdout);
#endif
#if (CM_LOG_FLAG & LOG_FLAG_NO_STDOUT_IN_LOGFILE)
if (GAPI_LOG_LEVEL_IS_FILE(pconf->log_level)) {
const char dm_prompt[] = "DM> ";
if (*(int *) p == *(int *) dm_prompt) {
printf("%s", p);
fflush(stdout);
}
}
#endif
break;
case WIMAX_DL_IMAGE_STATUS:
case WIMAX_UL_IMAGE_RESULT:
case WIMAX_FILE_RESULT:
case WIMAX_IMAGE_CMD_STATUS:
cmd_signal_event(pID->deviceIndex, event, (char *)data, length);
break;
}
}
static void ind_powermode_change(GDEV_ID_P pID, GCT_API_POWER_MODE nPowerMode)
{
char *power_mode = "Unknown";
switch (nPowerMode) {
case WiMAXPowerModeIdle:
power_mode = "Idle";
break;
case WiMAXPowerModeSleep:
power_mode = "Sleep";
break;
case WiMAXPowerModeNormal:
power_mode = "Normal";
break;
case WiMAXPowerModeMaximum:
power_mode = "Maximum";
break;
}
cm_printf("device[%d] power mode: %s\n", pID->deviceIndex, power_mode);
}
static void ind_connect_network(GDEV_ID_P pID,
WIMAX_API_NETWORK_CONNECTION_RESP networkConnectionResponse)
{
cm_common_conf_t *pconf = &cm_common_conf;
#if defined(CONFIG_DM_INTERFACE)
if (pconf->dm_interface_enable && pconf->dm_interface_cfd > 0)
dm_ind_connetion(1, networkConnectionResponse==WIMAX_API_CONNECTION_SUCCESS);
#endif
cm_printf("device[%d] connection %s\n", pID->deviceIndex,
networkConnectionResponse==WIMAX_API_CONNECTION_SUCCESS
? "SUCCESS" : "FAIL");
if (pconf->api_mode != GCT_WIMAX_API_PRIVILEGE_READ_ONLY) {
if (networkConnectionResponse==WIMAX_API_CONNECTION_SUCCESS)
dh_start_dhclient(pID->deviceIndex);
#if defined(CONFIG_DM_INTERFACE)
else if (pconf->auto_connect_enable)
cm_retry_auto_connection(pID->deviceIndex);
#endif
}
}
static void ind_dev_disconnect_network(GDEV_ID_P pID,
WIMAX_API_NETWORK_CONNECTION_RESP networkDisconnectResponse)
{
cm_common_conf_t *pconf = &cm_common_conf;
#if defined(CONFIG_DM_INTERFACE)
if (pconf->dm_interface_enable && pconf->dm_interface_cfd > 0)
dm_ind_connetion(0, networkDisconnectResponse==WIMAX_API_CONNECTION_SUCCESS);
#endif
cm_printf("device[%d] disconnection %s\n", pID->deviceIndex,
networkDisconnectResponse==WIMAX_API_CONNECTION_SUCCESS
? "SUCCESS" : "FAIL");
if (networkDisconnectResponse==WIMAX_API_CONNECTION_SUCCESS)
dh_stop_dhclient(pID->deviceIndex);
if (pconf->api_mode != GCT_WIMAX_API_PRIVILEGE_READ_ONLY) {
if (pconf->auto_connect_enable)
cm_request_auto_connection(pID->deviceIndex);
}
}
static void ind_dev_network_search_widescan(GDEV_ID_P pID,
WIMAX_API_NSP_INFO_P pNspList, UINT32 listSize)
{
int i;
cm_printf("[NSP-Name] [NSP-ID] [RSSI] [CINR]\n");
for (i = 0; i < listSize; i++) {
cm_printf("%9S %06X %6d %6d\n",
(wchar_t *) pNspList[i].NSPName,
(int) pNspList[i].NSPid,
(int) pNspList[i].RSSI-123,
(int) pNspList[i].CINR-10);
}
}
static void ind_dev_provisioning_operation(GDEV_ID_P pID,
WIMAX_API_PROV_OPERATION provisioningOperation,
WIMAX_API_CONTACT_TYPE contactType)
{
char *op = NULL;
switch (provisioningOperation) {
case WIMAX_API_PROV_OPERATION_CFG_UPDATE_STARTED:
op = "STARTED";
break;
case WIMAX_API_PROV_OPERATION_CFG_UPDATE_COMPLETED:
op = "COMPLETED";
break;
case WIMAX_API_PROV_OPERATION_CFG_UPDATE_FAILED_NETWORK_DISCONNECT:
op = "FAILED_NETWORK_DISCONNECT";
break;
case WIMAX_API_PROV_OPERATION_CFG_UPDATE_FAILED:
op = "FAILED";
break;
case WIMAX_API_PROV_OPERATION_CFG_UPDATE_FAILED_INVALID_PROVISIONING:
op = "FAILED_INVALID_PROVISIONING";
break;
case WIMAX_API_PROV_OPERATION_CFG_UPDATE_FAILED_BAD_AUTHENTICATION:
op = "FAILED_BAD_AUTHENTICATION";
break;
case WIMAX_API_PROV_OPERATION_CFG_UPDATE_REQUEST_INITIAL_PROVISIONING:
op = "REQUEST_INITIAL_PROVISIONING";
break;
case WIMAX_API_PROV_OPERATION_CFG_UPDATE_REQUEST_ONGOING_PROVISIONING:
op = "REQUEST_ONGOING_PROVISIONING";
break;
case WIMAX_API_PROV_OPERATION_CFG_UPDATE_REQUEST_RESET_PROVISIONING:
op = "REQUEST_RESET_PROVISIONING";
break;
case WIMAX_API_PROV_OPERATION_CFG_UPDATE_TRIGGER_CONTACT:
op = "TRIGGER_CONTACT";
break;
}
if (op)
cm_printf("Provisioning:%s, contact-type=%d\n", op, contactType);
else
cm_printf("Provisioning:Unknown(%d), contact-type=%d\n", provisioningOperation, contactType);
}
static void ind_power_mng(
GDEV_ID_P pID,
WIMAX_API_RF_STATE powerState)
{
cm_printf("device[%d] Power %s\n", pID->deviceIndex,
powerState==WIMAX_API_RF_ON ? "ON" : "OFF");
}
static void ind_dev_insert_remove(GDEV_ID_P pID, BOOL cardPresence)
{
cm_printf("device[%d] %s\n", pID->deviceIndex,
cardPresence ? "INSERT" : "REMOVE");
if (cardPresence)
device_open(pID);
else
device_close(pID);
}
static void ind_dev_status(GDEV_ID_P pID,
WIMAX_API_DEVICE_STATUS deviceStatus, WIMAX_API_STATUS_REASON statusReason,
WIMAX_API_CONNECTION_PROGRESS_INFO connectionProgressInfo)
{
dev_conf_t *dconf = &cm_dev_conf[pID->deviceIndex];
dconf->wimax_status = deviceStatus;
if (deviceStatus > WIMAX_API_DEVICE_STATUS_Data_Connected) {
cm_printf("device[%d] Unknown device status[%d]\n",
pID->deviceIndex, deviceStatus);
return;
}
cm_printf("device[%d] status [%s]\n", pID->deviceIndex, StatusStr[deviceStatus]);
if (dconf->ip_acq_timed && deviceStatus != WIMAX_API_DEVICE_STATUS_Data_Connected) {
cm_stop_timer(&dconf->ip_acq_timer);
dconf->ip_acq_timed = 0;
}
if (deviceStatus == WIMAX_API_DEVICE_STATUS_Connecting) {
if (connectionProgressInfo <= WIMAX_API_DEVICE_CONNECTION_PROGRESS_Registration_DSX) {
cm_printf("device[%d] Connection Progress Info [%s]\n",
pID->deviceIndex, ConnStatusStr[connectionProgressInfo]);
} else {
cm_printf("device[%d] Unknown connection Progress Info [%d]\n",
pID->deviceIndex, connectionProgressInfo);
return;
}
}
if (statusReason != WIMAX_API_STATUS_REASON_Normal) {
if (statusReason <= WIMAX_API_STATUS_REASON_Fail_to_connect_datapath) {
cm_printf("device[%d] Status Reason [%s]\n",
pID->deviceIndex, StatusReasonStr[statusReason]);
} else {
cm_printf("device[%d] Unknown status Reason [%d]\n",
pID->deviceIndex, statusReason);
}
}
}
#if defined(CONFIG_ENABLE_SERVICE_FLOW)
static void ind_noti_service_flow(GDEV_ID_P pID, WIMAX_SF_EVENT_P pSfEvent)
{
cm_printf("device[%d] WIMAX_SF_EVENT_TYPE[%d], CC=[%d]\n", pID->deviceIndex, pSfEvent->code, pSfEvent->sf.cc);
}
#endif // CONFIG_ENABLE_SERVICE_FLOW
#define E_WM_CR801_EAP_FAILURE -201
#define E_WM_UNKNOWN_SERVER_REALM -202
static void eap_get_error_string(int err_code, char *err_str)
{
switch (err_code) {
case 0:
strcpy(err_str, "Success.");
break;
case -1:
strcpy(err_str, "CA Certification File Load Failed");
break;
case -2:
strcpy(err_str, "Client Cert. or Private Key File Load Failed");
break;
case -3:
strcpy(err_str, "Mutual Authentication Failed");
break;
case -4:
strcpy(err_str, "Phase 2 Authentication Failed");
break;
case -5:
strcpy(err_str, "Insufficient Memory");
break;
case -6:
strcpy(err_str, "Not Supported Functionality");
break;
case -7:
strcpy(err_str, "Invalid Parameter Setting");
break;
case -8:
strcpy(err_str, "EAP Configuration was not setted.");
break;
case -9:
strcpy(err_str, "Internal Callback Function failed.");
break;
case -10:
strcpy(err_str, "TLS Initialization failed.");
break;
case -11:
strcpy(err_str, "Internal Static Buffer is too small.");
break;
case -12:
strcpy(err_str, "Getting the MSK was failed.");
break;
case -13:
strcpy(err_str, "There's no more date from TLSDealEAPPayload().");
break;
case -14:
strcpy(err_str, "Invalid EAP Packet Frame.");
break;
case -15:
strcpy(err_str, "Invalid TLS from server.");
break;
case -16:
strcpy(err_str, "Invalid TLS to server.");
break;
case -17:
strcpy(err_str, "There's no certification file.");
break;
case -18:
strcpy(err_str, "CTX Allocation failed.");
break;
case -19:
strcpy(err_str, "Loading Certification File in TLSGetCertInfo()");
break;
case -20:
strcpy(err_str, "p_szRtnBuf, p_nRtnBufSize is NULL.");
break;
case -21:
strcpy(err_str, "Writing the P12 File is failed in TLSConvertP12().");
break;
case -22:
strcpy(err_str, "Invalid Password for P12 File in TLSConvertP12().");
break;
case -23:
strcpy(err_str, "There's no ID (InnerNAI) for EAP-Response_Identity.");
break;
case -24:
strcpy(err_str, "Invalid AVP in TTLS-MSCHAPv2.");
break;
case -25:
strcpy(err_str, "Received Invalid AVP from AAA in TTLS-MSCHAPv2.");
break;
case -26:
strcpy(err_str, "Internal Buffer Pointer is NULL.");
break;
case -27:
strcpy(err_str, "There's no or invalid 'S=' Value in MSCHAPv2.");
break;
case -28:
strcpy(err_str, "Invalid Identifier in MSCHAPv2.");
break;
case -29:
strcpy(err_str, "There's no SSL Context.");
break;
case -30:
strcpy(err_str, "TLS Record Length is over than internal buffer size.");
break;
case -31:
strcpy(err_str, "There's misorder in TTLS's internal authentication.");
break;
case E_WM_CR801_EAP_FAILURE:
strcpy(err_str, "Receive failure packet.");
break;
case E_WM_UNKNOWN_SERVER_REALM:
strcpy(err_str, "Unknown server realm");
break;
case 1:
strcpy(err_str, "ID not found");
break;
case 2:
strcpy(err_str, "Password not found");
break;
case 3:
strcpy(err_str, "CA certificate error");
break;
case 4:
strcpy(err_str, "Private certificate error");
break;
case 5:
strcpy(err_str, "Server rejected");
break;
default:
strcpy(err_str, "Unknown Error.");
break;
}
}
static void odm_get_error_string(int err_code, char *err_str)
{
static const char *odm_err_str[] = {
"NONE",
"INVALID_BOOTSTRAP_MESSAGE",
"CANNOT_CONNECT_ODM_SERVER",
"HTTP_ERROR",
"HTTP_RESPONSE_TIMEOUT",
"STATUS_ERROR",
"DNS_QUERY_FAIL",
"CANNOT_CONNECT_WIB_SERVER"
};
if (_numof_array(odm_err_str) < err_code)
cm_printf("OMA-DM invalid error code=%d\n", err_code);
else
strcpy(err_str, odm_err_str[err_code]);
}
void ind_notification(GDEV_ID_P pID, GCT_API_NOTI_CATEGORY category,
GCT_API_NOTI_TYPE type, int buf_size, char *buf)
{
char string[256];
char *title = "Unknown";
short code = 0;
int odm_err = 0;
switch (category) {
case GCT_API_ERROR_NOTI_EAP:
title = "EAP Error";
if (type == GCT_API_NOTI_TYPE_CODE) {
memcpy(&code, buf, sizeof(short));
if (CAP_EEAP_ENABLED(pID->deviceIndex))
code = _B2H(code);
eap_get_error_string(code, string);
cm_printf("\t%s: %s\n", title, string);
if (code == E_WM_UNKNOWN_SERVER_REALM)
cm_printf("\tserver realm: %s\n", &buf[sizeof(short)]);
}
break;
case GCT_API_NOTI_EAP:
title = "EAP Notification";
break;
case GCT_API_NOTI_ODM_NOTI:
title = "ODM Notification";
if (type == GCT_API_NOTI_TYPE_CODE) {
code = buf[0];
switch (code) {
case GCT_API_ODM_NOTI_EXEC_REGISTRATION_PAGE_OPEN:
cm_printf("\t%s EXEC_REGISTRATION_PAGE_OPEN: %s\n", title, &buf[1]);
break;
case GCT_API_ODM_NOTI_CHANGE_ACTIVATED:
cm_printf("\t%s CHANGE_ACTIVATED\n", title);
break;
default:
cm_printf("\t%s: code=%d\n", title, code);
break;
}
}
break;
case GCT_API_NOTI_ODM_ERROR:
memcpy(&odm_err, buf, sizeof(odm_err));
odm_get_error_string(odm_err, string);
cm_printf("OMA-DM Error: %s\n", string);
break;
default:
title = "Unknown";
break;
}
if (type == GCT_API_NOTI_TYPE_TEXT)
cm_printf("[%s]\n%s", title, buf);
}
void reg_indications(APIHAND *api_handle)
{
GCT_API_RET ret;
ret = GAPI_RegRcvHCIPacketFunc(api_handle, ind_recv_hci_packet);
if (ret != GCT_API_RET_SUCCESS)
cm_eprintf("GAPI_RegRcvHCIPacketFunc error=%d\n", ret);
ret = GAPI_RegPowerModeChange(api_handle, ind_powermode_change);
if (ret != GCT_API_RET_SUCCESS)
cm_eprintf("GAPI_RegPowerModeChange error=%d\n", ret);
ret = GAPI_SubscribeDeviceInsertRemove(api_handle, ind_dev_insert_remove);
if (ret != GCT_API_RET_SUCCESS)
cm_eprintf("GAPI_SubscribeDeviceInsertRemove error=%d\n", ret);
ret = GAPI_SubscribeControlPowerManagement(api_handle, ind_power_mng);
if (ret != GCT_API_RET_SUCCESS)
cm_eprintf("GAPI_SubscribeControlPowerManagement error=%d\n", ret);
ret = GAPI_SubscribeConnectToNetwork(api_handle, ind_connect_network);
if (ret != GCT_API_RET_SUCCESS)
cm_eprintf("GAPI_SubscribeConnectToNetwork error=%d\n", ret);
ret = GAPI_SubscribeDisconnectFromNetwork(api_handle, ind_dev_disconnect_network);
if (ret != GCT_API_RET_SUCCESS)
cm_eprintf("GAPI_SubscribeDisconnectFromNetwork error=%d\n", ret);
ret = GAPI_SubscribeNetworkSearchWideScan(api_handle, ind_dev_network_search_widescan);
if (ret != GCT_API_RET_SUCCESS)
cm_eprintf("GAPI_SubscribeNetworkSearchWideScan error=%d\n", ret);
ret = GAPI_SubscribeProvisioningOperation(api_handle, ind_dev_provisioning_operation);
if (ret != GCT_API_RET_SUCCESS)
cm_eprintf("GAPI_SubscribeProvisioningOperation error=%d\n", ret);
ret = GAPI_SubscribeDeviceStatusChange(api_handle, ind_dev_status);
if (ret != GCT_API_RET_SUCCESS)
cm_eprintf("GAPI_SubscribeDeviceStatusChange error=%d\n", ret);
ret = GAPI_SubscribeNotiFunc(api_handle, ind_notification);
if (ret != GCT_API_RET_SUCCESS)
cm_eprintf("GAPI_SubscribeNotiFunc error=%d\n", ret);
#if defined(CONFIG_ENABLE_SERVICE_FLOW)
ret = GAPI_SubscribeNotiServiceFlow(api_handle, ind_noti_service_flow);
if (ret != GCT_API_RET_SUCCESS)
cm_eprintf("GAPI_SubscribeNotiFunc error=%d\n", ret);
#endif // CONFIG_ENABLE_SERVICE_FLOW
}