Initial import of GCT GDM WiMAX SDK 3.11.

- Add both SDK and CM source code from GCT.
- Modify SDK and CM to remove host EAP and OMA DM code.
- Add LICENSE and README.chromium file.

BUG=chrome-os-partner:9605
TEST=emerge-klang gdmwimax

Change-Id: I18f2a3219bd0ff7d288396ad98c8eb6c7f9b3713
diff --git a/README.chromium b/README.chromium
index 0997f8f..80d636e 100644
--- a/README.chromium
+++ b/README.chromium
@@ -1,5 +1,5 @@
 URL: http://www.gctsemi.com/
-Version: 3.11 (Imported on 05-10-2012)
+Version: 3.11 (Imported on 05-21-2012)
 License: Copyright (c) 2012, GCT Semiconductor, Inc. All rights reserved.
 License File: LICENSE
 
diff --git a/cm/ChangeLog b/cm/ChangeLog
new file mode 100644
index 0000000..15a6da9
--- /dev/null
+++ b/cm/ChangeLog
@@ -0,0 +1,133 @@
+1.4.7
+	Add eap parameter interface.
+		eap_tls_decoration
+		eap_tls_sessionticket_disable
+
+1.4.6
+	Type of EEPROM bootloader image is added to cmd_rimg command
+	Cm commands is added as follow
+		cm_command_mac_state
+		cm_set_idle_mode_timeout
+		cm_get_phy_mac_basic
+		cm_get_phy_mcs
+		cm_get_phy_cinr_rssi
+	Add command usage for cm_rimg.
+	Cm commands is added for Service Flow and register callback fuction for Service Flow status
+		cm_gsf
+		cm_dsa_test
+		cm_dsc_test
+		cm_dsd_test
+	md_get_phy_cinr_rssi API name chanaged to cmd_get_phy_cinr_rssi
+	BUGFIX:
+		Stack-overflow occurs when mbstowcs is invoked.
+		Invalid uicc on/off parameter in cmd_uicc()
+
+1.4.4 / 1.4.5
+	Servife Flow support. If include 'CONFIG_ENABLE_SERVICE_FLOW=y' in '.config', active.
+	Support auto-connection for partner network.
+	E-EAP is in use, 'log on eap' will be activated when device opened.
+	BUGFIX:
+		DM HCI is corrupted when Calibration tool send DM HCI
+		Missing dev_dix initialization
+
+v.1.4.3
+	Add cm_reap command. Support reading certificate command.
+	Add cm_cimg command. Support controling certificate command. (delete, get size, get cr32)
+	Support OMA-DM DRMD
+	[DELETED, Move to v1.4.4/1.4.5]Support auto-connection for partner network.
+
+v.1.4.2
+	Add IP-renew indication.
+	Add a function to execute a shell.
+	Add a configuration which is the profile index to be selected automatically.
+	Add a couple of configurations which are a value of ip allocation timeout 
+	and the other is a flag to decide to disconnect when ip allocation is failed.
+
+v.1.4.1
+	Add 'cm_uicc [on|off]" command for test.
+	Support auto-connection.
+	DM network interface is enabled automatically if CONFIG_DM_INTERFACE is 
+	enabled.
+	Support auto script that allows a script file to be run automatically when CM 
+	is executed.
+	To execute dhclient, use fork & execl instead of system.
+
+v.1.4
+	Support multiple defining of EAP-TLS and EAP-AKA.
+	Fix a but that after updating FW with FUMO, invalid buffer address is freed.
+	Chagne printf to cm_printf.
+	Change the way setting default log level.
+	Move the code that reads eap-log file in E-EAP into SDK.
+
+v.1.3
+	Change the way to select the network device used to connect to DM tool.
+	Support connecting/disconnecting network with DM interface.
+	Add cm_timer.
+	Support resuming downloading for FOTA.
+	Add the ignoring code for the SIGPIPE signal.
+
+v.1.2
+	Support using DM interface when SDK opens with normal mode.
+
+v.1.1.4
+	Fix a bug that default configuration in cm.conf is not applied.
+	CM gets EAP logs if EAP type is TLS/TTLS only.
+
+v.1.1.3
+	Add CR801 configuration.
+
+v.1.1.2
+	Support Wide-Scan.
+	Support DM Network Interface.
+
+v.1.1.1
+	Change the way getting SDK Log.
+	Support sending CRC at the last packet during downloading FW.
+
+v.1.1.0
+	Support using NULL certificate for embedded EAP.
+	Support downloading EAP parameters. ('cm_weap' command)
+	Support downloading certificate. ('cm_wimg' command)
+	Support getting neighbor list.
+	Support indicating power-mode.
+
+v.1.0.2
+	Fix a bug that checking whether a file was encrypted doesn't work.
+
+v.1.0.1
+	Fix a but that 'cm_exit' command doesn't work.
+
+v.1.0
+	Support setting NULL certificate.
+
+v.0.9
+	Support EAP-AKA.
+	Support getting encrypted xml.
+
+v.0.8
+	Print bootloader/FW version.
+	Print scanning indication.
+	Print RF statistic.
+	Support CM command getting OMA-XML.
+
+v.0.7
+	Fix a bug that CM is not working on Big-Endian machine.
+
+v.0.6
+	Support reading/writing MAC-address.
+	Support downloading oma-xml.
+
+v.0.5
+	Support disconnect-reason notification.
+
+v.0.4
+	Support downloading f/w.
+
+v.0.3
+	Support file read/wirte.
+
+v.0.2
+	Fix a bug related to device index mismatch.
+
+v.0.1
+	First update
diff --git a/cm/Makefile b/cm/Makefile
new file mode 100644
index 0000000..740d607
--- /dev/null
+++ b/cm/Makefile
@@ -0,0 +1,41 @@
+# Configuration
+-include ../.config
+
+CC = gcc
+OBJDUMP = objdump
+
+SDK_LIB = ../sdk/libgdmwimax.a
+SDK_LNK = -lpthread -lm -lrt -lz
+CM = cm
+LIBS = $(SDK_LNK) $(SDK_LIB)
+obj-cm = main.o cm.o cmd.o ind.o profilestring.o exitcb.o sem.o \
+	cm_timer.o cm_msg.o dhclient.o
+
+.EXPORT_ALL_VARIABLES:
+
+CFLAGS += ${GFLAGS}
+CFLAGS += -Wall
+CFLAGS += -g -O0
+
+ifeq ("$(CONFIG_DM_INTERFACE)", "y")
+CFLAGS += -DCONFIG_DM_INTERFACE
+CFLAGS += -DCONFIG_DM_NET_DEVICE="\""$(CONFIG_DM_NET_DEVICE)""\"
+obj-cm += dm_if.o
+endif
+
+ifdef CONFIG_LOG_FILE_BUF_SIZE
+CFLAGS += -DCONFIG_LOG_FILE_BUF_SIZE=$(CONFIG_LOG_FILE_BUF_SIZE)
+endif
+
+ifeq ("$(CONFIG_ENABLE_SERVICE_FLOW)", "y")
+CFLAGS += -DCONFIG_ENABLE_SERVICE_FLOW
+endif
+
+all: $(CM)
+
+$(CM): $(obj-cm) $(SDK_LIB)
+	$(CC) -o $@ $(obj-cm) $(LIBS)
+	$(OBJDUMP) -d $@ > disa
+
+clean:
+	-rm -f $(CM) *.a *.so *.elf *.gdb *.o disa
diff --git a/cm/cm.c b/cm/cm.c
new file mode 100644
index 0000000..a12b518
--- /dev/null
+++ b/cm/cm.c
@@ -0,0 +1,737 @@
+// 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 <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <errno.h>
+#include <zlib.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <pthread.h>
+#include <dirent.h>
+#include <stdarg.h>
+#include <wchar.h>
+#include <linux/version.h>
+#include <signal.h>
+
+#include "cm.h"
+#include "exitcb.h"
+#include "profilestring.h"
+#include "dhclient.h"
+
+extern void reg_indications(APIHAND *api_handle);
+extern void kill_dhclient(int dev_idx);
+extern int setup_device_conf(GDEV_ID *ID, const unsigned char *mac);
+extern void load_device_conf(dev_conf_t *conf, const char *mac);
+extern dev_conf_t default_dev_conf;
+
+int cm_init(int read_only);
+int cm_deinit(void);
+
+APIHAND cm_api_handle;
+char cm_odev_list[MAX_DEV];
+dev_conf_t cm_dev_conf[MAX_DEV];
+int cm_odev_cnt;
+cm_common_conf_t cm_common_conf;
+
+
+int get_first_odev(void)
+{
+	int i;
+
+	if (cm_odev_cnt) {
+		for (i = 0; i < MAX_DEV; i++) {
+			if (cm_odev_list[i])
+				return i;
+		}
+	}
+	return 0;
+}
+
+void add_odev_list(int dev_idx)
+{
+	assert(!cm_odev_list[dev_idx]);
+	cm_odev_list[dev_idx] = 1;
+	cm_odev_cnt++;
+}
+
+
+int del_odev_list(int dev_idx)
+{
+	if (cm_odev_list[dev_idx]) {
+		cm_odev_list[dev_idx] = 0;
+		cm_odev_cnt--;
+		return 1;
+	}
+	return 0;
+}
+
+int cm_get_filesize(const char *file)
+{
+	int fd, len;
+
+	if ((fd = open(file, O_RDONLY)) < 0) {
+		cm_printf("open(%s) fail. %s(%d)\n", file, strerror(errno), errno);
+		return -1;
+	}
+
+	len = lseek(fd, 0, SEEK_END);
+	close(fd);
+	return len;
+}
+
+int cm_read_file(const char *file, char *buf, int buf_size)
+{
+	int fd, len, total = 0;
+
+	if ((fd = open(file, O_RDONLY)) < 0) {
+		cm_printf("open(%s) fail. %s(%d)\n", file, strerror(errno), errno);
+		return -1;
+	}
+	while ((len = read(fd, &buf[total], buf_size-total)) > 0) {
+		total += len;
+		if (buf_size-total == 0)
+			break;
+	}
+
+	if (len < 0)
+		cm_printf("read(%s) fail. %s(%d)\n", file, strerror(errno), errno);
+
+	close(fd);
+	return total;
+}
+
+int cm_write_file(const char *file, char *buf, int buf_size, int flags)
+{
+	int fd, len = 0, total = 0;
+	mode_t mode = 0;
+
+	if (flags & O_CREAT)
+		mode = 0644;
+
+	if ((fd = open(file, flags, mode)) < 0) {
+		cm_printf("open(%s) fail. %s(%d)\n", file, strerror(errno), errno);
+		return -1;
+	}
+
+	if (buf_size) {
+		while ((len = write(fd, &buf[total], buf_size-total)) > 0) {
+			total += len;
+			if (buf_size-total == 0)
+				break;
+		}
+	}
+
+	if (len < 0)
+		cm_printf("write(%s) fail\n", file);
+
+	close(fd);
+	return total;
+}
+
+int cm_cmp_file(const char *file, const char *file2)
+{
+	int fd = -1, fd2 = -1;
+	int ret = -1;
+	int len, len2;
+	char buf[4096], buf2[4096];
+	
+	if ((fd = open(file, O_RDONLY)) < 0) {
+		cm_printf("open(%s) fail. %s(%d)\n", file, strerror(errno), errno);
+		goto out;
+	}
+	if ((fd2 = open(file2, O_RDONLY)) < 0) {
+		cm_printf("open(%s) fail. %s(%d)\n", file2, strerror(errno), errno);
+		goto out;
+	}
+
+	do {
+		if ((len = read(fd, buf, sizeof(buf))) < 0) {
+			cm_printf("read(%d:%s) fail. %s(%d)\n", fd, file, strerror(errno), errno);
+			break;
+		}
+		if ((len2 = read(fd2, buf2, sizeof(buf2))) < 0) {
+			cm_printf("read(%d:%s) fail. %s(%d)\n", fd2, file2, strerror(errno), errno);
+			break;
+		}
+
+		if (len != len2)
+			break;
+		if (len < 0 || len2 < 0)
+			break;
+			
+		if (len == 0 && len2 == 0) {
+			ret = 0;
+			break;
+		}
+
+		if (memcmp(buf, buf2, len))
+			break;
+	} while (1);
+
+out:
+	if (fd > 0)
+		close(fd);
+	if (fd2 > 0)
+		close(fd2);
+	return ret;
+}
+
+int cm_get_dir_entry(const char *dir, int index, char *filepath, int size)
+{
+	DIR *dirp;
+	struct dirent *dp;
+	int idx = 0, ret = -1;
+	char *file;
+
+	dirp = opendir(dir);
+
+	while ((dp = readdir(dirp)) != NULL) {
+		file = dp->d_name;
+		if (!strcmp(file, ".") || !strcmp(file, ".."))
+			continue;
+
+		if (idx++ == index) {
+			strncpy(filepath, file, size);
+			ret = 0;
+			break;
+		}
+	}
+
+	closedir(dirp);
+	return ret;
+}
+
+int cm_load_file_lines(const char *file, int lines, ...)
+{
+	char line[1024];
+	FILE *fp;
+	va_list list;
+	char *p;
+	int i, len;
+
+	if (!(fp = fopen(file, "rt"))) {
+		cm_eprintf("fopen(%s) error\n", file);
+		return -1;
+	}
+
+	va_start(list, lines);
+	for (i = 0; i < lines; i++) {
+		p = va_arg(list, char *);
+		if (p) *p = 0;
+		if (!fgets(line, sizeof(line), fp))
+			break;
+		len = strlen(line);
+		if (len >= 2 && line[len-2] == '\r') line[len-2] = 0;
+		if (len >= 1 && line[len-1] == '\n') line[len-1] = 0;
+		//cm_printf("[%s]\n", line);
+		if (p) strcpy(p, line);
+	}
+	va_end(list);
+
+	fclose(fp);
+	return i;
+}
+
+int cm_store_file_lines(const char *file, int lines, ...)
+{
+	FILE *fp;
+	va_list list;
+	char *p;
+	int i;
+
+	if (!(fp = fopen(file, "wt"))) {
+		cm_eprintf("fopen(%s) error\n", file);
+		return -1;
+	}
+
+	va_start(list, lines);
+	for (i = 0; i < lines; i++) {
+		p = va_arg(list, char *);
+		if (fprintf(fp, "%s\n", p ? p : "") < 0) {
+			cm_eprintf("fprintf(%s) error\n", file);
+			break;
+		}
+		//cm_printf("[%s]\n", p);
+	}
+	va_end(list);
+
+	fclose(fp);
+	return i;
+}
+
+char *cm_get_dev_idx2name(int dev_idx)
+{
+	static char name_buf[MAX_DEV][8];
+	char *name = name_buf[dev_idx];
+
+	sprintf(name, GCT_WM_PREFIX "%d", dev_idx-1);
+	return name;
+}
+
+int cm_get_dhcp_ip(int dev_idx, char *ip)
+{
+#define sizeof_sa_sin_port	2
+#define p_inaddrr(x) (&ifr.x[sizeof_sa_sin_port])
+	struct ifreq ifr;
+	struct in_addr inaddr;
+	int fd = 0;
+	int ret = 0;
+
+	fd = socket(PF_PACKET, SOCK_DGRAM, IPPROTO_IP);
+	if (fd < 0) {
+		cm_eprintf("socket\n");
+		return -1;
+	}
+
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, cm_get_dev_idx2name(dev_idx), IFNAMSIZ);
+	if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
+		//cm_dprintf("ioctl SIOCGIFFLAGS(%d)\n", fd);
+		ret = -1;
+		goto out;
+	}
+	memcpy(&inaddr, p_inaddrr(ifr_addr.sa_data), sizeof(inaddr));
+	if (ip)
+		strcpy(ip, inet_ntoa(inaddr));
+out:
+	if (fd > 0)
+		close(fd);
+	return ret;
+}
+
+static void extract_fw_version(const char *fw_ver, unsigned *app_ver, unsigned *mac_ver)
+{
+	const char *fw_ver_fmt = "FW(%d.%d.%d.%d : %d.%d.%d.%d)";
+	int v[8];
+
+	sscanf(fw_ver, fw_ver_fmt, &v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7]);
+
+	*app_ver = ((char)v[0] << 24) | ((char)v[1] << 16) | ((char)v[2] << 8) | (char)v[3];
+	*mac_ver = ((char)v[4] << 24) | ((char)v[5] << 16) | ((char)v[6] << 8) | (char)v[7];
+}
+
+static void extract_fw_w_version(const wchar_t *fw_ver, unsigned *app_ver, unsigned *mac_ver)
+{
+	char ch_fw_ver[128];
+	
+	wcstombs((char *)ch_fw_ver, fw_ver, wcslen(fw_ver)+1);
+
+	extract_fw_version(ch_fw_ver, app_ver, mac_ver);
+}
+
+static void setup_fw_version(int dev_idx, wchar_t *fw_ver)
+{
+	dev_conf_t *conf = &cm_dev_conf[dev_idx];
+
+	extract_fw_w_version(fw_ver, &conf->fw_app_version, &conf->fw_mac_version);
+
+	#if 0
+	cm_dprintf("fw_app_version=0x%08x\n", conf->fw_app_version);
+	cm_dprintf("fw_mac_version=0x%08x\n", conf->fw_mac_version);
+	#endif
+}
+
+static int send_print_log_on_eap(GDEV_ID_P pID)
+{
+	#define STR_LOG_ON_EAP "log on eap\n"
+	
+	char *buf = STR_LOG_ON_EAP;
+	int len = strlen(STR_LOG_ON_EAP);
+	char hci_buf[HCI_HEADER_SIZE + 32];
+	hci_t *hci = (hci_t *) hci_buf;
+
+	hci->cmd_evt = _H2B(WIMAX_CLI_CMD);
+	hci->length = _H2B(len);
+	memcpy(hci->data, buf, len);
+
+	len += HCI_HEADER_SIZE;
+
+	if (GAPI_WriteHCIPacket(pID, hci_buf, len) != GCT_API_RET_SUCCESS) {
+		cm_printf("Write HCI failure\n");
+		return -1;
+	}
+
+	return 0;
+
+}
+
+int device_open(GDEV_ID_P pID)
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+	WIMAX_API_DEVICE_INFO info;
+	char bl_ver[64];
+
+	if (GAPI_WiMaxDeviceOpen(pID) == GCT_API_RET_SUCCESS) {
+		add_odev_list(pID->deviceIndex);
+		GAPI_GetBootloaderVersion(pID, bl_ver, sizeof(bl_ver));
+		cm_printf("BL version: %s\n", bl_ver);
+
+		if (GAPI_GetDeviceInformation(pID, &info) != GCT_API_RET_SUCCESS)
+			return -1;
+
+		setup_fw_version(pID->deviceIndex, (wchar_t *)info.swVersion.version);
+
+		cm_printf("HW version: %S\n", (wchar_t *)info.hwVersion.version);
+		cm_printf("SW version: %S\n", (wchar_t *)info.swVersion.version);
+		
+		setup_device_conf(pID, info.macAddress);
+
+		if (pconf->eap_log_enable && CM_USE_EEAP && CAP_EEAP_ENABLED(pID->deviceIndex))
+			send_print_log_on_eap(pID);
+
+		if (pconf->api_mode != GCT_WIMAX_API_PRIVILEGE_READ_ONLY) {
+			if (pconf->auto_connect_enable)
+				cm_request_auto_connection(pID->deviceIndex);
+			#if defined(CONFIG_DM_INTERFACE)
+			else
+				cm_profiling_rf_up(pID->deviceIndex);
+			#endif
+		}
+		return 0;
+	}
+	else {
+		cm_printf("open fail device[%d]\n", pID->deviceIndex);
+		return -1;
+	}
+}
+
+
+int device_close(GDEV_ID_P pID)
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+	
+	if (del_odev_list(pID->deviceIndex)) {
+		if (pconf->api_mode != GCT_WIMAX_API_PRIVILEGE_READ_ONLY)
+			dh_stop_dhclient(pID->deviceIndex);
+
+		if (GAPI_WiMaxDeviceClose(pID) == GCT_API_RET_SUCCESS)
+			return 0;
+		else {
+			cm_printf("close fail device[%d]\n", pID->deviceIndex);
+			return -1;
+		}
+	}
+	cm_printf("Not found device[%d]\n", pID->deviceIndex);
+	return -1;
+}
+
+
+int open_dev_list(void)
+{
+	WIMAX_API_HW_DEVICE_ID list[256];
+	UINT32 cnt = 256;
+	GDEV_ID ID;
+	int i;
+
+	ID.apiHandle = cm_api_handle;
+
+	if (GAPI_GetListDevice(cm_api_handle, list, &cnt) == GCT_API_RET_SUCCESS) {
+		for (i = 0; i < cnt; i++) {
+			ID.deviceIndex = list[i].deviceIndex;
+			if (device_open(&ID) < 0)
+				return -1;
+		}
+		return 0;
+	}
+	else
+		return -1;
+}
+
+
+void close_dev_list(void)
+{
+	GDEV_ID ID;
+	int i;
+
+	ID.apiHandle = cm_api_handle;
+
+	for (i = 0; i < sizeof(cm_odev_list)/sizeof(cm_odev_list[0]); i++) {
+		if (cm_odev_list[i]) {
+			ID.deviceIndex = i;
+			device_close(&ID);
+		}
+			
+	}
+}
+
+static void cb_cm_deinit(int signal/*, void *info*/)
+{
+	cm_deinit();
+}
+
+#define KEY_log_path							"log_path"
+#define KEY_log_level							"log_level"
+#define KEY_eap_log_enable						"eap_log_enable"
+#define KEY_embedded_eap_enable					"embedded_eap_enable"
+#define KEY_oma_dm_enable						"oma_dm_enable"
+#define KEY_nonvolatile_dir						"nonvolatile_dir"
+#define KEY_run_script_file						"run_script_file"
+#define KEY_auto_connect_enable					"auto_connect_enable"
+#define KEY_auto_connect_retry_count			"auto_connect_retry_count"
+#define KEY_auto_select_profile_index			"auto_select_profile_index"
+#define KEY_unknown_net_auto_connect_enable		"unknown_net_auto_connect_enable"
+#define KEY_ip_allocation_timeout_sec			"ip_allocation_timeout_sec"
+#define KEY_disconnct_on_ip_failure				"disconnct_on_ip_failure"
+
+static void cm_load_common(cm_common_conf_t *pconf)
+{
+	char *section = "common";
+	char str[256], *p;
+	int len;
+
+	p = pconf->log_path;
+	len = sizeof(pconf->log_path);
+	get_profile_string(section, KEY_log_path, "./sdklog", p, len, CONF_FILE);
+
+	get_profile_string(section, KEY_eap_log_enable, "n", str, sizeof(str), CONF_FILE);
+	if (!strcasecmp(str, "y"))
+		pconf->eap_log_enable = 1;
+	else
+		pconf->eap_log_enable = 0;
+
+	get_profile_string(section, KEY_embedded_eap_enable, "n", str, sizeof(str), CONF_FILE);
+	if (!strcasecmp(str, "y"))
+		pconf->embedded_eap_enable = 1;
+	else
+		pconf->embedded_eap_enable = 0;
+
+	pconf->oma_dm_enable = 0;
+	
+	p = pconf->nonvolatile_dir;
+	len = sizeof(pconf->nonvolatile_dir);
+	get_profile_string(section, KEY_nonvolatile_dir, "./", p, len, CONF_FILE);
+	len = strlen(pconf->nonvolatile_dir);
+	if (pconf->nonvolatile_dir[len-1] == '/' || pconf->nonvolatile_dir[len-1] == '\\')
+		pconf->nonvolatile_dir[len-1] = 0;
+	
+	p = pconf->run_script_file;
+	len = sizeof(pconf->run_script_file);
+	get_profile_string(section, KEY_run_script_file, "", p, len, CONF_FILE);
+	len = strlen(pconf->run_script_file);
+	if (pconf->run_script_file[len-1] == '/' || pconf->run_script_file[len-1] == '\\')
+		pconf->run_script_file[len-1] = 0;
+	
+	get_profile_string(section, KEY_log_level, "1", str, sizeof(str), CONF_FILE);
+	pconf->log_level = strtoul(str, NULL, 0);
+	
+	get_profile_string(section, KEY_auto_connect_enable, "n", str, sizeof(str), CONF_FILE);
+	if (!strcasecmp(str, "y"))
+		pconf->auto_connect_enable = 1;
+	else
+		pconf->auto_connect_enable = 0;
+	
+	get_profile_string(section, KEY_auto_connect_retry_count, "0", str, sizeof(str), CONF_FILE);
+	pconf->auto_connect_retry_count = strtoul(str, NULL, 0);
+	
+	get_profile_string(section, KEY_auto_select_profile_index, "0", str, sizeof(str), CONF_FILE);
+	pconf->auto_select_profile_index = strtoul(str, NULL, 0);
+	
+	get_profile_string(section, KEY_unknown_net_auto_connect_enable, "n", str, sizeof(str), CONF_FILE);
+	if (!strcasecmp(str, "y"))
+		pconf->unknown_net_auto_connect_enable = 1;
+	else
+		pconf->unknown_net_auto_connect_enable = 0;
+
+	get_profile_string(section, KEY_ip_allocation_timeout_sec, "30", str, sizeof(str), CONF_FILE);
+	pconf->ip_allocation_timeout_sec = strtoul(str, NULL, 0);
+
+	get_profile_string(section, KEY_disconnct_on_ip_failure, "n", str, sizeof(str), CONF_FILE);
+	if (!strcasecmp(str, "y"))
+		pconf->disconnct_on_ip_failure = 1;
+	else
+		pconf->disconnct_on_ip_failure = 0;
+}
+
+static void *cm_auto_connect_thread(void *data)
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+	cm_msg_cb_t *msg_cb;
+	int dev_idx;
+
+	msg_cb = &pconf->auto_conn_msg;
+	cm_msg_init(msg_cb);
+
+	cm_printf("Auto connection is ready!\n");
+	while (1) {
+		dev_idx = DEFAULT_DEVICE;
+		if (cm_msg_recv(msg_cb, &dev_idx, NULL) < 0) {
+			cm_eprintf("auto connector cm_msg_recv error\n");
+			break;
+		}
+		if (pconf->auto_connect_enable)
+			cm_auto_connect(dev_idx);
+	}
+	
+	cm_msg_deinit(msg_cb);
+	pconf->auto_conn_thr = (pthread_t) NULL;
+	cm_printf("Auto connection finished!\n");
+	return NULL;
+}
+
+void cm_request_auto_connection(int dev_idx)
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+	dev_conf_t *conf = &cm_dev_conf[dev_idx];
+
+	if (pconf->api_mode == GCT_WIMAX_API_PRIVILEGE_READ_ONLY)
+		return;
+
+	conf->auto_conn_retry_cnt = 0;
+	cm_printf("Request auto connection device(%d)\n", dev_idx);
+	if (dev_idx > 0)
+		cm_msg_send(&pconf->auto_conn_msg, dev_idx, NULL);
+}
+
+void cm_retry_auto_connection(int dev_idx)
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+	dev_conf_t *conf = &cm_dev_conf[dev_idx];
+
+	if (pconf->api_mode == GCT_WIMAX_API_PRIVILEGE_READ_ONLY)
+		return;
+
+	if (++conf->auto_conn_retry_cnt == pconf->auto_connect_retry_count) {
+		cm_printf("Too many retries(%u), auto_connect_retry_count in cm.conf is %u\n",
+			conf->auto_conn_retry_cnt, pconf->auto_connect_retry_count);
+	}
+	else if (conf->auto_conn_retry_cnt < pconf->auto_connect_retry_count) {
+		cm_printf("Re-request(%u/%u) auto connection device(%d)\n",
+			conf->auto_conn_retry_cnt, pconf->auto_connect_retry_count, dev_idx);
+		if (dev_idx > 0)
+			cm_msg_send(&pconf->auto_conn_msg, dev_idx, NULL);
+	}
+}
+
+static void cm_create_auto_connector(void)
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+
+	if (!pconf->auto_connect_enable)
+		cm_printf("Auto connection flag was disabled!\n");
+	if (pconf->auto_conn_thr) {
+		cm_eprintf("Auto connector has been started already!\n");
+		return;
+	}
+	pthread_create(&pconf->auto_conn_thr, NULL, cm_auto_connect_thread, NULL);
+}
+
+static void cm_delete_auto_connector(void)
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+	pthread_t thread;
+
+	if ((thread = pconf->auto_conn_thr)) {
+		pconf->auto_conn_thr = (pthread_t) NULL;
+		pthread_cancel(thread);
+		pthread_join(thread, NULL);
+		cm_printf("Auto connector deleted!\n");
+	}
+	pconf->auto_connect_enable = 0;
+}
+
+int cm_init(int read_only)
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+	GCT_WIMAX_SDK_MODE sdk_mode = 0;
+	GCT_WIMAX_API_PARAM param;
+	GCT_API_RET ret;
+
+	if (read_only) {
+		pconf->api_mode = GCT_WIMAX_API_PRIVILEGE_READ_ONLY;
+		pconf->eap_log_enable = 0;
+	}
+	else
+		pconf->api_mode = GCT_WIMAX_API_OPEN_MODE_NORMAL;
+
+	cm_timer_module_init();
+
+	cm_load_common(pconf);
+
+	if (!read_only) {
+		cm_create_auto_connector();
+		dh_create_dhclient();
+	}
+
+	load_device_conf(&default_dev_conf, NULL);
+
+	#if defined(CONFIG_DM_INTERFACE)
+	if (!read_only) {
+		if (dmif_init() < 0)
+			return -1;
+		pconf->dm_interface_enable = 1;
+	}
+	#endif
+
+	if (mkdir(pconf->log_path, 0644) < 0 && errno != EEXIST) {
+		cm_eprintf("Access directory(%s) failed %s(%d)\n",
+			pconf->log_path, strerror(errno), errno);
+		return -1;
+	}
+
+	if (pconf->embedded_eap_enable)
+		sdk_mode |= GCT_WIMAX_SDK_EMBEDDED_EAP_ENABLED;
+	if (pconf->oma_dm_enable)
+		sdk_mode |= GCT_WIMAX_SDK_OMA_DM_ENABLED;
+
+	strcpy(param.nonvolatile_dir, pconf->nonvolatile_dir);
+	strcpy(param.log_path, pconf->log_path);
+	param.log_level = pconf->log_level;
+	ret = GAPI_Initialize(sdk_mode, &param);
+	if (ret != GCT_API_RET_SUCCESS) {
+		cm_eprintf("GAPI_Initialize failed(%d)\n", ret);
+		return -1;
+	}
+
+	register_exit_cb(cb_cm_deinit);
+
+	ret = GAPI_WiMaxAPIOpen(&cm_api_handle, pconf->api_mode);
+	if (ret != GCT_API_RET_SUCCESS) {
+		cm_eprintf("GAPI_WiMaxAPIOpen failed(%d)\n", ret);
+		return -1;
+	}
+
+	reg_indications(cm_api_handle);
+
+	if (open_dev_list() < 0)
+		return -1;
+	return 0;
+}
+
+int cm_deinit(void)
+{
+	APIHAND apihand = cm_api_handle;
+	GCT_API_RET ret;
+
+	cm_delete_auto_connector();
+
+	unregister_exit_cb(cb_cm_deinit);
+
+	close_dev_list();
+
+	dh_delete_dhclient();
+
+	#if (CONFIG_LOG_FILE_BUF_SIZE > 0)
+	GAPI_SetDebugLevel(apihand, GAPI_LOG_FLUSH_LEVEL, NULL);
+	#endif
+
+	cm_api_handle = NULL;
+	GAPI_WiMaxAPIClose(apihand);
+
+	ret = GAPI_DeInitialize();
+	if (ret != GCT_API_RET_SUCCESS)
+		return -1;
+
+	cm_timer_module_deinit();
+	return 0;
+}
diff --git a/cm/cm.conf b/cm/cm.conf
new file mode 100644
index 0000000..cf4139c
--- /dev/null
+++ b/cm/cm.conf
@@ -0,0 +1,40 @@
+[common]
+log_path=/var/log/gct
+log_level=1
+eap_log_enable=n
+embedded_eap_enable=y
+oma_dm_enable=n
+nonvolatile_dir=/var/cache/gct
+run_script_file=
+auto_connect_enable=y
+auto_connect_retry_count=10
+auto_select_profile_index=0
+unknown_net_auto_connect_enable=n
+ip_allocation_timeout_sec=30
+disconnct_on_ip_failure=y
+
+
+[device-default]
+auth_pkm_enable=y
+eap_type=TLS
+#eap_type=TTLS_MSCHAPV2
+#eap_type=AKA
+eap_tls_use_nvram_info=y
+eap_tls_userid=socswmschap
+eap_tls_userpasswd=whatever
+eap_tls_anonyid=ttls
+eap_tls_pri_passwd=whatever
+eap_tls_fragsize=1300
+eap_tls_delimiter_enable=n
+eap_tls_dev_cert_null=n
+eap_tls_ca_cert_null=n
+eap_tls_use_nvram_cert=y
+eap_tls_wm_serv_root=
+eap_tls_serv_root_ca1=
+eap_tls_serv_root_ca2=
+eap_tls_serv_root_ca3=
+eap_tls_wm_dev_root=
+eap_tls_dev_root_ca1=
+eap_tls_dev_sub_ca=
+eap_tls_dev_cert=
+eap_tls_dev_cert_key=
diff --git a/cm/cm.h b/cm/cm.h
new file mode 100644
index 0000000..154df06
--- /dev/null
+++ b/cm/cm.h
@@ -0,0 +1,298 @@
+// 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.
+
+#if !defined(CM_H_20081007)
+#define CM_H_20081007
+
+#include <netinet/in.h>
+#include "../sdk/gctapi.h"
+#include "cm_timer.h"
+#include "cm_msg.h"
+#define MAX_DEV				8
+#define MAX_PROFILE_LIST	8
+#define MAX_NETWORK_LIST	16
+
+#define GCT_WM_PREFIX		"wm"
+
+#define DEFAULT_DEVICE		(int)(1)
+
+#define HCI_MAX_PACKET				2048
+#define HCI_HEADER_SIZE				4
+
+#define WIMAX_DISCONN_IND			0x8115
+#define WIMAX_IP_RENEW_IND			0x811a
+
+#define WIMAX_DM_CMD				0x030a
+#define WIMAX_DM_RSP				0x830b
+
+#define WIMAX_CLI_CMD				0x030c
+#define WIMAX_CLI_RSP				0x830d
+
+#define END_OF_BLOCK	(-1)
+#define END_OF_IMAGE	(-2)
+#define SEQUENCE_READ	(-1)
+#define DL_DATA_CHUCK		1024
+
+#define ENC_HEAD_SIZE	4
+
+#define WIMAX_DL_IMAGE				0x0310
+#define WIMAX_DL_IMAGE_STATUS		0x8311
+#define WIMAX_UL_IMAGE				0x0312
+#define WIMAX_UL_IMAGE_RESULT		0x8313
+#define WIMAX_UL_IMAGE_STATUS		0x0314
+#define WIMAX_IMAGE_CMD				0x0316
+	#define ICMD_INVALIDATE			0
+	#define ICMD_GET_SIZE			1
+	#define ICMD_GET_CRC32			2
+#define WIMAX_IMAGE_CMD_STATUS		0x8317
+
+#define WIMAX_UICC_STATUS_IND		0x8318
+#define WIMAX_UICC_EAP_IND			0x8319
+#define WIMAX_UICC_CMD				0x031A
+	#define UICC_CMD_PIN_ENABLE		0x00
+	#define UICC_CMD_PIN_DISABLE	0x01
+	#define UICC_CMD_PIN_CHANGE		0x02
+	#define UICC_CMD_PIN_VERIFY		0x03
+	#define UICC_CMD_PUK_INPUT		0x04
+	#define UICC_CMD_UICC_STATUS	0x05
+	#define UICC_CMD_SUBSCRIBERID	0x06
+	#define UICC_CMD_ICCID			0x07
+	#define UICC_CMD_POWER_DOWN		0x08
+	#define UICC_CMD_POWER_UP		0x09
+#define WIMAX_UICC_CMD_RESULT		0x831B
+	#define UICC_CMD_RESULT_SUCCESS	0x00
+	#define UICC_CMD_RESULT_FAIL	0x01
+
+#define EOF_OFFSET					-1
+#define WIMAX_READ_FILE				0x0350
+#define WIMAX_WRITE_FILE			0x0351
+#define WIMAX_DELETE_FILE			0x0352
+#define WIMAX_FILE_RESULT			0x8354
+
+#define WIMAX_MANAGER_MSG			0x8333
+
+#define WIMAX_EAP_STR_LEN			256
+#define MAX_EAP_BUF_SIZE			2048
+
+/* Download image type */
+#define DLIMG_KERNEL		0
+#define DLIMG_FS			1
+#define DLIMG_CFG			2
+#define DLIMG_EAP_PARM		6
+#define DLIMG_BL_EEPROM		7
+#define DLIMG_BL_FLASH		8
+#define DLIMG_OMA_XML		0x100
+#define DLIMG_DEV_CERT		0x101
+#define DLIMG_CERT1_U		0x102
+#define DLIMG_CERT1_L		0x103
+#define DLIMG_CERT2_U		0x104
+#define DLIMG_EAP_PARAM		0x105
+#define DLIMG_CERT_BIG		0x106
+
+#define WIMAX_PRINT_PAD				8
+
+typedef struct hci {
+	unsigned short 	cmd_evt;
+	unsigned short 	length;
+	unsigned char 	data[0];	
+} __attribute__((packed)) hci_t;
+
+typedef struct hci_image_payload {
+	unsigned short	type;
+	unsigned int	offset;
+	char 			data[0];
+} __attribute__((packed)) hci_image_payload_t;
+
+typedef struct hci_image_response {
+	unsigned short 	type;
+	unsigned int	offset;
+	int			result;
+} __attribute__((packed)) hci_image_response_t;
+
+typedef struct hci_image_cmd {
+	unsigned short	cmd;
+	unsigned short	type;
+} __attribute__((packed)) hci_image_cmd_t;
+
+typedef struct hci_image_cmd_result {
+	unsigned short	cmd;
+	unsigned short	type;
+	unsigned		status;
+	unsigned char	data[0];
+} __attribute__((packed)) hci_image_cmd_result_t;
+
+typedef struct hci_file_write {
+	unsigned int	offset;
+	unsigned short	path_len;	/*Include null char*/
+	char 			path[0];
+	char 			data[0];
+} __attribute__((packed)) hci_file_write_t;
+#define hci_file_data(p)	(p->path+p->path_len)
+
+typedef struct hci_file_delete {
+	char 			path[0];
+	char 			data[0];
+} __attribute__((packed)) hci_file_delete_t;
+
+typedef struct hci_file_read {
+	unsigned int	offset;
+	char 			path[0];
+	char 			data[0];
+} __attribute__((packed)) hci_file_read_t;
+
+typedef struct hci_file_response {
+	int			result;
+	unsigned short	path_len;
+	char 			path[0];
+	char 			data[0];
+} __attribute__((packed)) hci_file_response_t;
+#define file_response_data(r)	\
+	(((hci_file_response_t*)(r))->path+_B2H(((hci_file_response_t*)(r))->path_len))
+
+#define _B2H(x)			ntohs(x)
+#define _H2B(x)			htons(x)
+#define _DB2H(x)		ntohl(x)
+#define _DH2B(x)		htonl(x)
+
+#define _U82U16(b)	((((u16)((u8*)b)[0])<<8)|((u16)((u8*)b)[1]))
+#define _U82U24(b)	((((u32)((u8*)b)[0])<<16)|(((u32)((u8*)b)[1])<<8)|((u32)((u8*)b)[2]))
+#define _U82U32(b)	(((u32)_U82U16(b)<<16)|(u32)_U82U16((u8*)(b)+2))
+#define _U162U8(b,v)	((((u8*)b)[0])=((u16)(v)>>8),(((u8*)b)[1])=(u8)((u16)(v)))
+#define _U242U8(b,v)	((((u8*)b)[0])=(u8)((u32)(v)>>16),(((u8*)b)[1])=(u8)((u32)(v)>>8),\
+						(((u8*)b)[2])=(u8)((u32)(v)))
+#define _U322U8(b,v)	(_U162U8((u8*)(b)+2, v), _U162U8(b, (u32)v>>16))
+
+#define _set_msb(x32, x8)	(x32 = ((u32)x32 & 0x00ffffff) | ((u32)x8<<24))
+#define _get_msb(x32)		((u8)((u32)x32>>24))
+
+#ifndef offsetof
+#define	offsetof(type, field)	((int)(&((type*)0)->field))
+#endif
+
+#define _numof_array(arr)	(sizeof(arr)/sizeof(arr[0]))
+
+#define FW_UPDATE_REPORT_TRY_CNT		5
+#define DRMD_REPORT_TRY_CNT				FW_UPDATE_REPORT_TRY_CNT
+
+/*Auto connection*/
+#define NETWORK_LIST_TIMEOUT_SEC		(0x7fffffff)
+
+typedef struct dev_conf_s {
+	char mac_str[32];
+	char type_str[256];
+	CAPABILITY_BIT cap;
+	GCT_API_EAP_PARAM eapp;
+	GCT_API_ODM_PARAM odmp;
+
+	WIMAX_API_DEVICE_STATUS wimax_status;
+	u16 nsp_name16_before[MAX_SIZE_OF_NSP_NAME];
+	u16 nsp_name16_current[MAX_SIZE_OF_NSP_NAME];
+
+	pid_t			dhclient_pid;
+	cm_timer_obj_t	ip_acq_timer;
+	int				ip_acq_timed;
+
+	unsigned		auto_conn_retry_cnt;
+
+	unsigned fw_app_version;
+	unsigned fw_mac_version;
+
+} dev_conf_t;
+
+typedef struct cm_common_conf_s {
+	char		log_path[256];
+	int			log_level;
+	int			eap_log_enable;
+	int			embedded_eap_enable;
+	int			oma_dm_enable;
+	char		nonvolatile_dir[128];
+	char		run_script_file[128];
+	int			auto_connect_enable;
+	unsigned	auto_connect_retry_count;
+	int			auto_select_profile_index;
+	int			unknown_net_auto_connect_enable;
+	int			ip_allocation_timeout_sec;
+	int			disconnct_on_ip_failure;
+
+	pthread_t		auto_conn_thr;
+	cm_msg_cb_t		auto_conn_msg;
+
+	pthread_t		dhclient_thr;
+	cm_msg_cb_t		dhclient_msg;
+
+	GCT_WIMAX_API_OPEN_MODE api_mode;
+	#if defined(CONFIG_DM_INTERFACE)
+	int		dm_interface_enable;
+	int		dm_interface_cfd;	/*socket fd*/
+	#endif
+
+} cm_common_conf_t;
+
+#define CM_USE_EEAP	(cm_common_conf.embedded_eap_enable)
+#define CM_USE_ODM	(cm_common_conf.oma_dm_enable)
+
+#define CAP_ENC_XML_ENABLED(dev_idx)		(cm_dev_conf[dev_idx].cap & CAPABILITY_ENC_XML)
+#define CAP_EEAP_TLS_ENABLED(dev_idx)		(cm_dev_conf[dev_idx].cap & CAPABILITY_E_EAP_TLS)
+#define CAP_ODM_ENABLED(dev_idx)			(cm_dev_conf[dev_idx].cap & CAPABILITY_ODM)
+#define CAP_EEAP_AKA_ENABLED(dev_idx)		(cm_dev_conf[dev_idx].cap & CAPABILITY_E_EAP_AKA)
+#define CAP_CAPLINFO_ENABLED(dev_idx)		(cm_dev_conf[dev_idx].cap & CAPABILITY_CAPL_INFO)
+#define CAP_EEAP_ENABLED(dev_idx)			(CAP_EEAP_TLS_ENABLED(dev_idx) || CAP_EEAP_AKA_ENABLED(dev_idx))
+
+extern dev_conf_t cm_dev_conf[];
+extern cm_common_conf_t cm_common_conf;
+extern APIHAND cm_api_handle;
+
+#define CONF_FILE						"./cm.conf"
+
+#define CM_LOG_FLAG						(LOG_FLAG_NO_STDOUT_IN_LOGFILE)
+#if 1
+#define cm_print_log(api, flag, fmt, args ...)	do {\
+		if (api)\
+			GAPI_PrintLog(api, flag, "CM", fmt, ## args);\
+		else {\
+			printf(fmt, ## args);\
+			fflush(stdout);\
+		}\
+	} while (0)
+#else
+#define cm_print_log(api, fmt, args ...)	do {printf(fmt, ## args);fflush(stdout);} while (0)
+#endif
+
+#define cm_dprintf(fmt, args ...)	do {\
+		if (cm_common_conf.log_level > 1)\
+			cm_print_log(cm_api_handle, 0, "DBG " fmt, ## args);\
+	} while (0)
+
+#define cm_printf(fmt, args ...)		cm_print_log(cm_api_handle, 0, fmt, ## args)
+#define cm_flag_printf(fmt, args ...)	cm_print_log(cm_api_handle, \
+											CM_LOG_FLAG, fmt, ## args)
+#define cm_eprintf(fmt, args ...)		cm_print_log(cm_api_handle, 0, \
+											"ERR(%s) " fmt, __FUNCTION__, ## args)
+
+#if defined(CONFIG_DM_INTERFACE)
+int dmif_init(void);
+int dmif_deinit(void);
+#endif
+
+char *cm_get_dev_idx2name(int dev_idx);
+int cm_get_dhcp_ip(int dev_idx, char *ip);
+int cm_get_filesize(const char *file);
+int cm_read_file(const char *file, char *buf, int buf_size);
+int cm_write_file(const char *file, char *buf, int buf_size, int flags);
+#define cm_creat_file(file, buf, buf_size)	\
+		cm_write_file(file, buf, buf_size, O_CREAT|O_WRONLY|O_TRUNC)
+#define cm_append_file(file, buf, buf_size)	\
+		cm_write_file(file, buf, buf_size, O_APPEND)
+int cm_cmp_file(const char *file1, const char *file2);
+int cm_get_dir_entry(const char *dir, int index, char *filepath, int size);
+int cm_load_file_lines(const char *file, int lines, ...);
+int cm_store_file_lines(const char *file, int lines, ...);
+int cm_profiling_rf_up(int dev_idx);
+int cm_auto_connect(int dev_idx);
+int cm_disconnect_net(int dev_idx);
+void cm_enable_auto_connet(int enable, int dev_idx);
+void cm_request_auto_connection(int dev_idx);
+void cm_retry_auto_connection(int dev_idx);
+
+#endif
diff --git a/cm/cm_msg.c b/cm/cm_msg.c
new file mode 100644
index 0000000..e1c023e
--- /dev/null
+++ b/cm/cm_msg.c
@@ -0,0 +1,131 @@
+// 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 <stdlib.h>
+#include <assert.h>
+#include "cm_msg.h"
+
+#define msg_malloc(s)	malloc(s)
+#define msg_free(b)		free(b)
+
+#define MAX_MSG_POOL		10
+
+void cm_msg_init(cm_msg_cb_t *msg_cb)
+{
+	msg_cb->mc_msg_pool = NULL;
+	msg_cb->mc_head = NULL;
+	msg_cb->mc_tail = NULL;
+	msg_cb->mc_pool_cnt = 0;
+
+	pthread_mutex_init(&msg_cb->mc_lock, NULL);
+	pthread_cond_init(&msg_cb->mc_cond, NULL);
+}
+
+void cm_msg_deinit(cm_msg_cb_t *msg_cb)
+{
+	int free_cnt = 0;
+	cm_msg_t *msg;
+
+	pthread_mutex_lock(&msg_cb->mc_lock);
+	while (msg_cb->mc_msg_pool) {
+		msg = msg_cb->mc_msg_pool;
+		msg_cb->mc_msg_pool = msg_cb->mc_msg_pool->ms_next;
+		msg_free(msg);
+		free_cnt++;
+	}
+	msg_cb->mc_pool_cnt = 0;
+	pthread_mutex_unlock(&msg_cb->mc_lock);
+
+	pthread_mutex_destroy(&msg_cb->mc_lock);
+	pthread_cond_destroy(&msg_cb->mc_cond);
+	assert(free_cnt <= MAX_MSG_POOL);
+}
+
+static void put_msg_pool(cm_msg_cb_t *msg_cb, cm_msg_t *msg)
+{
+	if (!msg_cb->mc_msg_pool) {
+		msg->ms_next = NULL;
+		msg_cb->mc_msg_pool = msg;
+		assert(msg_cb->mc_pool_cnt == 0);
+	}
+	else {
+		msg->ms_next = msg_cb->mc_msg_pool;
+		msg_cb->mc_msg_pool = msg;
+		assert(msg_cb->mc_pool_cnt > 0);
+	}
+	msg_cb->mc_pool_cnt++;
+}
+
+static cm_msg_t *get_msg_pool(cm_msg_cb_t *msg_cb)
+{
+	cm_msg_t *msg;
+
+	msg = msg_cb->mc_msg_pool;
+	msg_cb->mc_msg_pool = msg->ms_next;
+	msg_cb->mc_pool_cnt--;
+	assert(msg_cb->mc_pool_cnt >= 0);
+
+	return msg;
+}
+
+void cm_msg_send(cm_msg_cb_t *msg_cb, int prim, void *data)
+{
+	cm_msg_t *msg;
+
+	pthread_mutex_lock(&msg_cb->mc_lock);
+	if (!msg_cb->mc_msg_pool) {
+		pthread_mutex_unlock(&msg_cb->mc_lock);
+		msg = (cm_msg_t *) msg_malloc(sizeof(cm_msg_t));
+		assert(msg);
+		pthread_mutex_lock(&msg_cb->mc_lock);
+	}
+	else
+		msg = get_msg_pool(msg_cb);
+
+	msg->ms_prim = prim;
+	msg->ms_data = data;
+	msg->ms_next = NULL;
+
+	if (!msg_cb->mc_head)
+		msg_cb->mc_head = msg_cb->mc_tail = msg;
+	else {
+		msg_cb->mc_tail->ms_next = msg;
+		msg_cb->mc_tail = msg;
+	}
+	pthread_cond_signal(&msg_cb->mc_cond);
+	pthread_mutex_unlock(&msg_cb->mc_lock);
+}
+
+int cm_msg_recv(cm_msg_cb_t *msg_cb, int *prim, void **data)
+{
+	cm_msg_t *msg;
+	int ret = 0;
+
+	pthread_mutex_lock(&msg_cb->mc_lock);
+	if (!msg_cb->mc_head) {
+		ret = pthread_cond_wait(&msg_cb->mc_cond, &msg_cb->mc_lock);
+		assert(msg_cb->mc_head);
+	}
+
+	msg = msg_cb->mc_head;
+	msg_cb->mc_head = msg_cb->mc_head->ms_next;
+
+	if (prim)
+		*prim = msg->ms_prim;
+	if (data)
+		*data = msg->ms_data;
+
+	if (msg_cb->mc_pool_cnt < MAX_MSG_POOL) {
+		put_msg_pool(msg_cb, msg);
+		pthread_mutex_unlock(&msg_cb->mc_lock);
+	}
+	else {
+		pthread_mutex_unlock(&msg_cb->mc_lock);
+		msg_free(msg);
+	}
+
+	return ret;
+}
+
diff --git a/cm/cm_msg.h b/cm/cm_msg.h
new file mode 100644
index 0000000..fcc88da
--- /dev/null
+++ b/cm/cm_msg.h
@@ -0,0 +1,34 @@
+// 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.
+
+#if !defined(CM_MSG_H_20100407)
+#define CM_MSG_H_20100407
+#include <pthread.h>
+
+typedef struct cm_msg_s {
+	struct cm_msg_s	*ms_next;
+	int				ms_prim;
+	void			*ms_data;
+
+} cm_msg_t;
+
+typedef struct cm_msg_cb_s {
+	struct cm_msg_s	*mc_msg_pool;
+	int				mc_pool_cnt;
+
+	struct cm_msg_s	*mc_head, 
+					*mc_tail;
+
+	pthread_mutex_t	mc_lock;
+	pthread_cond_t	mc_cond;
+
+} cm_msg_cb_t;
+
+void cm_msg_init(cm_msg_cb_t *msg_cb);
+void cm_msg_deinit(cm_msg_cb_t *msg_cb);
+void cm_msg_send(cm_msg_cb_t *msg_cb, int prim, void *data);
+int cm_msg_recv(cm_msg_cb_t *msg_cb, int *prim, void **data);
+
+#endif
+
diff --git a/cm/cm_timer.c b/cm/cm_timer.c
new file mode 100644
index 0000000..14ec923
--- /dev/null
+++ b/cm/cm_timer.c
@@ -0,0 +1,447 @@
+// 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 <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "cm_timer.h"
+
+#if 0
+#include "log.h"
+#define timer_func_in(fmt, args...)			xfunc_in(fmt, ## args)
+#define timer_func_out(fmt, args...)		xfunc_out(fmt, ## args)
+#define timer_iprintf(fmt, args...)			xprintf(SDK_INFO, fmt, ## args)
+#define timer_dprintf(fmt, args...)			xprintf(SDK_DBG, fmt, ## args)
+#define timer_eprintf(fmt, args...)			xprintf(SDK_ERR, fmt, ## args)
+#define timer_std_eprintf(fmt, args...)		xprintf(SDK_STD_ERR, fmt, ## args)
+#else
+#define timer_func_in(fmt, args...)
+#define timer_func_out(fmt, args...)
+#define timer_iprintf(fmt, args...)
+#define timer_dprintf(fmt, args...)
+#define timer_eprintf(fmt, args...)			fprintf(stderr, "%s " fmt, __FUNCTION__, ## args)
+#define timer_std_eprintf(fmt, args...)		fprintf(stderr, "%s err=%s(%d):" fmt,\
+											__FUNCTION__, strerror(errno), errno, ## args)
+#endif
+
+#define CREATED_MASK		0x54494D45UL
+
+#if defined(CM_PTHREAD_TIMER)
+//#define TIMER_ASSERT
+
+typedef struct pthread_timer_s {
+	unsigned		tt_inited;
+	pthread_t 		tt_thread;
+	pthread_mutex_t tt_lock;
+	pthread_cond_t 	tt_cond;
+
+	struct list_head	tt_head;
+	cm_timer_obj_t		*tt_active;
+	
+} pthread_timer_t;
+
+static pthread_timer_t pthread_timer;
+
+static struct timespec *get_timespec_ms(struct timespec *ts, int timeout_ms)
+{
+	#define nsec_per_sec	(1000*1000*1000)
+	#define ps_timeval2timespec(tv,ts)	\
+		((ts)->tv_sec = (tv)->tv_sec, (ts)->tv_nsec = (tv)->tv_usec * 1000)
+	struct timeval tv;
+	int sec, nsec;
+
+	sec = timeout_ms/1000;
+	nsec = (timeout_ms%1000) * 1000/*usec*/ * 1000/*nsec*/;
+
+	gettimeofday(&tv, NULL);
+	ps_timeval2timespec(&tv, ts);
+	ts->tv_sec += sec;
+	ts->tv_nsec += nsec;
+
+	if (ts->tv_nsec >= nsec_per_sec) {
+		ts->tv_sec++;
+		ts->tv_nsec -= nsec_per_sec;
+	}
+	return ts;
+}
+
+static struct timespec *cmp_earlier_timespec(struct timespec *ts1, struct timespec *ts2)
+{
+	if (ts1->tv_sec == ts2->tv_sec) {
+		if (ts1->tv_nsec < ts2->tv_nsec)
+			return ts1;
+	}
+	else if (ts1->tv_sec < ts2->tv_sec)
+		return ts1;
+	return ts2;
+}
+
+#if defined(TIMER_ASSERT)
+static void time_assert(struct timespec *ts)
+{
+	struct timespec curr_ts;
+
+	get_timespec_ms(&curr_ts, 0);
+
+	assert(cmp_earlier_timespec(&curr_ts, ts) == ts);
+}
+#endif
+
+static void *timer_thread(void *thr_data)
+{
+	pthread_timer_t *ptt = &pthread_timer;
+	struct list_head *head = &ptt->tt_head;
+	cm_timer_obj_t *to;
+	void *data;
+	void (*callback)(void *data);
+	int ret;
+
+	timer_func_in();
+
+	while (1) {
+		pthread_mutex_lock(&ptt->tt_lock);
+
+		/*
+		cm_start_timer is called, cond-lock is released,
+		but at that time,
+		if cm_stop_timer is called before wake up cond-wait, the list becomes empty.
+		Thus, we use while loop instead of if.
+		*/
+		while (list_empty(head))
+			ret = pthread_cond_wait(&ptt->tt_cond, &ptt->tt_lock);
+
+		to = list_entry(head->next, cm_timer_obj_t, to_list);
+		list_del_init(&to->to_list);
+
+		ptt->tt_active = to;
+		ret = pthread_cond_timedwait(&ptt->tt_cond, &ptt->tt_lock, &to->to_ts);
+		ptt->tt_active = NULL;
+		if (ret == ETIMEDOUT && to->to_active) {
+			#if defined(TIMER_ASSERT)
+			time_assert(&to->to_ts);
+			#endif
+			callback = to->to_callback;
+			data = to->to_data;
+			pthread_mutex_lock(&to->to_lock);
+		}
+		else
+			callback = NULL;
+		pthread_mutex_unlock(&ptt->tt_lock);
+
+		if (callback) {
+			timer_dprintf("+timer callback\n");
+			callback(data);
+			timer_dprintf("-timer callback\n");
+			pthread_mutex_unlock(&to->to_lock);
+		}
+	}
+
+	timer_func_out();
+	return NULL;
+}
+
+int cm_init_timer(cm_timer_obj_t *timer, void (*callback)(void *), void *data)
+{
+	pthread_timer_t *ptt = &pthread_timer;
+
+	if (!ptt->tt_inited) {
+		timer_eprintf("Timer module hasn't been initialized!!\n");
+		return -1;
+	}
+
+	timer_func_in("timer=%p, callback=%p, data=%p", timer, callback, data);
+
+	if (!timer || !callback || !data) {
+		timer_eprintf("Invalid parameter\n");
+		return -1;
+	}
+
+	pthread_mutex_init(&timer->to_lock, NULL);
+	INIT_LIST_HEAD(&timer->to_list);
+	timer->to_callback = callback;
+	timer->to_data = data;
+	timer->to_active = 0;
+	timer->to_created = CREATED_MASK;
+
+	timer_func_out();
+	return 0;
+}
+
+int cm_start_timer(cm_timer_obj_t *timer, int expire_milisec)
+{
+	pthread_timer_t *ptt = &pthread_timer;
+	struct list_head *head = &ptt->tt_head;
+	cm_timer_obj_t *pos;
+	struct timespec ts;
+	int ret = 0, inserted = 0;
+
+	if (!ptt->tt_inited) {
+		timer_eprintf("Timer module hasn't been initialized!!\n");
+		return -1;
+	}
+
+	timer_func_in("timer=%p, expire_milisec=%d", timer, expire_milisec);
+
+	get_timespec_ms(&ts, expire_milisec);
+
+	pthread_mutex_lock(&ptt->tt_lock);
+	if (timer->to_created != CREATED_MASK) {
+		timer_eprintf("The timer was not to_created or deleted.\n");
+		goto out;
+	}
+	if (pthread_self() != ptt->tt_thread)
+		pthread_mutex_lock(&timer->to_lock);
+
+	memcpy(&timer->to_ts, &ts, sizeof(ts));
+	timer->to_active = 1;
+	timer->to_caller = __builtin_return_address(0);
+
+	if (list_empty(head))
+		list_add(&timer->to_list, head);
+	else {
+		list_for_each_entry(pos, head, to_list) {
+			if (pos != timer) {
+				if (cmp_earlier_timespec(&timer->to_ts, &pos->to_ts) == &timer->to_ts) {
+					if (list_empty(&timer->to_list))	/*It isn't in list*/
+						list_add(&timer->to_list, &pos->to_list);
+					else
+						list_move(&timer->to_list, &pos->to_list);
+					inserted = 1;
+					break;
+				}
+			}
+		}
+
+		if (!inserted) {
+			if (list_empty(&timer->to_list))	/*It isn't in list*/
+				list_add_tail(&timer->to_list, head);
+			else
+				list_move_tail(&timer->to_list, head);
+		}
+	}
+	
+	assert(!list_empty(&timer->to_list));
+
+	if (ptt->tt_active) {
+		if (ptt->tt_active == timer)
+			pthread_cond_signal(&ptt->tt_cond);
+		else if (list_entry(head->next, cm_timer_obj_t, to_list) == timer) {/*is head?*/
+			if (cmp_earlier_timespec(&timer->to_ts, &ptt->tt_active->to_ts)
+				== &timer->to_ts) {
+				list_add(&ptt->tt_active->to_list, &timer->to_list);
+				pthread_cond_signal(&ptt->tt_cond);
+			}
+		}
+	}
+	else if (list_entry(head->next, cm_timer_obj_t, to_list) == timer) /*is head?*/
+		pthread_cond_signal(&ptt->tt_cond);
+
+	if (pthread_self() != ptt->tt_thread)
+		pthread_mutex_unlock(&timer->to_lock);
+out:
+	pthread_mutex_unlock(&ptt->tt_lock);
+	timer_func_out("ret=%d", ret);
+	return ret;
+}
+
+int cm_stop_timer(cm_timer_obj_t *timer)
+{
+	pthread_timer_t *ptt = &pthread_timer;
+	int ret = 0;
+
+	if (!ptt->tt_inited) {
+		timer_eprintf("Timer module hasn't been initialized!!\n");
+		return -1;
+	}
+
+	timer_func_in("timer=%p", timer);
+
+	pthread_mutex_lock(&ptt->tt_lock);
+	if (timer->to_created != CREATED_MASK) {
+		timer_iprintf("The timer was not to_created or deleted.\n");
+		goto out;
+	}
+	if (pthread_self() != ptt->tt_thread)
+		pthread_mutex_lock(&timer->to_lock);
+
+	timer->to_active = 0;
+
+	if (ptt->tt_active && ptt->tt_active == timer)
+		pthread_cond_signal(&ptt->tt_cond);
+	else
+		list_del_init(&timer->to_list);
+
+	if (pthread_self() != ptt->tt_thread)
+		pthread_mutex_unlock(&timer->to_lock);
+out:
+	pthread_mutex_unlock(&ptt->tt_lock);
+	timer_func_out("ret=%d", ret);
+	return ret;
+}
+
+int cm_del_timer(cm_timer_obj_t *timer)
+{
+	int ret = 0;
+
+	timer_func_in("timer=%p", timer);
+
+	ret = cm_stop_timer(timer);
+	timer->to_created = 0;
+
+	timer_func_out("ret=%d", ret);
+	return ret;
+}
+
+int cm_timer_module_init(void)
+{
+	pthread_timer_t *ptt = &pthread_timer;
+
+	timer_func_in();
+
+	INIT_LIST_HEAD(&ptt->tt_head);
+
+	pthread_mutex_init(&ptt->tt_lock, NULL);
+	pthread_cond_init(&ptt->tt_cond, NULL);
+	ptt->tt_inited = 1;
+
+	pthread_create(&ptt->tt_thread, NULL, timer_thread, (void *) NULL);
+	
+	timer_func_out();
+	return 0;
+}
+
+void cm_timer_module_deinit(void)
+{
+	pthread_timer_t *ptt = &pthread_timer;
+	pthread_t thread;
+
+	timer_func_in();
+	
+	if ((thread = ptt->tt_thread)) {
+		ptt->tt_thread = (pthread_t) NULL;
+		pthread_cancel(thread);
+		pthread_join(thread, NULL);
+	}
+
+	pthread_mutex_destroy(&ptt->tt_lock);
+	pthread_cond_destroy(&ptt->tt_cond);
+	ptt->tt_inited = 0;
+
+	timer_func_out();
+}
+#else
+#include <signal.h>
+
+#define SIGNO_TIMER			SIGRTMIN
+
+static void timer_callback(int signum, siginfo_t *si, void *sv)
+{
+	cm_timer_obj_t *timer = si->_sifields._rt.si_sigval.sival_ptr;
+	void (*callback)(void *data) = timer->to_callback;
+
+	assert(signum == SIGNO_TIMER);
+
+	timer_func_in();
+	if (callback) {
+		timer_dprintf("+timer callback\n");
+		callback(timer->to_data);
+		timer_dprintf("-timer callback\n");
+	}
+	timer_func_out();
+}
+
+int cm_init_timer(cm_timer_obj_t *timer, void (*callback)(void *), void *data)
+{
+	struct sigaction sa_rt;
+	struct sigevent sigev;
+
+	timer_func_in("timer=%p, callback=%p, data=%p\n", timer, callback, data);
+
+	if (!timer || !callback || !data) {
+		timer_eprintf("Invalid parameter\n");
+		return -1;
+	}
+
+	memset(&sa_rt, 0, sizeof(sa_rt));
+	sigemptyset(&sa_rt.sa_mask);
+	sa_rt.sa_sigaction = timer_callback;
+	sa_rt.sa_flags = SA_SIGINFO | SA_RESTART;
+
+	if (sigaction(SIGNO_TIMER, &sa_rt, NULL) == -1) {
+		timer_std_eprintf("sigaction\n");
+		return -1;
+	}
+
+	timer->to_callback = callback;
+	timer->to_data = data;
+	memset(&sigev, 0, sizeof(sigev));
+	sigev.sigev_value.sival_ptr = timer;
+	sigev.sigev_notify = SIGEV_SIGNAL; /* notification with signal */
+	sigev.sigev_signo = SIGNO_TIMER;
+
+	/* create timer */
+	if (timer_create(CLOCK_REALTIME, &sigev, (timer_t *)&timer->to_id) < 0) {
+		timer_std_eprintf("timer_create\n");
+		return -1;
+	}
+
+	timer->to_created = CREATED_MASK;
+	timer_func_out("id=%p", timer->to_id);
+	return 0;
+}
+
+int cm_start_timer(cm_timer_obj_t *timer, int expire_milisec)
+{
+	struct itimerspec rt_itspec;
+	int second, nano_sec;
+	int ret = 0;
+
+	timer_func_in("timer=%p, expire_milisec=%d", timer, expire_milisec);
+
+	if (timer->to_created != CREATED_MASK) {
+		timer_iprintf("The timer was not to_created or deleted.\n");
+		goto out;
+	}
+
+	/* interval timer setting */
+	second = expire_milisec/1000;
+	nano_sec = (expire_milisec%1000)*1000/*us*/*1000/*ns*/;
+	rt_itspec.it_value.tv_sec = second;
+	rt_itspec.it_value.tv_nsec = nano_sec;
+	/*We do not repeat timer.*/
+	rt_itspec.it_interval.tv_sec = 0;
+	rt_itspec.it_interval.tv_nsec = 0;
+
+	if (timer_settime((timer_t)timer->to_id, 0, &rt_itspec, NULL) < 0) {
+		timer_std_eprintf("timer_settime(%p)\n", timer->to_id);
+		timer_delete((timer_t)timer->to_id);
+		ret = -1;
+	}
+out:
+	timer_func_out("ret=%d", ret);
+	return ret;
+}
+
+int cm_del_timer(cm_timer_obj_t *timer)
+{
+	int ret = 0;
+
+	timer_func_in("timer=%p, id=%p", timer, timer->to_id);
+
+	if (timer->to_created != CREATED_MASK) {
+		timer_eprintf("Invalid timer parameter\n");
+		ret = -1;
+	}
+	else if (timer->to_id) {
+		timer->to_created = 0;
+		ret = timer_delete((timer_t) timer->to_id);
+	}
+
+	timer_func_out("ret=%d", ret);
+	return ret;
+}
+#endif
+
diff --git a/cm/cm_timer.h b/cm/cm_timer.h
new file mode 100644
index 0000000..f45cf4b
--- /dev/null
+++ b/cm/cm_timer.h
@@ -0,0 +1,85 @@
+// 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.
+
+#if !defined(TIMER_H_07282008)
+#define TIMER_H_07282008
+#include <pthread.h>
+#include <sys/time.h>
+
+#define CM_PTHREAD_TIMER
+
+#if defined(CM_PTHREAD_TIMER)
+#include "list.h"
+
+typedef struct cm_timer_obj_s {
+	struct list_head	to_list;
+	unsigned			to_created;
+	pthread_mutex_t		to_lock;
+	struct timespec		to_ts;
+	int					to_active;
+
+	void *to_data;
+	void (*to_callback)(void *data);
+
+	/*debug info*/
+	void *to_caller;	
+} cm_timer_obj_t;
+#else
+typedef struct cm_timer_obj_s {
+	unsigned to_created;
+	void *to_id;
+	void *to_data;
+	void (*to_callback)(void *data);
+	
+} cm_timer_obj_t;
+#endif
+
+#define cm_time2ms(time_ptr)	(((time_ptr)->tv_sec * 1000) + ((time_ptr)->tv_usec / 1000))
+
+static inline const char *cm_get_date(time_t *t)
+{
+	static char buf[64];
+	struct tm *tm;
+	
+	tm = localtime(t);
+	sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d",
+		tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+	return buf;
+}
+
+static inline const char *cm_get_cur_date(void)
+{
+	time_t t;
+
+	time(&t);
+	return cm_get_date(&t);
+}
+
+static inline int cm_gettimemsofday(void)
+{
+	struct timeval time;
+
+	gettimeofday(&time, NULL);
+	return cm_time2ms(&time);
+}
+
+#if defined(CM_PTHREAD_TIMER)
+int cm_timer_module_init(void);
+void cm_timer_module_deinit(void);
+#else
+#define cm_timer_module_init()
+#define cm_timer_module_deinit()
+#endif
+
+int cm_init_timer(cm_timer_obj_t *timer, void (*callback)(void *), void *data);
+int cm_start_timer(cm_timer_obj_t *timer, int expire_milisec);
+#if defined(CM_PTHREAD_TIMER)
+int cm_stop_timer(cm_timer_obj_t *timer);
+#else
+#define cm_stop_timer(timer)	cm_start_timer(timer, 0)
+#endif
+int cm_del_timer(cm_timer_obj_t *timer);
+
+#endif
+
diff --git a/cm/cmd.c b/cm/cmd.c
new file mode 100644
index 0000000..d75c1ca
--- /dev/null
+++ b/cm/cmd.c
@@ -0,0 +1,2966 @@
+// 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.
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+#include <math.h>
+#include <zlib.h>
+
+#include "cm.h"
+#include "profilestring.h"
+#include "param.h"
+#include "sem.h"
+
+extern int get_first_odev(void);
+extern int cm_odev_cnt;
+extern char *StatusStr[8];
+extern char *ConnStatusStr[8];
+static sem_t hci_data_sem[MAX_DEV];
+
+typedef struct hci_data_s {
+	char data[HCI_MAX_PACKET];
+	int len;
+} hci_data_t;
+static hci_data_t hci_data[MAX_DEV];
+
+#define NO_CM_CMD		(-2)
+#define EXIT_CM_CMD		(-100)
+
+#define KEY_auth_pkm_enable					"auth_pkm_enable"
+#define KEY_eap_type						"eap_type"
+#define KEY_eap_tls_use_nvram_info			"eap_tls_use_nvram_info"
+#define KEY_eap_tls_userid					"eap_tls_userid"
+#define KEY_eap_tls_userpasswd				"eap_tls_userpasswd"
+#define KEY_eap_tls_anonyid					"eap_tls_anonyid"
+#define KEY_eap_tls_privateKeyPwd			"eap_tls_pri_passwd"
+#define KEY_eap_tls_fragsize				"eap_tls_fragsize"
+#define KEY_eap_tls_delimiter_enable		"eap_tls_delimiter_enable"
+#define KEY_eap_tls_resumption_disable		"eap_tls_resumption_disable"
+#define KEY_eap_tls_cr801_enable			"eap_tls_cr801_enable"
+#define KEY_eap_tls_decoration				"eap_tls_decoration"
+#define KEY_eap_tls_sessionticket_disable	"eap_tls_sessionticket_disable"
+#define KEY_eap_tls_dev_cert_null			"eap_tls_dev_cert_null"
+#define KEY_eap_tls_ca_cert_null			"eap_tls_ca_cert_null"
+#define KEY_eap_tls_use_nvram_cert			"eap_tls_use_nvram_cert"
+#define KEY_eap_tls_wm_serv_root			"eap_tls_wm_serv_root"
+#define KEY_eap_tls_serv_root_ca1			"eap_tls_serv_root_ca1"
+#define KEY_eap_tls_serv_root_ca2			"eap_tls_serv_root_ca2"
+#define KEY_eap_tls_serv_root_ca3			"eap_tls_serv_root_ca3"
+#define KEY_eap_tls_wm_dev_root				"eap_tls_wm_dev_root"
+#define KEY_eap_tls_dev_root_ca1			"eap_tls_dev_root_ca1"
+#define KEY_eap_tls_dev_sub_ca				"eap_tls_dev_sub_ca"
+#define KEY_eap_tls_dev_cert				"eap_tls_dev_cert"
+#define KEY_eap_tls_dev_cert_key			"eap_tls_dev_cert_key"
+
+#define desc_eap_tls_wm_serv_root			"wimax server root"
+#define desc_eap_tls_serv_root_ca1			"server root ca1"
+#define desc_eap_tls_serv_root_ca2			"server root ca2"
+#define desc_eap_tls_serv_root_ca3			"server root ca3"
+#define desc_eap_tls_wm_dev_root			"wimax device root"
+#define desc_eap_tls_dev_root_ca1			"device root ca1"
+#define desc_eap_tls_dev_sub_ca				"device sub ca"
+#define desc_eap_tls_dev_cert				"device cert"
+#define desc_eap_tls_dev_cert_key			"device cert private key"
+
+dev_conf_t default_dev_conf;
+WIMAX_API_PROFILE_INFO profile_list[MAX_PROFILE_LIST];
+int profile_list_cnt;
+
+typedef int cmd_fun(int argc, char *argv[]);
+
+typedef struct cmd_s {
+	const char	*cmd;
+	const char	*desc;
+	const char	*param;
+	cmd_fun	*func;
+
+} cmd_t;
+
+#define DEVIATION_CNT	10
+
+typedef struct deviation_s {
+	float value[DEVIATION_CNT];
+	int cnt;
+
+} deviation_t;
+
+typedef struct dev_info_s {
+	deviation_t cinr1;
+	deviation_t cinr2;
+	deviation_t rssi1;
+	deviation_t rssi2;
+
+} dev_info_t;
+
+static dev_info_t dev_info[MAX_DEV];
+
+
+static int cm_uicc_power(int dev_idx, int on);
+static void print_cmd_usage(const char *cmd);
+static void print_cmd_list(const char *cmd);
+static int do_cmd(char *cmd_line, int len);
+
+static __inline bool __is_delimiter(char ch)
+{
+   return (ch == ' ');
+}
+
+static __inline bool __is_binder(char ch)
+{
+   return (ch == '"');
+}
+
+static void __get_token_arg(char *cmd_line, int *argc, char *argv[])
+{
+	int found_arg = 1,
+		bind_on = 0;
+	int argn = 0;
+
+	while (*cmd_line) {
+		if (*cmd_line == '\n') {
+			*cmd_line = '\0';
+			break;
+		}
+		if (0 == bind_on && __is_delimiter(*cmd_line)) {
+			found_arg = 1;
+			*cmd_line = '\0';
+		}
+		else if (__is_binder(*cmd_line)) {
+			bind_on ^= 1;
+			*cmd_line = '\0';
+		}
+		else if (found_arg) {
+			argv[argn++] = cmd_line;
+			found_arg = 0;
+		}
+
+		cmd_line++;
+	}
+
+	*argc = argn;
+}
+
+static int find_device_conf(const char *mac)
+{
+	char section[256];
+	int tmp;
+
+	assert(mac);
+	
+	sprintf(section, "device-%s", mac);
+
+	if (get_profile_section(section, (char *)&tmp, 1, CONF_FILE))
+		return 1;
+	else
+		return 0;
+}
+
+void load_device_conf(dev_conf_t *conf, const char *mac)
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+	char section[256];
+	char str[256];
+
+	memset(conf, 0, sizeof(*conf));
+
+	if (!mac) {
+		memset(conf->mac_str, 0, sizeof(conf->mac_str));
+		mac = "default";
+	}
+	else
+		memcpy(conf->mac_str, mac, sizeof(conf->mac_str));
+	sprintf(section, "device-%s", mac);
+
+	get_profile_string(section, KEY_auth_pkm_enable, "n", str, sizeof(str), CONF_FILE);
+	if (!strcasecmp(str, "n"))
+		conf->eapp.type = GCT_WIMAX_NO_EAP;
+	else {
+		get_profile_string(section, KEY_eap_type, "TTLS_MSCHAPV2", 
+			str, sizeof(str), CONF_FILE);
+		strcpy(conf->type_str, str);
+		if (!strcasecmp(str, "AKA"))
+			conf->eapp.type = GCT_WIMAX_EAP_AKA;
+		else if (!strcasecmp(str, "TLS"))
+			conf->eapp.type = GCT_WIMAX_EAP_TLS;
+		else if (!strcasecmp(str, "TTLS_MD5"))
+			conf->eapp.type = GCT_WIMAX_EAP_TTLS_MD5;
+		else if (!strcasecmp(str, "TTLS_MSCHAPV2"))
+			conf->eapp.type = GCT_WIMAX_EAP_TTLS_MSCHAPV2;
+		else if (!strcasecmp(str, "TTLS_CHAP"))
+			conf->eapp.type = GCT_WIMAX_EAP_TTLS_CHAP;
+	}
+	get_profile_string(section, KEY_eap_tls_use_nvram_info, "n", str,
+						sizeof(str), CONF_FILE);
+	if (!strcasecmp(str, "y"))
+		conf->eapp.useNvramParam = 1;
+	else {
+		conf->eapp.useNvramParam = 0;
+
+		get_profile_string(section, KEY_eap_tls_userid, "",
+			(char *) conf->eapp.userId, sizeof(conf->eapp.userId), CONF_FILE);
+		get_profile_string(section, KEY_eap_tls_userpasswd, "",
+			(char *) conf->eapp.userIdPwd, sizeof(conf->eapp.userIdPwd), CONF_FILE);
+		get_profile_string(section, KEY_eap_tls_anonyid, "",
+			(char *) conf->eapp.anonymousId, sizeof(conf->eapp.anonymousId), CONF_FILE);
+		get_profile_string(section, KEY_eap_tls_privateKeyPwd, "",
+			(char *) conf->eapp.privateKeyPwd, sizeof(conf->eapp.privateKeyPwd), CONF_FILE);
+	}
+	
+	get_profile_string(section, KEY_eap_tls_fragsize, "1300",
+		str, sizeof(str), CONF_FILE);
+	conf->eapp.fragSize = atoi(str);
+
+	get_profile_string(section, KEY_eap_tls_delimiter_enable, "n",
+		str, sizeof(str), CONF_FILE);
+	if (!strcasecmp(str, "y"))
+		conf->eapp.useDelimiter = 1;
+	else
+		conf->eapp.useDelimiter = 0;
+
+	get_profile_string(section, KEY_eap_tls_resumption_disable, "n",
+		str, sizeof(str), CONF_FILE);
+	if (!strcasecmp(str, "y"))
+		conf->eapp.disableResumption = 1;
+	else
+		conf->eapp.disableResumption = 0;
+	
+	get_profile_string(section, KEY_eap_tls_cr801_enable, "n",
+		str, sizeof(str), CONF_FILE);
+	if (!strcasecmp(str, "y"))
+		conf->eapp.cr801Enable = 1;
+	else
+		conf->eapp.cr801Enable = 0;
+	
+	get_profile_string(section, KEY_eap_tls_decoration, "",
+		(char *) conf->eapp.decoration, sizeof(conf->eapp.decoration), CONF_FILE);
+	
+	get_profile_string(section, KEY_eap_tls_sessionticket_disable, "n",
+		str, sizeof(str), CONF_FILE);
+	if (!strcasecmp(str, "y"))
+		conf->eapp.disableSessionTicket = 1;
+	else
+		conf->eapp.disableSessionTicket = 0;
+
+	get_profile_string(section, KEY_eap_tls_dev_cert_null, "n",
+		str, sizeof(str), CONF_FILE);
+	if (!strcasecmp(str, "y"))
+		conf->eapp.devCertNULL = 1;
+	else
+		conf->eapp.devCertNULL = 0;
+
+	get_profile_string(section, KEY_eap_tls_ca_cert_null, "n",
+		str, sizeof(str), CONF_FILE);
+	if (!strcasecmp(str, "y"))
+		conf->eapp.caCertNULL = 1;
+	else
+		conf->eapp.caCertNULL = 0;
+
+	conf->eapp.logEnable = pconf->eap_log_enable;
+}
+
+static void print_device_conf(dev_conf_t *conf)
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+	const char *type;
+
+	cm_printf("--------------- Begin loaded configurations ---------------\n");
+
+	cm_printf("[common]\n");
+	cm_printf("Log path: %s\n", pconf->log_path);
+	cm_printf("Log level: %d\n", pconf->log_level);
+	cm_printf("EAP log: %s\n", pconf->eap_log_enable ? "enabled" : "disabled");
+	cm_printf("Embedded EAP: %s\n", pconf->embedded_eap_enable ? "enabled" : "disabled");
+	cm_printf("OMA-DM: %s\n", pconf->oma_dm_enable ? "enabled" : "disabled");
+	cm_printf("Non-volatile path: %s\n", pconf->nonvolatile_dir);
+	cm_printf("Default script file: %s\n", pconf->run_script_file);
+	cm_printf("Auto connection: %s\n", pconf->auto_connect_enable ? "enabled" : "disabled");
+	if (pconf->auto_connect_enable)
+		cm_printf("Auto connection retry count: %u\n", pconf->auto_connect_retry_count);
+	cm_printf("Auto selecting profile index: %d\n", pconf->auto_select_profile_index);
+	cm_printf("Unknown network auto connection: %s\n",
+		pconf->unknown_net_auto_connect_enable ? "enabled" : "disabled");
+	cm_printf("IP allocation timeout: %d sec.\n", pconf->ip_allocation_timeout_sec);
+	cm_printf("Disconnect on ip failure: %s\n",
+		pconf->disconnct_on_ip_failure ? "enabled" : "disabled");
+	cm_printf("\n");
+
+	if (!conf->mac_str[0])
+		cm_printf("[device-default]\n");
+	else
+		cm_printf("[device-%s]\n", conf->mac_str);
+
+	if (conf->eapp.type == GCT_WIMAX_NO_EAP)
+		cm_printf("AUTH PKM: disabled\n");
+	else {
+		cm_printf("AUTH PKM: enabled\n");
+		cm_printf("EAP type: %s\n", conf->type_str);
+		if (conf->eapp.type >= GCT_WIMAX_EAP_TLS &&
+			conf->eapp.type <= GCT_WIMAX_EAP_TTLS_CHAP) {
+			if (conf->eapp.useNvramParam)
+				cm_printf("NVRAM parameter for TLS/TTLS enabled\n");
+
+			if (conf->eapp.type != GCT_WIMAX_EAP_TLS) {
+				type = "TTLS";
+				if (!conf->eapp.useNvramParam) {
+					cm_printf("%s user id: %s\n", type, conf->eapp.userId);
+					cm_printf("%s user passwd: %s\n", type, conf->eapp.userIdPwd);
+				}
+			}
+			else
+				type = "TLS";
+
+			if (!conf->eapp.useNvramParam) {
+				cm_printf("%s anonymous id: %s\n", type, conf->eapp.anonymousId);
+				cm_printf("%s private key passwd: %s\n", type, conf->eapp.privateKeyPwd);
+			}
+			cm_printf("%s frag size: %d\n", type, conf->eapp.fragSize);
+			cm_printf("%s delimiter: %s\n", type,
+				conf->eapp.useDelimiter ? "enabled" : "disabled");
+			cm_printf("%s null dev cert: %s\n", type,
+				conf->eapp.devCertNULL ? "enabled" : "disabled");
+			cm_printf("%s null ca cert: %s\n", type,
+				conf->eapp.caCertNULL ? "enabled" : "disabled");
+			cm_printf("%s resumption: %s\n", type,
+				conf->eapp.disableResumption ? "disabled" : "enabled");
+			cm_printf("%s cr801: %s\n", type,
+				conf->eapp.cr801Enable ? "enabled" : "disabled");
+			cm_printf("%s decoration: %s\n", type, conf->eapp.decoration);
+			cm_printf("%s session-ticket: %s\n", type,
+				conf->eapp.disableSessionTicket ? "disabled" : "enabled");
+		}
+	}
+
+	cm_printf("---------------- End loaded configurations ----------------\n");
+}
+
+int setup_device_conf(GDEV_ID *ID, const unsigned char *mac)
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+	dev_conf_t *conf = &cm_dev_conf[ID->deviceIndex];
+	char mac_str[32];
+
+	memset(conf, 0, sizeof(*conf));
+
+	assert(mac);
+
+	sprintf(mac_str, "%02x:%02x:%02x:%02x:%02x:%02x",
+		mac[0], mac[1],	mac[2], mac[3], mac[4], mac[5]);
+
+	if (find_device_conf(mac_str))
+		load_device_conf(conf, mac_str);
+	else
+		memcpy(conf, &default_dev_conf, sizeof(dev_conf_t));
+
+	print_device_conf(conf);
+	if (conf->eapp.type != GCT_WIMAX_NO_EAP) {
+		if (pconf->api_mode != GCT_WIMAX_API_PRIVILEGE_READ_ONLY) {
+			if (GAPI_SetEap(ID, &conf->eapp) != GCT_API_RET_SUCCESS) {
+				cm_printf("Auth configuration failure\n");
+				return -1;
+			}
+		}
+	}
+
+	if (GAPI_GetCapability(ID, &conf->cap) != GCT_API_RET_SUCCESS) {
+		conf->cap = 0;
+		cm_printf("Getting capability failure\n");
+		return -1;
+	}
+	if (pconf->api_mode != GCT_WIMAX_API_PRIVILEGE_READ_ONLY) {
+		if (CAP_EEAP_AKA_ENABLED(ID->deviceIndex))
+			cm_uicc_power(ID->deviceIndex, 1);
+	}
+	return ID->deviceIndex;
+}
+
+static int send_print_string(GDEV_ID_P pID, void *buf, int len)
+{
+	char hci_buf[HCI_MAX_PACKET];
+	hci_t *hci = (hci_t *) hci_buf;
+
+	if (len > (HCI_MAX_PACKET-HCI_HEADER_SIZE))
+		len = HCI_MAX_PACKET-HCI_HEADER_SIZE;
+
+	hci->cmd_evt = _H2B(WIMAX_CLI_CMD);
+	hci->length = _H2B(len);
+	memcpy(hci->data, buf, len);
+
+	len += HCI_HEADER_SIZE;
+
+	if (GAPI_WriteHCIPacket(pID, hci_buf, len) != GCT_API_RET_SUCCESS) {
+		cm_printf("Write HCI failure\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int cmd_get_dev_list(int argc, char *argv[])
+{
+	WIMAX_API_HW_DEVICE_ID list[256];
+	UINT32 cnt = 256;
+	int i;
+
+	if (GAPI_GetListDevice(cm_api_handle, list, &cnt) != GCT_API_RET_SUCCESS) {
+		cm_printf("Get device list failure\n");
+		return -1;
+	}
+
+	if (cnt) {
+		cm_printf("[Device index] [Device name]\n");
+		for (i = 0; i < (int) cnt; i++) {
+			cm_printf("          %3d%14S\n",
+				list[i].deviceIndex,	(wchar_t *)list[i].deviceName);
+		}
+		return list[0].deviceIndex;
+	}
+	else
+		cm_printf("Not found device\n");
+	return 0;
+}
+
+static int cmd_get_status(int argc, char *argv[])
+{
+	WIMAX_API_DEVICE_STATUS	nDevStatus = 0;
+	WIMAX_API_CONNECTION_PROGRESS_INFO nConnectionInfo = 0;
+	GDEV_ID ID;
+
+	ID.apiHandle = cm_api_handle;
+	if (argc == 1)
+		ID.deviceIndex = DEFAULT_DEVICE;
+	else
+		ID.deviceIndex = atoi(argv[1]);
+
+	if (GAPI_GetDeviceStatus(&ID, &nDevStatus, &nConnectionInfo) == GCT_API_RET_SUCCESS) {
+		cm_printf("device[%d] status [%s]\n", ID.deviceIndex, StatusStr[nDevStatus]);
+		if (nDevStatus == WIMAX_API_DEVICE_STATUS_Connecting)
+			cm_printf("Connection status [%s]\n", ConnStatusStr[nConnectionInfo]);
+	}
+	else
+		cm_printf("Get device status failure\n");
+	return ID.deviceIndex;
+}
+
+static int cm_rf_up(int dev_idx)
+{
+	GDEV_ID ID;
+
+	ID.apiHandle = cm_api_handle;
+	ID.deviceIndex = dev_idx;
+
+	if (GAPI_CmdControlPowerManagement(&ID, WIMAX_API_RF_ON) != GCT_API_RET_SUCCESS) {
+		cm_eprintf("device[%d] rf up failure\n", ID.deviceIndex);
+		return -1;
+	}
+	return dev_idx;
+}
+
+static int cmd_rf_up(int argc, char *argv[])
+{
+	int dev_idx;
+
+	if (argc == 1)
+		dev_idx = DEFAULT_DEVICE;
+	else
+		dev_idx = atoi(argv[1]);
+
+	return cm_rf_up(dev_idx);
+}
+
+static int cmd_rf_down(int argc, char *argv[])
+{
+	GDEV_ID ID;
+
+	ID.apiHandle = cm_api_handle;
+	if (argc == 1)
+		ID.deviceIndex = DEFAULT_DEVICE;
+	else
+		ID.deviceIndex = atoi(argv[1]);
+
+	if (GAPI_CmdControlPowerManagement(&ID, WIMAX_API_RF_OFF) != GCT_API_RET_SUCCESS) {
+		cm_printf("device[%d] rf down failure\n", ID.deviceIndex);
+		return -1;
+	}
+	return ID.deviceIndex;
+}
+
+static int cm_get_profile_list(int dev_idx)
+{
+	GDEV_ID ID;
+	int i;
+
+	ID.apiHandle = cm_api_handle;
+	ID.deviceIndex = dev_idx;
+
+	profile_list_cnt = _numof_array(profile_list);
+	if (GAPI_GetSelectProfileList(&ID, profile_list, (UINT32 *) &profile_list_cnt)
+		!= GCT_API_RET_SUCCESS) {
+		cm_printf("Get profile failure\n");
+		return -1;
+	}
+
+	cm_printf("[Profile-Index] [Profile-ID] [Profile-Name]\n");
+	for (i = 0; i < profile_list_cnt; i++) {
+		cm_printf("%14d     %08X   %S\n",
+			i, (int)profile_list[i].profileID,	(wchar_t *)profile_list[i].profileName);
+	}
+
+	return profile_list_cnt;
+}
+
+static int cmd_get_profile_list(int argc, char *argv[])
+{
+	int dev_idx;
+
+	if (argc == 1)
+		dev_idx = DEFAULT_DEVICE;
+	else
+		dev_idx = atoi(argv[1]);
+
+	if (cm_get_profile_list(dev_idx) < 0)
+		return -1;
+
+	return dev_idx;
+}
+
+static int cm_set_profile(int dev_idx, int profile_idx)
+{
+	GDEV_ID ID;
+
+	ID.apiHandle = cm_api_handle;
+	ID.deviceIndex = dev_idx;
+
+	if (profile_idx >= profile_list_cnt)
+		cm_eprintf("index[%d] is invalid\n", profile_idx);
+	else {
+		if (GAPI_SetProfile(&ID, profile_list[profile_idx].profileID)
+			!= GCT_API_RET_SUCCESS ) {
+			cm_eprintf("Set profile failure\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int cmd_set_profile(int argc, char *argv[])
+{
+	int dev_idx, profile_idx;
+
+	if (argc < 2) {
+		cm_printf("Invalid parameter.\n");
+		return -1;
+	}
+
+	if (argc == 2)
+		dev_idx = DEFAULT_DEVICE;
+	else
+		dev_idx = atoi(argv[2]);
+	profile_idx = atoi(argv[1]);
+
+	return cm_set_profile(dev_idx, profile_idx);
+}
+
+static int cm_get_net_list(int dev_idx, WIMAX_API_NSP_INFO_P list, int *list_cnt)
+{
+	GDEV_ID ID;
+
+	ID.apiHandle = cm_api_handle;
+	ID.deviceIndex = dev_idx;
+
+	if (GAPI_GetNetworkList(&ID, list, (UINT32 *) list_cnt)
+		!= GCT_API_RET_SUCCESS) {
+		cm_eprintf("Get network list failure\n");
+		return -1;
+	}
+
+	return ID.deviceIndex;
+}
+
+static void cm_print_net_list(WIMAX_API_NSP_INFO_P list, int list_cnt)
+{
+	int i;
+
+	cm_printf("[NSP-Name] [NSP-ID] [RSSI] [CINR]\n");
+	for (i = 0; i < list_cnt; i++) {
+		cm_printf("%9S   %06X %6d %6d\n",
+			(wchar_t *) list[i].NSPName,
+			(int) list[i].NSPid,
+			(int) list[i].RSSI-123,
+			(int) list[i].CINR-10);
+	}
+}
+
+static int cmd_get_net_list(int argc, char *argv[])
+{
+	WIMAX_API_NSP_INFO nsp[MAX_NETWORK_LIST];
+	int dev_idx;
+	int list_cnt = MAX_NETWORK_LIST;
+
+	if (argc == 1)
+		dev_idx = DEFAULT_DEVICE;
+	else
+		dev_idx = atoi(argv[1]);
+
+	if (cm_get_net_list(dev_idx, nsp, &list_cnt) < 0)
+		return -1;
+
+	cm_print_net_list(nsp, list_cnt);
+
+	return dev_idx;
+}
+
+static int cmd_get_neighbor_list(int argc, char *argv[])
+{
+	GCT_API_NEIGHBOR_LIST Neighbor[64], *n;
+	GDEV_ID ID;
+	UINT32 list_cnt = _numof_array(Neighbor), i;
+
+	ID.apiHandle = cm_api_handle;
+	if (argc == 1)
+		ID.deviceIndex = DEFAULT_DEVICE;
+	else
+		ID.deviceIndex = atoi(argv[1]);
+
+	if (GAPI_GetNeighborList(&ID, Neighbor, &list_cnt)
+		!= GCT_API_RET_SUCCESS) {
+		cm_printf("Get neighbor list failure\n");
+		return -1;
+	}
+
+	if (!list_cnt) {
+		cm_printf("Not found neighbor!!\n");
+		goto out;
+	}
+
+	n = Neighbor;
+	cm_printf("[Frequency] [Preamble] [CINR] [RSSI]         [BSID]\n");
+	for (i = 0; i < list_cnt; i++, n++) {
+		cm_printf(" %9d        %3d   %4d   %4d  %02x%02x%02x:%02x%02x%02x\n",
+				(int)n->frequency, n->preamble, (s8)n->cinr-10, (s8)n->rssi-123,
+				n->bsId[0], n->bsId[1], n->bsId[2],
+				n->bsId[3], n->bsId[4], n->bsId[5]);
+	}
+
+out:
+	return ID.deviceIndex;
+}
+
+static int combine_level(int dev_idx, int c0, int c1)
+{
+	dev_conf_t *conf = &cm_dev_conf[dev_idx];
+	int max, diff, offset;
+
+	if (c0 > c1) {
+		max = c0;
+		diff = c0 - c1;
+	}
+	else {
+		max = c1;
+		diff = c1 - c0;
+	}
+
+	if (conf->fw_mac_version < 0x01090104/*1.9.1.4*/) {
+		/*floor*/
+		if (diff >= 6) offset = 0;
+		else if (diff >= 3)  offset = 1;
+		else if (diff >= 1)  offset = 2;
+		else     offset = 3; 
+	}
+	else {
+		/*round*/
+		if (diff >= 10) offset = 0;
+		else if (diff >= 4)  offset = 1;
+		else if (diff >= 2)  offset = 2;
+		else     offset = 3; 
+	}
+
+	max += offset;
+
+	return max;
+}
+
+static float calc_deviation(float *fArr, int cnt)
+{
+	float sum, dsum, avg;
+	int i;
+
+	if (cnt <= 0)
+		return 0;
+	if (cnt > DEVIATION_CNT)
+		cnt = DEVIATION_CNT;
+
+	sum = 0;
+	for (i = 0; i < cnt; i++)
+		sum += fArr[i];
+	avg = sum/cnt;
+
+	for (i = dsum = 0; i < cnt; i++)
+		dsum += (fArr[i]-avg)*(fArr[i]-avg);
+
+	return (float) sqrt(dsum/cnt);
+}
+
+static const char *fec_string(int fec)
+{
+	#define _T(s)	s
+	const char *str;
+
+	switch(fec) {
+		case 0:
+			str = _T("QPSK(CC) 1/2");
+			break;
+		case 1:
+			str = _T("QPSK(CC) 3/4");
+			break;
+		case 2:
+			str = _T("16-QAM(CC) 1/2");
+			break;
+		case 3:
+			str = _T("16-QAM(CC) 3/4");
+			break;
+		case 4:
+			str = _T("64-QAM(CC) 1/2");
+			break;
+		case 5:
+			str = _T("64-QAM(CC) 2/3");
+			break;
+		case 6:
+			str = _T("64-QAM(CC) 3/4");
+			break;
+		case 7:
+			str = _T("QPSK(BTC) 1/2");
+			break;
+		case 8:
+			str = _T("QPSK(BTC) 3/4 or 2/3");
+			break;
+		case 9:
+			str = _T("16-QAM(BTC) 3/5");
+			break;
+		case 10:
+			str = _T("16-QAM(BTC) 4/5");
+			break;
+		case 11:
+			str = _T("64-QAM(BTC) 2/3 or 5/8");
+			break;
+		case 12:
+			str = _T("64-QAM(BTC) 5/6 or 4/5");
+			break;
+		case 13:
+			str = _T("QPSK(CTC) 1/2");
+			break;
+		/*case 14:
+			str = _T("Reserved");
+			break;*/
+		case 15:
+			str = _T("QPSK(CTC) 3/4");
+			break;
+		case 16:
+			str = _T("16-QAM(CTC) 1/2");
+			break;
+		case 17:
+			str = _T("16-QAM(CTC) 3/4");
+			break;
+		case 18:
+			str = _T("64-QAM(CTC) 1/2");
+			break;
+		case 19:
+			str = _T("64-QAM(CTC) 2/3");
+			break;
+		case 20:
+			str = _T("64-QAM(CTC) 3/4");
+			break;
+		case 21:
+			str = _T("64-QAM(CTC) 5/6");
+			break;
+		case 22:
+			str = _T("QPSK(ZT CC) 1/2");
+			break;
+		case 23:
+			str = _T("QPSK(ZT CC) 3/4");
+			break;
+		case 24:
+			str = _T("16-QAM(ZT CC) 1/2");
+			break;
+		case 25:
+			str = _T("16-QAM(ZT CC) 3/4");
+			break;
+		case 26:
+			str = _T("64-QAM(ZT CC) 1/2");
+			break;
+		case 27:
+			str = _T("64-QAM(ZT CC) 2/3");
+			break;
+		case 28:
+			str = _T("64-QAM(ZT CC) 3/4");
+			break;
+		case 29:
+			str = _T("QPSK(LDPC) 1/2");
+			break;
+		case 30:
+			str = _T("QPSK(LDPC) 2/3 A code");
+			break;
+		case 31:
+			str = _T("QPSK(LDPC) 3/4 A code");
+			break;
+		case 32:
+			str = _T("16-QAM(LDPC) 1/2");
+			break;
+		case 33:
+			str = _T("16-QAM(LDPC) 2/3 A code");
+			break;
+		case 34:
+			str = _T("16-QAM(LDPC) 3/4 A code");
+			break;
+		case 35:
+			str = _T("64-QAM(LDPC) 1/2");
+			break;
+		case 36:
+			str = _T("64-QAM(LDPC) 2/3 A code");
+			break;
+		case 37:
+			str = _T("64-QAM(LDPC) 3/4 A code");
+			break;
+		case 38:
+			str = _T("QPSK(LDPC) 2/3 B code");
+			break;
+		case 39:
+			str = _T("QPSK(LDPC) 3/4 B code");
+			break;
+		case 40:
+			str = _T("16-QAM(LDPC) 2/3 B code");
+			break;
+		case 41:
+			str = _T("16-QAM(LDPC) 3/4 B code");
+			break;
+		case 42:
+			str = _T("64-QAM(LDPC) 2/3 B code");
+			break;
+		case 43:
+			str = _T("64-QAM(LDPC) 3/4 B code");
+			break;
+		case 44:
+			str = _T("QPSK(CC with optional interleaver) 1/2");
+			break;
+		case 45:
+			str = _T("QPSK(CC with optional interleaver) 3/4");
+			break;
+		case 46:
+			str = _T("16-QAM(CC with optional interleaver) 1/2");
+			break;
+		case 47:
+			str = _T("16-QAM(CC with optional interleaver) 3/4");
+			break;
+		case 48:
+			str = _T("64-QAM(CC with optional interleaver) 2/3");
+			break;
+		case 49:
+			str = _T("64-QAM(CC with optional interleaver) 3/4");
+			break;
+		case 50:
+			str = _T("QPSK(LDPC) 5/6");
+			break;
+		case 51:
+			str = _T("16-QAM(LDPC) 5/6");
+			break;
+		case 52:
+			str = _T("64-QAM(LDPC) 5/6");
+			break;
+		default:
+			str = _T("Unknown");
+			break;
+	}
+
+	return str;
+}
+
+static int refresh_rf_info(GDEV_ID *ID)
+{
+	static int last_recv_PERErrorCount;
+	static int last_recv_PERReceiveCount;
+	static int base_PERErrorCount;
+	static int base_PERReceiveCount;
+
+	dev_info_t *di = &dev_info[ID->deviceIndex];
+	GCT_API_RF_INFORM rf_info;
+	s8 cinr1, cinr2, rssi1, rssi2;
+	float per;
+
+	if (GAPI_GetRFInform(ID, &rf_info) != GCT_API_RET_SUCCESS) {
+		cm_printf("Get rf info fail\n");
+		return -1;
+	}
+
+	cinr1 = (s8) rf_info.CINR-10;
+	cinr2 = (s8) rf_info.CINR2-10;
+	rssi1 = (s8) rf_info.RSSI-123;
+	rssi2 = (s8) rf_info.RSSI2-123;
+
+	cm_printf("[RF Information]\n");
+
+	cm_printf("BSID: %02X %02X %02X %02X %02X %02X\n",
+		rf_info.bsId[0], rf_info.bsId[1], rf_info.bsId[2],
+		rf_info.bsId[3], rf_info.bsId[4], rf_info.bsId[5]);
+	cm_printf("UL PermBase: %d\n", rf_info.ULPermBase);
+	cm_printf("DL PermBase: %d\n", rf_info.DLPermBase);
+	cm_printf("Current preamble index: %d\n", rf_info.CurrentPreambleIndex);
+	cm_printf("Previous preamble index: %d\n", rf_info.PreviousPreambleIndex);
+	cm_printf("HO count: %d\n", rf_info.HandOverCount);
+	cm_printf("HO fail count: %d\n", rf_info.HandOverFailCount);
+	cm_printf("Resync count: %d\n", rf_info.ResyncCount);
+	cm_printf("HO signal latency: %d\n", rf_info.HoSignalLatency);
+	cm_printf("Combined CINR: %d\n", combine_level(ID->deviceIndex, cinr1, cinr2));
+	cm_printf("CINR: %d\n", cinr1);
+	cm_printf("CINR deviation: %.4f\n", calc_deviation(di->cinr1.value, ++di->cinr1.cnt));
+	cm_printf("CINR2: %d\n", cinr2);
+	cm_printf("CINR2 deviation: %.4f\n", calc_deviation(di->cinr2.value, ++di->cinr2.cnt));
+	cm_printf("Combined RSSI: %d\n", combine_level(ID->deviceIndex, rssi1, rssi2));
+	cm_printf("RSSI: %d\n", rssi1);
+	cm_printf("RSSI deviation: %.4f\n", calc_deviation(di->rssi1.value, ++di->rssi1.cnt));
+	cm_printf("RSSI2: %d\n", rssi2);
+	cm_printf("RSSI2 deviation: %.4f\n", calc_deviation(di->rssi2.value, ++di->rssi2.cnt));
+	
+	if (rf_info.nPERReceiveCount) {
+		last_recv_PERErrorCount = rf_info.nPERErrorCount;
+		last_recv_PERReceiveCount = rf_info.nPERReceiveCount;
+		if (base_PERErrorCount > last_recv_PERErrorCount)
+			base_PERErrorCount = last_recv_PERErrorCount;
+		if (base_PERReceiveCount > last_recv_PERReceiveCount)
+			base_PERReceiveCount = last_recv_PERReceiveCount;
+
+		if (last_recv_PERReceiveCount-base_PERReceiveCount) {
+			per = ((float)last_recv_PERErrorCount-(float)base_PERErrorCount)/
+				((float)last_recv_PERReceiveCount-(float)base_PERReceiveCount);
+		} else
+			per = 0;
+
+		cm_printf("PER: %.6f [%d/%d]\n", per, 
+						last_recv_PERErrorCount-base_PERErrorCount, 
+						last_recv_PERReceiveCount-base_PERReceiveCount);
+	}
+	else
+		cm_printf("PER: --\n");
+	
+	cm_printf("Power control mode: %d\n", rf_info.PowerControlMode);
+	cm_printf("Tx power: %d\n", (s8) (rf_info.TxPower/2-84));
+	cm_printf("Tx power maximum: %d\n", (s8) (rf_info.TxPowerMax/2-84));
+	cm_printf("Tx power headroom: %d\n", (s8)rf_info.TxPowerMax-(s8)rf_info.TxPower);
+	cm_printf("UL burst data FEC scheme: %s\n", fec_string(rf_info.ULBurstDataFECScheme));
+	cm_printf("DL burst data FEC scheme: %s\n", fec_string(rf_info.DLBurstDataFECScheme));
+	cm_printf("UL burst data UIUC: %02d\n", rf_info.ULBurstDataUIUC);
+	cm_printf("DL burst data DIUC: %02d\n", rf_info.DLBurstDataDIUC);
+	cm_printf("Frequency: %d\n", (int)rf_info.Frequency);
+
+	return 0;
+}
+
+static int cmd_get_link_status(int argc, char *argv[])
+{
+	WIMAX_API_LINK_STATUS_INFO LinkStatus;
+	GDEV_ID ID;
+
+	ID.apiHandle = cm_api_handle;
+	if (argc == 1)
+		ID.deviceIndex = DEFAULT_DEVICE;
+	else
+		ID.deviceIndex = atoi(argv[1]);
+
+	if (GAPI_GetLinkStatus(&ID, &LinkStatus) != GCT_API_RET_SUCCESS) {
+		cm_printf("Get link status fail\n");
+		return -1;
+	}
+
+	cm_printf("[RSSI] [CINR] [TX-PWR] [NAP-ID]\n");
+	cm_printf("%5d %6d %8d   %02X%02X%02X\n",
+		LinkStatus.RSSI-123,
+		LinkStatus.CINR-10,
+		(s8) (LinkStatus.txPWR/2-84),
+		LinkStatus.bsId[0], LinkStatus.bsId[1], LinkStatus.bsId[2]);
+
+	return refresh_rf_info(&ID);
+}
+
+static int cm_connect_net(int dev_idx, WIMAX_API_WSTRING nsp_name,
+	WIMAX_API_PROFILE_ID profileID)
+{
+	GDEV_ID ID;
+
+	ID.apiHandle = cm_api_handle;
+	ID.deviceIndex = dev_idx;
+	dev_conf_t *conf = &cm_dev_conf[dev_idx];
+
+	wcscpy((wchar_t*)conf->nsp_name16_before, (wchar_t*)conf->nsp_name16_current);
+
+	if (GAPI_CmdConnectToNetwork(&ID, nsp_name, profileID) != GCT_API_RET_SUCCESS) {
+		cm_eprintf("Connect failure\n");
+		return -1;
+	}
+
+	wcscpy((wchar_t*)conf->nsp_name16_current, (wchar_t*)nsp_name);
+
+	return ID.deviceIndex;
+}
+
+static int cmd_connect_net(int argc, char *argv[])
+{
+	u16 nsp_name16[MAX_SIZE_OF_NSP_NAME];
+	int dev_idx = DEFAULT_DEVICE;
+	WIMAX_API_PROFILE_ID profileID = 0;
+
+	if (argc < 2 && argc > 4) {
+		cm_eprintf("Invalid parameter.\n");
+		return -1;
+	}
+
+	if (argc > 2) {
+		if (strlen(argv[2]) <= 1)
+			dev_idx = atoi(argv[2]);
+		else {
+			profileID = strtoul(argv[2], NULL, 16);
+			if (argc == 4)
+				dev_idx = atoi(argv[3]);
+		}
+	}
+	mbstowcs((wchar_t*)nsp_name16, argv[1], strlen(argv[1])+1);
+
+	return cm_connect_net(dev_idx, (WIMAX_API_WSTRING)nsp_name16, profileID);
+}
+
+void cm_enable_auto_connet(int enable, int dev_idx)
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+	pconf->auto_connect_enable = enable;
+	if (enable)
+		cm_request_auto_connection(dev_idx);
+}
+
+static int cmd_auto_connect_net(int argc, char *argv[])
+{
+	int dev_idx = DEFAULT_DEVICE;
+	int enable = 0;
+
+	if (argc < 2) {
+invalid_param:
+		cm_eprintf("Invalid parameter\n");
+		return -1;
+	}
+	if (!strcasecmp(argv[1], "on"))
+		enable = 1;
+	else if (strcasecmp(argv[1], "off"))
+		goto invalid_param;
+
+	if (argc > 2)
+		dev_idx = atoi(argv[1]);
+
+	cm_enable_auto_connet(enable, dev_idx);
+	return dev_idx;
+}
+
+static WIMAX_API_NSP_INFO_P select_nsp(WIMAX_API_NSP_INFO_P nsp, int nsp_cnt)
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+	WIMAX_API_NSP_INFO_P mnsp;
+	WIMAX_API_NSP_INFO_P home, partner, rpartner;
+	UINT8 cinr = 0;
+	int i;
+
+	mnsp = nsp;
+	rpartner = partner = home = NULL;
+	for (i = 0; i < nsp_cnt; i++, nsp++) {
+		switch (nsp->networkType) {
+			case WIMAX_API_HOME:
+				if (!home)
+					home = nsp;
+				break;
+			case WIMAX_API_PARTNER:
+				if (!partner)
+					partner = nsp;
+				break;
+			case WIMAX_API_ROAMING_PARTNER:
+				if (!rpartner)
+					rpartner = nsp;
+				break;
+			case WIMAX_API_UNKNOWN:
+				if (nsp->CINR > cinr) {
+					cinr = nsp->CINR;
+					mnsp = nsp;
+				}
+				break;
+			default:
+				cm_printf("Unknown Network Type");
+				break;
+		}
+	}
+
+	if (home != NULL) {
+		cm_printf("HOME Operator %S is selected\n", (wchar_t *)home->NSPName);
+	   	return home;
+	}
+	if (partner != NULL) {
+		cm_printf("CAPL Operator %S is selected\n", (wchar_t *)partner->NSPName);
+	   	return partner;
+	}
+	if (rpartner != NULL) {
+		cm_printf("RAPL Operator %S is selected\n", (wchar_t *)rpartner->NSPName);
+	   	return rpartner;
+	}
+
+	if (pconf->unknown_net_auto_connect_enable) {
+		cm_printf("No known network is found, Selecting NSP with better CINR\n");
+		return mnsp;
+	}
+	else {
+		cm_printf("No known network is not selected!\n");
+		return NULL;
+	}
+}
+
+int cm_profiling_rf_up(int dev_idx)
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+	int profile_idx = pconf->auto_select_profile_index;
+	int ret;
+
+	if ((ret = cm_get_profile_list(dev_idx)) <= 0) {
+		cm_printf("There is no proile!\n");
+		goto out;
+	}
+
+	cm_printf("Profile index is %d\n", profile_idx);
+	if ((ret = cm_set_profile(dev_idx, profile_idx)) < 0)
+		goto out;
+
+	if ((ret = cm_rf_up(dev_idx)) < 0)
+		goto out;
+out:
+	return ret;
+}
+
+int cm_auto_connect(int dev_idx)
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+	WIMAX_API_NSP_INFO nsp[MAX_NETWORK_LIST], *selected_nsp = NULL;
+	WIMAX_API_PROFILE_ID profileID = 0;
+	int list_cnt, waiting_timeout_sec = NETWORK_LIST_TIMEOUT_SEC;
+	unsigned connect_retries = pconf->auto_connect_retry_count;
+	GDEV_ID ID;
+	WIMAX_API_DEVICE_STATUS DeviceStatus;
+	WIMAX_API_CONNECTION_PROGRESS_INFO ConnectionProgressInfo;
+	cm_msg_cb_t *msg_cb;
+	time_t start_time, cur_time;
+	int ret = -1;
+
+	msg_cb = &pconf->auto_conn_msg;
+	ID.apiHandle = cm_api_handle;
+	ID.deviceIndex = dev_idx;
+
+	if (waiting_timeout_sec == 0)
+		waiting_timeout_sec = 1;
+	if (connect_retries == 0)
+		connect_retries = 1;
+
+	if (GAPI_GetDeviceStatus(&ID, &DeviceStatus, &ConnectionProgressInfo)
+		!= GCT_API_RET_SUCCESS) {
+		cm_eprintf("GAPI_GetDeviceStatus Failure\n");
+		goto out;
+	}
+
+	if (DeviceStatus == WIMAX_API_DEVICE_STATUS_Connecting ||
+		DeviceStatus == WIMAX_API_DEVICE_STATUS_Data_Connected) {
+		cm_eprintf("DeviceStatus is not connectable state(%d)\n\n", DeviceStatus);
+		goto out;
+	}
+
+	if (cm_profiling_rf_up(dev_idx) <= 0)
+		goto out;
+
+get_net_list:
+	time(&start_time);
+	do {
+		sleep(1);
+		if (!pconf->auto_connect_enable)
+			goto out;
+		list_cnt = MAX_NETWORK_LIST;
+		if (cm_get_net_list(dev_idx, nsp, &list_cnt) < 0)
+			goto out;
+		time(&cur_time);
+		if (list_cnt == 0)
+			cm_printf("network list=%d (elapsed %dsec.)\n",
+				list_cnt, (unsigned)cur_time-(unsigned)start_time);
+		if (list_cnt) {
+			cm_print_net_list(nsp, list_cnt);
+			if ((selected_nsp = select_nsp(nsp, list_cnt)))
+				goto connect;
+		}
+	} while (--waiting_timeout_sec);
+
+	if (waiting_timeout_sec == 0) {
+		cm_eprintf("There is no scan list\n");
+		goto out;
+	}
+connect:
+	if (selected_nsp && pconf->auto_connect_enable) {
+		cm_printf("Connect to %S\n", (wchar_t *) selected_nsp->NSPName);
+		if (cm_connect_net(dev_idx, selected_nsp->NSPName, profileID) < 0) {
+			if (--connect_retries)
+				goto get_net_list;
+			ret = -1;
+		}
+		ret = 0;
+	}
+out:
+	cm_printf("Auto connect done\n");
+	return ret;
+}
+
+int cm_disconnect_net(int dev_idx)
+{
+	GDEV_ID ID;
+
+	ID.apiHandle = cm_api_handle;
+	ID.deviceIndex = dev_idx;
+
+	if (GAPI_CmdDisconnectFromNetwork(&ID) != GCT_API_RET_SUCCESS) {
+		cm_printf("Disconnect failure\n");
+		return -1;
+	}
+
+	return ID.deviceIndex;
+}
+
+static int cmd_disconnect_net(int argc, char *argv[])
+{
+	int dev_idx;
+
+	if (argc == 1)
+		dev_idx = DEFAULT_DEVICE;
+	else
+		dev_idx = atoi(argv[1]);
+
+	return cm_disconnect_net(dev_idx);
+}
+
+static int cmd_set_autoscan_interval(int argc, char *argv[])
+{
+	GDEV_ID ID;
+	int interval_sec;
+
+	if (argc < 2) {
+		cm_printf("Command usage: %s interval(second)\n", argv[0]);
+		return -1;
+	}
+
+	interval_sec = atoi(argv[1]);
+
+	ID.apiHandle = cm_api_handle;
+	if (argc == 2)
+		ID.deviceIndex = DEFAULT_DEVICE;
+	else
+		ID.deviceIndex = atoi(argv[1]);
+
+	if (GAPI_SetScanInterval(&ID, interval_sec) != GCT_API_RET_SUCCESS) {
+		cm_printf("Setting Scan-Interval failure!\n");
+		return -1;
+	}
+	else
+		cm_printf("Set autoscan interval(%d second)\n", interval_sec);
+
+	return ID.deviceIndex;
+}
+
+static int cmd_scan(int argc, char *argv[])
+{
+	GDEV_ID ID;
+	int scan_mode;
+	GCT_API_SCAN_TYPE type;
+	#define WIDE_SCAN			0
+	#define ALL_SUBS_SCAN		1
+	#define CURR_SUBS_SCAN		2
+	const char *scan_type = NULL;
+
+	if (argc < 2 || (scan_mode = atoi(argv[1])) > CURR_SUBS_SCAN) {
+		cm_printf("Command usage: %s scan-mode\n"
+			"                       scan-mode 0: wide scan\n"
+			"                       scan-mode 1: all subscriptions scan\n"
+			"                       scan-mode 2: current subscription scan\n", argv[0]);
+		return -1;
+	}
+
+	ID.apiHandle = cm_api_handle;
+	if (argc == 2)
+		ID.deviceIndex = DEFAULT_DEVICE;
+	else
+		ID.deviceIndex = atoi(argv[2]);
+
+	if (scan_mode == WIDE_SCAN) {
+		type = GCT_API_SCAN_WIDE;
+		scan_type = "wide";
+	}
+	else if (scan_mode == ALL_SUBS_SCAN) {
+		type = GCT_API_SCAN_ALL_SUBSCRIPTIONS;
+		scan_type = "all subscriptions";
+	}
+	else {
+		type = GCT_API_SCAN_CURR_SUBSCRIPTION;
+		scan_type = "current subscription";
+	}
+
+	if (GAPI_NetworkSearchScan(&ID, type) != GCT_API_RET_SUCCESS) {
+		cm_printf("Scaning network failure\n");
+		return -1;
+	}
+	else
+		cm_printf("Request %s scan!\n", scan_type);
+
+	return ID.deviceIndex;
+}
+
+static int cmd_auth(int argc, char *argv[])
+{
+	cm_printf("This command is not used no more.\n");
+	cm_printf("Authentication will be automatically set according to cm.conf configuration.\n");
+	return 0;
+}
+
+static int cmd_delete_cert(int argc, char *argv[])
+{
+	cm_printf("%s: not supported!\n", __func__);
+		return -1;
+	}
+
+static int cmd_get_cert_status(int argc, char *argv[])
+{
+	cm_printf("%s: not supported!\n", __func__);
+		return -1;
+	}
+
+static int cmd_get_cert_mask(int argc, char *argv[])
+{
+	cm_printf("%s: not supported!\n", __func__);
+		return -1;
+	}
+
+static int cmd_set_cert_mask(int argc, char *argv[])
+{
+	cm_printf("%s: not supported!\n", __func__);
+		return -1;
+	}
+
+static int cmd_get_cert_info(int argc, char *argv[])
+{
+	cm_printf("%s: not supported!\n", __func__);
+		return -1;
+	}
+
+static int cmd_debug_level(int argc, char *argv[])
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+	int level, prev_level;
+
+	if (argc < 2) {
+		cm_printf("Invalid parameter.\n");
+		return -1;
+	}
+
+	level = atoi(argv[1]);
+
+	if (GAPI_SetDebugLevel(cm_api_handle, level, &prev_level) != GCT_API_RET_SUCCESS) {
+		cm_printf("Debug level failure\n");
+		return -1;
+	}
+	if (level != GAPI_LOG_FLUSH_LEVEL)
+		pconf->log_level = level;
+	return get_first_odev();
+}
+
+static int cmd_help(int argc, char *argv[])
+{
+	if (argc == 2)
+		print_cmd_list(argv[1]);
+	else
+		print_cmd_list(NULL);
+	return 0;
+}
+
+static void request_dm_prompt(void)
+{
+	GDEV_ID ID;
+
+	ID.apiHandle = cm_api_handle;
+	ID.deviceIndex = get_first_odev();
+
+	if (ID.deviceIndex)
+		send_print_string(&ID, "\n", 1);
+}
+
+static void do_shell(const char *shell)
+{
+	#define DISABLE_SIGINT
+	pid_t pid;
+	int status, i;
+	#if defined(DISABLE_SIGINT)
+	struct sigaction act, oldact;
+
+	memset(&act, 0, sizeof(act));
+	act.sa_handler = SIG_IGN;
+	sigaction(SIGINT, &act, &oldact);
+	#endif
+
+	pid = fork();
+	if (pid == 0) {
+		/*Close all FDs*/
+		for (i = 3; i < 64; i++)
+			close(i);
+		#if defined(DISABLE_SIGINT)
+		sigaction(SIGINT, &oldact, NULL);
+		#endif
+		/* Invokes a shell */
+		execl(shell, shell, NULL);
+		cm_eprintf("execl failed\n");
+		exit(1);
+	}
+	else if (pid != -1) {
+		waitpid(pid, &status, 0);
+		#if defined(DISABLE_SIGINT)
+		sigaction(SIGINT, &oldact, NULL);
+		#endif
+		if ((!WIFEXITED(status) || WEXITSTATUS(status)))
+			cm_printf("waitpid: status=%d\n", WEXITSTATUS(status));
+		request_dm_prompt();
+	}
+	else
+		cm_eprintf("fork failed\n");
+}
+
+static int cmd_shell(int argc, char *argv[])
+{
+	#define MY_SHELL	"/bin/sh"
+
+	do_shell(MY_SHELL);
+	return 0;
+}
+
+static int cmd_exit(int argc, char *argv[])
+{
+	return EXIT_CM_CMD;
+}
+
+static void cmd_init_event(int dev_idx)
+{
+	sem_init(&hci_data_sem[dev_idx], 0);
+}
+
+static char *cmd_wait_event(int dev_idx, unsigned short event, int second, int *len)
+{
+	int ret;
+
+	ret = sem_timedwait(&hci_data_sem[dev_idx], second);
+	if (ret) {
+		cm_printf("Event(0x%04X) time out(%d)\n", event, ret);
+		return NULL;
+	}
+
+	if (len)
+		*len = hci_data[dev_idx].len;
+	return hci_data[dev_idx].data;
+}
+
+void cmd_signal_event(int dev_idx, unsigned short event, char *data, int len)
+{
+	memcpy(hci_data[dev_idx].data, data, len);
+	hci_data[dev_idx].len = len;
+	sem_signal(&hci_data_sem[dev_idx]);
+}
+
+#define HCI_FILE_BUF_CHUNK	1024
+
+static int check_file_arg(int argc, char *file)
+{
+	if (argc < 3) {
+		cm_printf("Invalid parameter.\n");
+		return -1;
+	}
+
+	if (file && access(file, 0)) {
+		cm_printf("%s is not found\n", file);
+		return -1;
+	}
+
+	return 0;
+}
+
+int cm_read_fw_file(GDEV_ID_P pID, char *host_file, char *target_file)
+{
+	int dev_idx = pID->deviceIndex;
+	char hci_buf[HCI_MAX_PACKET];
+	hci_t *hci = (hci_t *) hci_buf;
+	int hci_length;
+	hci_file_response_t *rsp;
+	hci_file_read_t *p = (hci_file_read_t *) hci->data;
+	int len;
+	unsigned offset = 0;
+	int fd, ret = -1;
+
+	if ((fd = open(host_file, O_CREAT|O_WRONLY|O_TRUNC, 0644)) < 0) {
+		cm_printf("Open failed, %s, %s(%d)\n", host_file, strerror(errno), errno);
+		return -1;
+	}
+
+	hci->cmd_evt = _H2B(WIMAX_READ_FILE);
+	strcpy(p->path, target_file);
+	hci_length = HCI_HEADER_SIZE + sizeof(hci_file_read_t) + strlen(p->path) + 1;
+	hci->length = _H2B(hci_length-HCI_HEADER_SIZE);
+
+	cmd_init_event(dev_idx);
+
+	while (1) {
+		p->offset = _DH2B(offset);
+
+		if (GAPI_WriteHCIPacket(pID, hci_buf, hci_length) != GCT_API_RET_SUCCESS) {
+			cm_printf("Write HCI failed! (Reading %s)\n", target_file);
+			goto out;
+		}
+
+		rsp = (hci_file_response_t *) cmd_wait_event(dev_idx, WIMAX_FILE_RESULT, 5, NULL);
+		if (!rsp)
+			break;
+		
+		ret = _DB2H(rsp->result);
+		if (!ret)
+			break;
+		if (ret < 0) {
+			cm_printf("Read file failed(%d)\n", ret);
+			break;
+		}
+		len = write(fd, file_response_data(rsp), ret);
+		if (len <= 0) {
+			cm_printf("Write failed, %s, %s(%d)\n", host_file, strerror(errno), errno);
+			ret = -1;
+			break;
+		}
+		offset += ret;
+		if (len < ret)
+			lseek(fd, offset, SEEK_SET);
+	}
+
+	if (!ret)
+		cm_printf("\t%s <= %s\n", host_file, target_file);
+out:
+	close(fd);
+	return pID->deviceIndex;
+}
+
+static int cmd_read_file(int argc, char *argv[])
+{
+	GDEV_ID ID;
+	char *host_file = argv[1];
+	char *target_file = argv[2];
+
+	if (check_file_arg(argc, NULL) < 0)
+		return -1;
+
+	ID.apiHandle = cm_api_handle;
+	ID.deviceIndex = (argc == 4 ? atoi(argv[3]) : DEFAULT_DEVICE);
+
+	return cm_read_fw_file(&ID, host_file, target_file);
+}
+
+static int cmd_write_file(int argc, char *argv[])
+{
+	GDEV_ID ID;
+	int dev_idx;
+	char hci_buf[HCI_MAX_PACKET];
+	hci_t *hci = (hci_t *) hci_buf;
+	int fix_length, hci_length;
+	hci_file_response_t *rsp;
+	hci_file_write_t *p = (hci_file_write_t *) hci->data;
+	char *buf;
+	int buf_size = HCI_FILE_BUF_CHUNK;
+	int len;
+	unsigned offset = 0, total;
+	char *host_file = argv[1];
+	char *target_file = argv[2];
+	int fd, ret = -1;
+
+	if (check_file_arg(argc, host_file) < 0)
+		return -1;
+
+	ID.apiHandle = cm_api_handle;
+	ID.deviceIndex = dev_idx = (argc == 4 ? atoi(argv[3]) : DEFAULT_DEVICE);
+
+	if ((fd = open(host_file, O_RDONLY)) < 0) {
+		cm_printf("Open failed, %s, %s(%d)\n", host_file, strerror(errno), errno);
+		return -1;
+	}
+
+	total = lseek(fd, 0, SEEK_END);
+	lseek(fd, 0, SEEK_SET);
+
+	hci->cmd_evt = _H2B(WIMAX_WRITE_FILE);
+	strcpy(p->path, target_file);
+	p->path_len = strlen(p->path) + 1;
+	fix_length = sizeof(hci_file_write_t) + p->path_len;
+	buf = hci_file_data(p);
+	p->path_len = _H2B(p->path_len);
+
+	cmd_init_event(dev_idx);
+	
+	while ((len = read(fd, buf, buf_size)) > 0) {
+		p->offset = _DH2B(offset);
+		hci->length = _H2B(fix_length + len);
+		hci_length = HCI_HEADER_SIZE + fix_length + len;
+
+		if (GAPI_WriteHCIPacket(&ID, hci_buf, hci_length) != GCT_API_RET_SUCCESS) {
+			cm_printf("Write-HCI failed\n");
+			goto out;
+		}
+
+		rsp = (hci_file_response_t *) cmd_wait_event(dev_idx, WIMAX_FILE_RESULT, 5, NULL);
+		if (!rsp)
+			break;
+		
+		ret = _DB2H(rsp->result);
+		if (!ret)
+			break;
+		if (ret < 0) {
+			cm_printf("Write-file failed(%d)\n", ret);
+			break;
+		}
+		offset += ret;
+		if (len > ret)
+			lseek(fd, offset, SEEK_SET);
+	}
+
+	if (len < 0)
+		cm_printf("Read failed, %s, %s(%d)\n", host_file, strerror(errno), errno);
+	else {
+		/*Notify EOF*/
+		p->offset = _DH2B(EOF_OFFSET);
+		hci->length = _H2B(fix_length);
+		hci_length = HCI_HEADER_SIZE + fix_length;
+
+		if (GAPI_WriteHCIPacket(&ID, hci_buf, hci_length) != GCT_API_RET_SUCCESS) {
+			cm_printf("Write-HCI failed\n");
+			return -1;
+		}
+
+		rsp = (hci_file_response_t *) cmd_wait_event(dev_idx, WIMAX_FILE_RESULT, 5, NULL);
+		if (rsp) {
+			ret = _DB2H(rsp->result);
+			if (ret < 0)
+				cm_printf("Write-file failed(%d)\n", ret);
+		}
+
+		if (total == offset)
+			cm_printf("\t%s => %s\n", host_file, target_file);
+		else
+			cm_printf("\tWrite-file mismatch(%d!=%d)\n", total, offset);
+	}
+out:
+	close(fd);
+	return ID.deviceIndex;
+}
+
+static int cmd_delete_file(int argc, char *argv[])
+{
+	GDEV_ID ID;
+	int dev_idx;
+	char hci_buf[HCI_MAX_PACKET];
+	hci_t *hci = (hci_t *) hci_buf;
+	int hci_length;
+	hci_file_response_t *rsp;
+	hci_file_delete_t *p = (hci_file_delete_t *) hci->data;
+	char *target_file = argv[1];
+	int path_len;
+	int ret = -1;
+
+	ID.apiHandle = cm_api_handle;
+	ID.deviceIndex = dev_idx = (argc == 4 ? atoi(argv[3]) : DEFAULT_DEVICE);
+
+	hci->cmd_evt = _H2B(WIMAX_DELETE_FILE);
+	strcpy(p->path, target_file);
+	path_len = strlen(p->path) + 1;
+	hci_length = sizeof(hci_file_delete_t) + path_len;
+	hci->length = _H2B(hci_length);
+	hci_length +=HCI_HEADER_SIZE;
+
+	cmd_init_event(dev_idx);
+
+	if (GAPI_WriteHCIPacket(&ID, hci_buf, hci_length) != GCT_API_RET_SUCCESS) {
+		cm_printf("Write-HCI failed\n");
+		return -1;
+	}
+
+	rsp = (hci_file_response_t *) cmd_wait_event(dev_idx, WIMAX_FILE_RESULT, 5, NULL);
+	if (rsp) {
+		ret = _DB2H(rsp->result);
+		if (ret < 0)
+			cm_printf("Delete-file failed(%d)\n", ret);
+		else
+			cm_printf("\t%s deleted\n", target_file);
+	}
+
+	return ID.deviceIndex;
+}
+
+static int read_image(GDEV_ID_P pID, int type, const char *file)
+{
+	cm_printf("%s: not supported!\n", __func__);
+			return -1;
+		}
+
+static int cmd_read_image(int argc, char *argv[])
+{
+	GDEV_ID ID;
+	int type;
+	char *file;
+	int ret;
+
+	type = strtoul(argv[1], NULL, 0);
+	file = argv[2];
+
+	ID.apiHandle = cm_api_handle;
+	ID.deviceIndex = (argc == 4 ? atoi(argv[3]) : DEFAULT_DEVICE);
+
+	switch (type) {
+		case DLIMG_BL_EEPROM:
+		case DLIMG_OMA_XML:
+		case DLIMG_DEV_CERT:
+		case DLIMG_CERT1_U:
+		case DLIMG_CERT1_L:
+		case DLIMG_CERT2_U:
+		case DLIMG_CERT_BIG:
+			break;
+		default:
+			cm_printf("0x%x is unknown type\n", type);
+			return 0;
+			break;
+	}
+
+	ret = read_image(&ID, type, file);
+	if (ret >= 0)
+		ret = ID.deviceIndex;
+	return ret;
+}
+
+static int cmd_write_image(int argc, char *argv[])
+{
+	cm_printf("%s: not supported!\n", __func__);
+		return -1;
+	}
+
+static int control_image(GDEV_ID_P pID, int type, int cmd, void *buffer, int length)
+{
+	int dev_idx = pID->deviceIndex;
+	char hci_buf[HCI_MAX_PACKET];
+	hci_t *hci = (hci_t *) hci_buf;
+	int hci_length;
+	int data_len = 0, len;
+	hci_image_cmd_t *p = (hci_image_cmd_t *) hci->data;
+	hci_image_cmd_result_t *rsp;
+	int ret = 0;
+	
+	hci->cmd_evt = _H2B(WIMAX_IMAGE_CMD);
+	hci_length = sizeof(*p);
+	hci->length = _H2B(hci_length);
+	p->cmd = _H2B(cmd);
+	p->type = _H2B(type);
+
+	cm_dprintf("cmd=%d, type=0x%x\n", cmd, type);
+
+	hci_length += HCI_HEADER_SIZE;
+	if (GAPI_WriteHCIPacket(pID, hci_buf, hci_length) != GCT_API_RET_SUCCESS) {
+		cm_printf("Write-HCI failed\n");
+		ret = -1;
+		goto out;
+	}
+
+	rsp = (hci_image_cmd_result_t *) cmd_wait_event(dev_idx, WIMAX_IMAGE_CMD_STATUS,
+		3, &data_len);
+	if (!rsp) {
+		ret = -1;
+		goto out;
+	}
+
+	ret = _DB2H(rsp->status);
+	if (ret) {
+		if (cmd == ICMD_GET_SIZE) {
+			if (buffer)
+				memcpy(buffer, &rsp->status, sizeof(rsp->status));
+			ret = 0;
+		}
+		else {
+			cm_printf("Image result failed(%d)\n", ret);
+			ret = -1;
+			goto out;
+		}
+	}
+	else if ((len = data_len-sizeof(hci_image_cmd_result_t))) {
+		if (len > length)  {
+			cm_eprintf("Buffer length is too small(%d)\n", length);
+			ret = -1;
+		}
+		else if (buffer)
+			memcpy(buffer, rsp->data, len);
+	}
+out:
+	return ret;
+}
+
+static int cmd_control_image(int argc, char *argv[])
+{
+	GDEV_ID ID;
+	int type, cmd;
+	char buffer[16];
+	int ret;
+
+	if (argc < 3) {
+		cm_eprintf("Invalid parameter\n");
+		return 0;
+	}
+
+	type = strtoul(argv[1], NULL, 0);
+	cmd = strtoul(argv[2], NULL, 0);
+
+	ID.apiHandle = cm_api_handle;
+	ID.deviceIndex = (argc == 4 ? atoi(argv[3]) : DEFAULT_DEVICE);
+
+	switch (type) {
+		case DLIMG_DEV_CERT:
+		case DLIMG_CERT1_U:
+		case DLIMG_CERT1_L:
+		case DLIMG_CERT2_U:
+		case DLIMG_EAP_PARAM:
+		case DLIMG_CERT_BIG:
+			break;
+		default:
+			cm_printf("0x%x is unknown type\n", type);
+			goto out;
+	}
+
+	if (cmd == ICMD_INVALIDATE) {
+		cm_printf("0x%x will be deleted! Are you sure (y/n) ? ", type);
+		if (!fgets(buffer, sizeof(buffer), stdin)) {
+			cm_eprintf("fgets error: %s(%d)\n", strerror(errno), errno);
+			goto out;
+		}
+		if (buffer[0] != 'y')
+			goto out;
+	}
+
+	ret = control_image(&ID, type, cmd, buffer, sizeof(buffer));
+	if (!ret) {
+		switch (cmd) {
+			case ICMD_INVALIDATE:
+				cm_printf("Type(0x%x) Deleted!\n", type);
+				break;
+			case ICMD_GET_SIZE:
+				cm_printf("Type(0x%x) Size: %u.\n", type, _U82U32(buffer));
+				break;
+			case ICMD_GET_CRC32:
+				cm_printf("Type(0x%x) CRC32: 0x%x.\n", type, _U82U32(buffer));
+				break;
+		}
+	}
+out:
+	return ID.deviceIndex;
+}
+
+static int read_param_block(GDEV_ID_P pID, void *buf, int offset, int length)
+{
+	int dev_idx = pID->deviceIndex;
+	char hci_buf[HCI_MAX_PACKET];
+	hci_t *hci = (hci_t *) hci_buf;
+	int hci_length;
+	int data_len = 0;
+	hci_image_payload_t *p = (hci_image_payload_t *) hci->data;
+	int ret = 0;
+
+	cmd_init_event(dev_idx);
+	
+	hci->cmd_evt = _H2B(WIMAX_UL_IMAGE);
+	hci->length = _H2B(sizeof(*p));
+	hci_length = HCI_HEADER_SIZE + sizeof(*p);
+	p->type = _H2B(DLIMG_CFG);
+	p->offset = _DH2B(offset);
+
+	if (GAPI_WriteHCIPacket(pID, hci_buf, hci_length) != GCT_API_RET_SUCCESS) {
+		cm_printf("Write-HCI failed\n");
+		ret = -1;
+		goto out;
+	}
+
+	p = (hci_image_payload_t *) cmd_wait_event(dev_idx, WIMAX_UL_IMAGE_RESULT, 5, &data_len);
+	if (!p) {
+		ret = -1;
+		goto out;
+	}
+
+	if (data_len != sizeof(hci_image_payload_t)+length) {
+		cm_printf("Length mismatch(%d!=%d)\n", data_len, length);
+		ret = -1;
+		goto out;
+	}
+
+	memcpy(buf, p->data, data_len);
+
+out:
+	return ret;
+}
+
+static int write_param_block(GDEV_ID_P pID, void *buf, int offset, int length)
+{
+	int dev_idx = pID->deviceIndex;
+	char hci_buf[HCI_MAX_PACKET];
+	hci_t *hci = (hci_t *) hci_buf;
+	int hci_length;
+	int data_len = 0;
+	hci_image_payload_t *p = (hci_image_payload_t *) hci->data;
+	hci_image_response_t *rsp;
+	int ret = 0;
+
+	cmd_init_event(dev_idx);
+	
+	hci->cmd_evt = _H2B(WIMAX_DL_IMAGE);
+	hci_length = sizeof(*p) + length;
+	hci->length = _H2B(hci_length);
+	p->type = _H2B(DLIMG_CFG);
+	p->offset = _DH2B(offset);
+	memcpy(p->data, buf, length);
+
+	hci_length += HCI_HEADER_SIZE;
+	if (GAPI_WriteHCIPacket(pID, hci_buf, hci_length) != GCT_API_RET_SUCCESS) {
+		cm_printf("Write-HCI failed\n");
+		ret = -1;
+		goto out;
+	}
+
+	rsp = (hci_image_response_t *) cmd_wait_event(dev_idx, WIMAX_DL_IMAGE_STATUS, 5, &data_len);
+	if (!rsp) {
+		ret = -1;
+		goto out;
+	}
+
+	ret = _DB2H(rsp->result);
+	if (ret) {
+		cm_printf("Image result failed(%d)\n", ret);
+		ret = -1;
+		goto out;
+	}
+
+out:
+	return ret;
+}
+
+static const char nv_param_usage[] = "<operation> [opeion]"
+								"\n            <operation>"
+								"\n              w.info	Write NV info block parameters to NVRAM."
+								"\n              v.info	Print NV info block parameters."
+								"\n              [options]"
+								"\n                macaddr [6 bytes hex digits (Mac Address)]";
+
+static int is_valid_mac(char *mac)
+{
+	return (!(mac[0] & 0x1)
+			&& (mac[0] | mac[1] | mac[2] | mac[3] | mac[4] | mac[5])
+		   );
+}
+
+static int cmd_nv_param(int argc, char *argv[])
+{
+	GDEV_ID ID;
+	char buf[HCI_MAX_PACKET];
+	char *operation = argv[1];
+	char *param = argv[2];
+	char *value = argv[3];
+	int is_invalid_block = 0;
+	int i, ret = -1;
+
+	if (argc < 2)
+		return -1;
+
+	ID.apiHandle = cm_api_handle;
+	ID.deviceIndex = 1; /*Support for only single device.*/
+	
+	if (!strcasecmp(operation, "w.info") || !strcasecmp(operation, "v.info")) {
+		struct wb_info_block_v2 *info = (struct wb_info_block_v2 *) buf;
+		ret = read_param_block(&ID, buf, WB_INFO_BLOCK_OFFSET_V2, sizeof(*info));
+		if (ret < 0)
+			goto out;
+
+		if (_H2B(info->magic) != MAGIC || info->version != MAP_VERSION_V2)
+			is_invalid_block = 1;
+
+		if (!strcasecmp(operation, "v.info")) {
+			if (is_invalid_block) {
+				cm_printf("Info block is invalid(MAGIC:0x%04X, Version:%d)\n",
+					_H2B(info->magic), info->version);
+				goto out;
+			}
+			if (!strcasecmp(param, "macaddr")) {
+				unsigned char *p = info->mac_address;
+				cm_printf("%02X:%02X:%02X:%02X:%02X:%02X\n", p[0], p[1], p[2], p[3], p[4], p[5]);
+				goto out;
+			}
+			goto err;
+		}
+		else if (!strcasecmp(operation, "w.info")) {
+			if (is_invalid_block) {
+				memset(info, 0, sizeof(*info));
+				info->magic = _H2B(MAGIC);
+				info->version = MAP_VERSION_V2;
+			}
+
+			if (!strcasecmp(param, "macaddr")) {
+				char mac[6], ch[3] = {0};
+
+				if (strlen(value) != 12)
+					goto err;
+
+				for (i = 0; i < 6; i++) {
+					memcpy(ch, value + 2 * i, 2);
+					mac[i] = strtoul(ch, NULL, 16);
+				}
+				if (!is_valid_mac(mac)) {
+					cm_printf("Invalid MAC address\n");
+					goto out;
+				}
+				memcpy((char *) info->mac_address, mac, 6);
+			}
+			else
+				goto err;
+
+			ret = write_param_block(&ID, buf, WB_INFO_BLOCK_OFFSET_V2, sizeof(*info));
+			if (!ret)
+				cm_printf("Writing is success!\n");
+			goto out;
+		}
+	}
+
+err:
+	print_cmd_usage(argv[0]);
+
+out:
+	return ret;
+}
+
+static int run_script(int dev_idx, const char *scr_file)
+{
+	#define IS_COMMENT(ch)		((ch)=='#' || (ch)=='\n')
+	GDEV_ID ID;
+	char file[256];
+	FILE *fp;
+	char buf[1024];
+	int ret, readn;
+
+	if (strstr(scr_file, ".scr"))
+		strcpy(file, scr_file);
+	else
+		sprintf(file, "%s.scr", scr_file);
+
+	ID.apiHandle = cm_api_handle;
+	ret = ID.deviceIndex = dev_idx;
+
+	if (!(fp = fopen(file, "rt"))) {
+		cm_eprintf("fopen(%s) failed!\n", file);
+		return -1;
+	}
+
+	cm_printf("Begin script(%s)\n", file);
+
+	while (fgets(buf, sizeof(buf), fp)) {
+		readn = strlen(buf);
+		if (IS_COMMENT(*buf))
+			continue;
+		cm_printf("%s", buf);
+		if ((ret = do_cmd(buf, readn)) == NO_CM_CMD)
+			ret = send_print_string(&ID, buf, readn);
+	}
+	cm_printf("End script(%s)\n", file);
+
+	fclose(fp);
+	return ret;
+}
+
+static int cmd_script(int argc, char *argv[])
+{
+	int ret, dev_idx;
+
+	dev_idx = (argc == 3 ? atoi(argv[2]) : DEFAULT_DEVICE);
+	ret = run_script(dev_idx, argv[1]);
+	return ret;
+}
+
+static int cmd_date(int argc, char *argv[])
+{
+	cm_printf("NOW: %s\n", cm_get_cur_date());
+	return 1;
+}
+
+static int cmd_sleep(int argc, char *argv[])
+{
+	int second;
+
+	second = (argc == 2 ? atoi(argv[1]) : 1);
+	cm_printf("Sleep %d...\n", second);
+	sleep(second);
+
+	return 1;
+}
+
+#define MALLOC_CHECK
+#if defined(MALLOC_CHECK)
+#include <malloc.h>
+static void malloc_check(void)
+{
+	static struct mallinfo mem_info_st;
+	struct mallinfo mem_info;
+
+	mem_info = mallinfo();
+
+	if (!memcmp(&mem_info_st, &mem_info, sizeof(struct mallinfo))) {
+		cm_printf("#malloc status has not been chagned#\n");
+	}
+	else {
+		memcpy(&mem_info_st, &mem_info, sizeof(struct mallinfo));
+		cm_printf("(%d) This is the total size of memory allocated with sbrk by malloc, in bytes.\n", mem_info.arena);
+		cm_printf("(%d) This is the number of chunks not in use.\n", mem_info.ordblks);
+		cm_printf("(%d) This field is unused.\n", mem_info.smblks);
+		cm_printf("(%d) This is the total number of chunks allocated with mmap.\n", mem_info.hblks);
+		cm_printf("(%d) This is the total size of memory allocated with mmap, in bytes.\n", mem_info.hblkhd);
+		cm_printf("(%d) This field is unused.\n", mem_info.usmblks);
+		cm_printf("(%d) This field is unused.\n", mem_info.fsmblks);
+	}
+	cm_printf("(%d) This is the total size of memory occupied by chunks handed out by malloc.\n", mem_info.uordblks);
+	cm_printf("(%d) This is the total size of memory occupied by free (not in use) chunks.\n", mem_info.fordblks);
+	cm_printf("(%d) This is the size of the top-most releasable chunk that normally borders the end of the heap.\n", mem_info.keepcost);
+}
+#endif
+
+static int cmd_chk(int argc, char *argv[])
+{
+	GDEV_ID ID;
+	int ret;
+
+	ID.apiHandle = cm_api_handle;
+	ret = ID.deviceIndex = (argc == 2 ? atoi(argv[1]) : DEFAULT_DEVICE);
+
+	#if defined(MALLOC_CHECK)
+	malloc_check();
+	#endif
+
+	return ret;
+}
+
+static int cmd_test(int argc, char *argv[])
+{
+	GDEV_ID ID;
+	int ret;
+
+	ID.apiHandle = cm_api_handle;
+	ret = ID.deviceIndex = (argc == 2 ? atoi(argv[1]) : DEFAULT_DEVICE);
+
+	return ID.deviceIndex;
+}
+
+static int cmd_get_statistics(int argc, char *argv[])
+{
+	GDEV_ID ID;
+	WIMAX_API_CONNECTION_STAT stat;
+	int ret;
+
+	ID.apiHandle = cm_api_handle;
+	ret = ID.deviceIndex = (argc == 2 ? atoi(argv[1]) : DEFAULT_DEVICE);
+
+	if (GAPI_GetStatistics(&ID, &stat) == GCT_API_RET_SUCCESS) {
+		cm_printf("\tTotal Rx Byte: %u\n", stat.totalRxByte);
+		cm_printf("\tTotal Tx Byte: %u\n", stat.totalTxByte);
+		cm_printf("\tTotal Rx Packets: %u\n", stat.totalRxPackets);
+		cm_printf("\tTotal Tx Packets: %u\n", stat.totalTxPackets);
+	}
+	else
+		cm_eprintf("GAPI_GetStatistics failed\n");
+
+	return ID.deviceIndex;
+}
+
+static int cm_uicc_power(int dev_idx, int on)
+{
+	GDEV_ID ID;
+	char hci_buf[HCI_MAX_PACKET];
+	hci_t *hci = (hci_t *) hci_buf;
+	int len;
+
+	ID.apiHandle = cm_api_handle;
+	ID.deviceIndex = dev_idx;
+
+	hci->cmd_evt = _H2B(WIMAX_UICC_CMD);
+	len = HCI_HEADER_SIZE;
+
+	if (on) {
+		hci->data[0] = UICC_CMD_POWER_UP;
+		len += 1;
+		cm_printf("uicc on\n");
+	}
+	else {
+		hci->data[0] = UICC_CMD_POWER_DOWN;
+		len += 1;
+		cm_printf("uicc off\n");
+	}
+	hci->length = _H2B(len-HCI_HEADER_SIZE);
+
+	if (GAPI_WriteHCIPacket(&ID, hci_buf, HCI_HEADER_SIZE+len) != GCT_API_RET_SUCCESS) {
+		cm_printf("Write HCI failure\n");
+		return -1;
+	}
+	return ID.deviceIndex;
+}
+
+static int cmd_uicc(int argc, char *argv[])
+{
+	int dev_idx;
+	int ret = -1;
+	
+	dev_idx = (argc == 2 ? atoi(argv[1]) : DEFAULT_DEVICE);
+
+	if (!strcmp(argv[1], "on"))
+		ret = cm_uicc_power(DEFAULT_DEVICE, 1);
+	else if (!strcmp(argv[1], "off"))
+		ret = cm_uicc_power(DEFAULT_DEVICE, 0);
+	else {
+		cm_eprintf("Not supported command: %s\n", argv[1]);
+		ret = -1;
+	}
+	return ret;
+}
+
+#if defined(CONFIG_DM_INTERFACE)
+static int cmd_dmif(int argc, char *argv[])
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+	GDEV_ID ID;
+	WIMAX_API_PROFILE_INFO profile;
+	int ret, enabled = 0, profile_cnt = 1;
+
+	if (argc < 2) {
+invalid_param:
+		cm_printf("Invalid parameter\n");
+		return -1;
+	}
+
+	if (pconf->api_mode == GCT_WIMAX_API_PRIVILEGE_READ_ONLY) {
+		cm_eprintf("Permission denied\n");
+		return -1;
+	}
+
+	if (!strcasecmp(argv[1], "on"))
+		enabled = 1;
+	else if (strcasecmp(argv[1], "off"))
+		goto invalid_param;
+
+	ID.apiHandle = cm_api_handle;
+	ret = ID.deviceIndex = (argc == 3? atoi(argv[2]) : DEFAULT_DEVICE);
+
+	if (enabled) {
+		if (pconf->dm_interface_enable) {
+			cm_printf("DM Interface has been enabled already!\n");
+			goto out;
+		}
+		if (dmif_init() < 0) {
+			ret = -1;
+			goto out;
+		}
+		pconf->dm_interface_enable = 1;
+		
+		if (GAPI_CmdControlPowerManagement(&ID, WIMAX_API_RF_ON) != GCT_API_RET_SUCCESS) {
+			cm_printf("device[%d] rf up failure\n", ID.deviceIndex);
+			ret = -1;
+			goto out;
+		}
+
+		if (GAPI_GetSelectProfileList(&ID, &profile, (UINT32 *) &profile_cnt)
+			!= GCT_API_RET_SUCCESS) {
+			cm_printf("Get profile failure\n");
+			ret = -1;
+			goto out;
+		}
+		
+		if (GAPI_SetProfile(&ID, profile.profileID) != GCT_API_RET_SUCCESS ) {
+			cm_printf("Set profile failure\n");
+			ret = -1;
+			goto out;
+		}
+	}
+	else {
+		pconf->dm_interface_enable = 0;
+		if (dmif_deinit() < 0)
+			ret = -1;
+	}
+out:
+	return ret;
+}
+#endif
+
+#if defined(CONFIG_ENABLE_SERVICE_FLOW)
+#include <arpa/inet.h>
+static int cmd_gsf(int argc, char *argv[])
+{
+	GDEV_ID ID;
+	WIMAX_API_DEVICE_STATUS DeviceStatus;
+	WIMAX_API_CONNECTION_PROGRESS_INFO ConnectionProgressInfo;
+	WIMAX_SERVICE_FLOW *pServiceFlow;
+	WIMAX_CLFR_RULE *pCrRule;
+	WIMAX_PHS_RULE *pPhsRule;	
+	int count;
+	int ret;
+
+	ID.apiHandle = cm_api_handle;
+	ret = ID.deviceIndex = (argc == 2 ? atoi(argv[1]) : DEFAULT_DEVICE);
+
+	if (GAPI_GetDeviceStatus(&ID, &DeviceStatus, &ConnectionProgressInfo)
+		!= GCT_API_RET_SUCCESS) {
+		cm_eprintf("GAPI_GetDeviceStatus Failure\n");
+		return -1;
+	}
+
+	if (DeviceStatus != WIMAX_API_DEVICE_STATUS_Data_Connected) {
+		cm_eprintf("DeviceStatus is not connected state(%d)\n", DeviceStatus);
+		return 0;
+	}
+
+	// Enumerate service flow
+	ret = GAPI_BeginSFRead(&ID);
+	if (GCT_API_RET_SUCCESS != ret) {
+		cm_printf("Failed to GAPI_BeginSFRead=%d\n",ret);
+	}
+
+	pServiceFlow = NULL;
+	pCrRule = NULL;
+	pPhsRule = NULL;
+	count = 0;
+	while ( GCT_API_RET_SUCCESS == (ret = GAPI_GetNextSF(&ID, pServiceFlow, 2, &pServiceFlow)) && pServiceFlow )
+	{
+		cm_printf("SFID=0x%08x\n", ntohl(pServiceFlow->param.SFID));
+
+		while ( GCT_API_RET_SUCCESS == (ret = GAPI_GetNextClfrRule(&ID, pServiceFlow, pCrRule, &pCrRule)) && pCrRule )
+		{
+			cm_printf("\tClfrIndex=%d\n", ntohs(pCrRule->PacketClassifierRuleIndex));
+		}
+
+		while ( GCT_API_RET_SUCCESS == (ret = GAPI_GetNextPHSRule(&ID, pServiceFlow, pPhsRule, &pPhsRule)) && pPhsRule )
+		{
+			cm_printf("\tPHSI=%d\n", pPhsRule->PHSI);
+		}
+
+		count++;
+	}
+
+	if (!count) {
+		cm_printf("Service Flow does not exist.\n");
+	}
+	else {
+		cm_printf("Service Flow count=[%d]\n", count);
+	}
+
+	ret = GAPI_EndSFRead(&ID);
+	if (GCT_API_RET_SUCCESS != ret) {
+		cm_printf("Failed to GAPI_EndSFRead=%d\n",ret);
+	}
+
+	return ID.deviceIndex;
+}
+
+static int cmd_dsa_test(int argc, char *argv[])
+{
+	GDEV_ID ID;
+	WIMAX_API_DEVICE_STATUS DeviceStatus;
+	WIMAX_API_CONNECTION_PROGRESS_INFO ConnectionProgressInfo;
+	WIMAX_SF_PARAM lSfParam;
+	WIMAX_CLFR_RULE lCrRule;
+	WIMAX_PHS_RULE lPhsRule;
+	int ret;
+
+	ID.apiHandle = cm_api_handle;
+	ret = ID.deviceIndex = (argc == 2 ? atoi(argv[1]) : DEFAULT_DEVICE);
+
+	if (GAPI_GetDeviceStatus(&ID, &DeviceStatus, &ConnectionProgressInfo)
+		!= GCT_API_RET_SUCCESS) {
+		cm_eprintf("GAPI_GetDeviceStatus Failure\n");
+		return -1;
+	}
+
+	if (DeviceStatus != WIMAX_API_DEVICE_STATUS_Data_Connected) {
+		cm_eprintf("DeviceStatus is not connected state(%d)\n", DeviceStatus);
+		return -1;
+	}
+
+	// DSA Test
+	unsigned char phsmdat[3] = {0x00,0x0f,0xf0};
+	unsigned char phsf[20] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0xc0, 0xa8, 0x01, 0x59, 0xc0, 0xa8, 0x01, 0xfd};
+
+	lSfParam = sf_param_init;
+	lCrRule = classifier_rule_init;
+	lPhsRule = phs_rule_init;
+
+	lSfParam.DL = 0; /* Uplink service flow */
+	lSfParam.TrafficPriority = 1; 
+	lSfParam.QosParamSetType = 7;
+	lSfParam.MaxSustainedTrafficRate = 88000;
+	lSfParam.MinReservedTrafficRate = 88000;
+	lSfParam.ULGrantSchedulingType = UL_SCHED_TYPE_ertPS;
+	lSfParam.RequestTransmissionPolicy = 0x02;
+	lSfParam.ToleratedJitter = 20;
+	lSfParam.MaxLatency = 60;
+	lSfParam.TypeOfDataDeliveryServices = DATA_SERVICE_UGS;
+	lSfParam.UnsolicitedGrantInterval = 20;
+
+	lSfParam.CSSpecification = 1;
+	lSfParam.ARQEnable = 0;
+	lSfParam.HARQServiceFlows = 1;
+	lSfParam.PDUSNExtendedSubheaderForHARQReordering = 2;
+	lSfParam.FSNSize = 1;
+
+	/* Classifier rule: UDP packets with destination port 5001 */
+	lCrRule.ClassifierRulePriority = 1;
+	lCrRule.Protocol = 17;
+	lCrRule.ProtocolDestPort.low = 0;
+	lCrRule.ProtocolDestPort.high = 65535;
+	lCrRule.IPv4MaskedDestAddress.address.s_addr = inet_addr("192.168.1.253");
+	lCrRule.IPv4MaskedDestAddress.mask.s_addr = inet_addr("255.255.255.255");
+
+	lPhsRule.PHSI = 1;
+	lPhsRule.PHSS = 20;
+
+	memcpy(lPhsRule.PHSM, phsmdat, 3);
+	memcpy(lPhsRule.PHSF, phsf, 20);
+
+	lPhsRule.PHSV = 1;
+
+	ret = GAPI_CmdAddSF(&ID, &lSfParam, &lCrRule, &lPhsRule); 
+	if (GCT_API_RET_SUCCESS != ret) {
+		cm_printf("Failed to GAPI_CmdAddSF=%d\n",ret);
+	}
+	else {
+		cm_printf("Success! GAPI_CmdAddSF, SFID=0x%08x\n", ntohl(lSfParam.SFID));
+	}
+
+	return ID.deviceIndex;
+}
+
+static int cmd_dsc_test(int argc, char *argv[])
+{
+	GDEV_ID ID;
+	WIMAX_API_DEVICE_STATUS DeviceStatus;
+	WIMAX_API_CONNECTION_PROGRESS_INFO ConnectionProgressInfo;
+	WIMAX_SERVICE_FLOW *sfp;
+	uint32_t sfid;
+	int ret;
+
+	if (argc < 2) {
+		cm_eprintf("Invalid parameter\n");
+		return 0;
+	}
+
+	sfid = strtoul(argv[1], NULL, 16);
+	sfid = htonl(sfid);
+
+	ID.apiHandle = cm_api_handle;
+	ret = ID.deviceIndex = (argc == 3 ? atoi(argv[2]) : DEFAULT_DEVICE);
+
+	if (GAPI_GetDeviceStatus(&ID, &DeviceStatus, &ConnectionProgressInfo)
+		!= GCT_API_RET_SUCCESS) {
+		cm_eprintf("GAPI_GetDeviceStatus Failure\n");
+		return -1;
+	}
+
+	if (DeviceStatus != WIMAX_API_DEVICE_STATUS_Data_Connected) {
+		cm_eprintf("DeviceStatus is not connected state(%d)\n", DeviceStatus);
+		return -1;
+	}
+
+	// DSC Test
+	ret = GAPI_GetServiceFlow(&ID, sfid, &sfp);
+	if (GCT_API_RET_SUCCESS != ret) {
+		cm_printf("Failed to GAPI_GetServiceFlow=%d\n",ret);
+	}
+
+	if (sfp) {
+		sfp->param.MaxSustainedTrafficRate = 100000;
+		sfp->param.MinReservedTrafficRate = 100000;
+	
+		sfp->classification_rule[0].Protocol = 1; /* ICMP */
+		
+		ret = GAPI_CmdChangeSF(&ID, &sfp->param,
+			DSC_ADD_CLASSIFIER, &sfp->classification_rule[0],
+			DSC_NOP_PHS, NULL);
+	
+		if (GCT_API_RET_SUCCESS != ret) {
+			cm_printf("Failed to GAPI_CmdChangeSF=%d\n",ret);
+		}
+		else {
+			cm_printf("Success! GAPI_CmdChangeSF\n");
+		}			
+	} else {
+		cm_printf("Not found Service Flow\n");
+	}
+	
+	return ID.deviceIndex;
+}
+
+static int cmd_dsd_test(int argc, char *argv[])
+{
+	GDEV_ID ID;
+	WIMAX_API_DEVICE_STATUS DeviceStatus;
+	WIMAX_API_CONNECTION_PROGRESS_INFO ConnectionProgressInfo;
+	WIMAX_SERVICE_FLOW *sfp;
+	uint32_t sfid;
+	int ret;
+
+	if (argc < 2) {
+		cm_eprintf("Invalid parameter\n");
+		return 0;
+	}
+
+	sfid = strtoul(argv[1], NULL, 16);
+	sfid = htonl(sfid);
+
+	ID.apiHandle = cm_api_handle;
+	ret = ID.deviceIndex = (argc == 3 ? atoi(argv[2]) : DEFAULT_DEVICE);
+
+	if (GAPI_GetDeviceStatus(&ID, &DeviceStatus, &ConnectionProgressInfo)
+		!= GCT_API_RET_SUCCESS) {
+		cm_eprintf("GAPI_GetDeviceStatus Failure\n");
+		return -1;
+	}
+
+	if (DeviceStatus != WIMAX_API_DEVICE_STATUS_Data_Connected) {
+		cm_eprintf("DeviceStatus is not connected state(%d)\n", DeviceStatus);
+		return -1;
+	}
+
+	// DSD Test
+	ret = GAPI_GetServiceFlow(&ID, sfid, &sfp);
+	if (GCT_API_RET_SUCCESS != ret) {
+		cm_printf("Failed to GAPI_GetServiceFlow=%d\n",ret);
+	}
+	
+	if (sfp) {
+		ret = GAPI_CmdDeleteSF(&ID, &sfp->param);
+		if (GCT_API_RET_SUCCESS != ret) {
+			cm_printf("Failed to GAPI_CmdDeleteSF=%d\n",ret);
+		}
+		else {
+			cm_printf("Success! GAPI_CmdDeleteSF\n");
+		}			
+	} else {
+		cm_printf("Not found service flow\n");
+	}
+
+	return ID.deviceIndex;
+}
+#endif // CONFIG_ENABLE_SERVICE_FLOW
+
+static int cmd_command_mac_state(int argc, char *argv[])
+{
+	GDEV_ID ID;
+	int type;
+	int ret;	
+
+	if (argc < 2) {
+		cm_printf("Invalid parameter.\n");
+		return -1;
+	}
+
+	type = atoi(argv[1]);
+	ID.apiHandle = cm_api_handle;
+	ret = ID.deviceIndex = (argc == 3 ? atoi(argv[2]) : DEFAULT_DEVICE);
+
+	if(GAPI_CmdMACState(&ID, type)
+		!= GCT_API_RET_SUCCESS) {
+		cm_printf("Failed to GAPI_CmdMACState=%d\n",ret);
+	}
+
+	return ID.deviceIndex;
+}
+
+static int cmd_set_idle_mode_timeout(int argc, char *argv[])
+{
+	GDEV_ID ID;
+	int timeoutSec;
+	int ret;	
+
+	if (argc < 2) {
+		cm_printf("Invalid parameter.\n");
+		return -1;
+	}
+
+	timeoutSec = atoi(argv[1]);
+	ID.apiHandle = cm_api_handle;
+	ret = ID.deviceIndex = (argc == 3 ? atoi(argv[2]) : DEFAULT_DEVICE);
+
+	if(GAPI_SetIdleModeTimeout(&ID, timeoutSec)
+		!= GCT_API_RET_SUCCESS) {
+		cm_printf("Failed to GAPI_SetIdleModeTimeout=%d\n",ret);
+	}
+
+	return ID.deviceIndex;
+
+}
+
+static int cmd_get_phy_mac_basic(int argc, char *argv[])
+{
+	GDEV_ID ID;
+	GCT_API_MAC_PHY_MAC_BASIC phy_mac_basic;
+	int ret;
+
+	ID.apiHandle = cm_api_handle;
+	ret = ID.deviceIndex = (argc == 2 ? atoi(argv[1]) : DEFAULT_DEVICE);
+
+	if(GAPI_GetPHY_MAC_Basic(&ID, &phy_mac_basic)
+		== GCT_API_RET_SUCCESS) {
+
+		cm_printf("[PHY/MAC Basic]\n");
+		cm_printf("FrameNumber: %u\n", phy_mac_basic.frame_number);
+		cm_printf("FCH:         %u\n", phy_mac_basic.fch);
+		cm_printf("TTG:         %u\n", phy_mac_basic.ttg);
+		cm_printf("RTG:         %u\n", phy_mac_basic.rtg);
+		cm_printf("NumDlSymbol: %u\n", phy_mac_basic.num_dl_symbol);
+		cm_printf("NumUlSymbol: %u\n", phy_mac_basic.num_ul_symbol);
+		cm_printf("CurrentPI:   %u\n", phy_mac_basic.current_pi);
+		cm_printf("PerviousPI:  %u\n", phy_mac_basic.previous_pi);
+		cm_printf("UlPermBase:  %u\n", phy_mac_basic.ul_perm_base);
+		cm_printf("MAC State:   %u\n", phy_mac_basic.mac_state);
+		cm_printf("BSID:        0x%02x%02x%02x%02x%02x%02x\n", 
+			phy_mac_basic.bsid[0], phy_mac_basic.bsid[1], phy_mac_basic.bsid[2],
+			phy_mac_basic.bsid[3], phy_mac_basic.bsid[4], phy_mac_basic.bsid[5]);
+		cm_printf("ulTime:      %d\n", phy_mac_basic.ul_time);
+		cm_printf("Frequency:   %u\n", phy_mac_basic.frequency);
+		cm_printf("Bandwidth:   %u\n", phy_mac_basic.bandwidth);
+		cm_printf("TimeActive:  %u\n", phy_mac_basic.time_active);
+		cm_printf("TimeSleep:   %u\n", phy_mac_basic.time_sleep);
+		cm_printf("TimeIdle:    %u\n", phy_mac_basic.time_idle);
+		cm_printf("BasicCID:    %u\n", phy_mac_basic.basic_cid);
+		cm_printf("PrimaryCID:  %u\n", phy_mac_basic.primary_cid);
+
+	} else {
+		cm_printf("Failed to GAPI_GetPHY_MAC_Basic=%d\n",ret);
+	}
+
+	return ID.deviceIndex;
+}
+
+static int cmd_get_phy_mcs(int argc, char *argv[])
+{
+	GDEV_ID ID;
+	GCT_API_MAC_PHY_MCS phy_mcs;
+	int i, j, k;
+	int ret;
+
+	ID.apiHandle = cm_api_handle;
+	ret = ID.deviceIndex = (argc == 2 ? atoi(argv[1]) : DEFAULT_DEVICE);
+
+	if(GAPI_GetPHY_MCS(&ID, &phy_mcs)
+		== GCT_API_RET_SUCCESS) {
+
+		cm_printf("[PHY MCS: DL]\n");
+		cm_printf("[OFDMA_FEC] [REPETITION] [MIMO] [num_burst] [num_burst_err] [len_pdu] [num_pdu]\n");
+
+		for (i = 0 ; i < OFDMA_FEC_MODE_CNT ; i++)
+		{
+			for (j = 0 ; j < REPETITION_CODING_CNT ; j++)
+			{
+				for (k = 0 ; k < MIMO_TYPE_CNT ; k++)
+				{
+					if (phy_mcs.dl_used[i][j][k])
+					{
+						cm_printf("%10d %12d %6d %11u %15u %9u %9u\n",
+							i, j, k, 
+							phy_mcs.dl[i][j][k].num_burst, phy_mcs.dl[i][j][k].num_burst_error, phy_mcs.dl[i][j][k].len_pdu, phy_mcs.dl[i][j][k].num_pdu);
+					}
+				}
+			}
+		}
+
+		cm_printf("[PHY MCS: UL]\n");
+		cm_printf("[OFDMA_FEC] [REPETITION] [MIMO] [num_burst] [num_burst_err] [len_pdu] [num_pdu]\n");
+
+		for (i = 0 ; i < OFDMA_FEC_MODE_CNT ; i++)
+		{
+			for (j = 0 ; j < REPETITION_CODING_CNT ; j++)
+			{
+				for (k = 0 ; k < MIMO_TYPE_CNT ; k++)
+				{
+					if (phy_mcs.ul_used[i][j][k])
+					{
+						cm_printf("%10d %12d %6d %11u %15u %9u %9u\n",
+							i, j, k, 
+							phy_mcs.ul[i][j][k].num_burst, phy_mcs.ul[i][j][k].num_burst_error, phy_mcs.ul[i][j][k].len_pdu, phy_mcs.ul[i][j][k].num_pdu);
+					}
+				}
+			}
+		}
+	
+	} else {
+		cm_printf("Failed to GAPI_GetPHY_MCS=%d\n",ret);
+	}
+
+	return ID.deviceIndex;
+}
+
+static int cmd_get_phy_cinr_rssi(int argc, char *argv[])
+{
+	GDEV_ID ID;
+	GCT_API_MAC_PHY_CINR_RSSI phy_cinr_rssi;
+	int ret;
+
+	ID.apiHandle = cm_api_handle;
+	ret = ID.deviceIndex = (argc == 2 ? atoi(argv[1]) : DEFAULT_DEVICE);
+
+	if(GAPI_GetPHY_CINR_RSSI(&ID, &phy_cinr_rssi)
+		== GCT_API_RET_SUCCESS) {
+
+		cm_printf("[PHY CINR/RSSI]\n");
+		cm_printf("CINR-mean:             %d\n", phy_cinr_rssi.cinr_mean);
+		cm_printf("CINR-std-dev:          %d\n", phy_cinr_rssi.cinr_std_dev);
+		cm_printf("RSSI-mean:             %d\n", phy_cinr_rssi.rssi_mean);
+		cm_printf("RSSI-std-dev:          %d\n", phy_cinr_rssi.rssi_std_dev);
+		cm_printf("CINR_A_mean:           %d\n", phy_cinr_rssi.cinr_a_mean);
+		cm_printf("CINR_B_mean:           %d\n", phy_cinr_rssi.cinr_b_mean);
+		cm_printf("CINR-main:             %d\n", phy_cinr_rssi.cinr_main);
+		cm_printf("CINR-diversity:        %d\n", phy_cinr_rssi.cinr_diversity);
+		cm_printf("RSSI-main:             %d\n", phy_cinr_rssi.rssi_main);
+		cm_printf("RSSI-diversity:        %d\n", phy_cinr_rssi.rssi_diversity);
+		cm_printf("Preamble CINR(reuse3): %d\n", phy_cinr_rssi.preamble_cinr_reuse3);
+		cm_printf("Preamble CINR(reuse1): %d\n", phy_cinr_rssi.preamble_cinr_reuse1);
+		
+	} else {
+		cm_printf("Failed to GAPI_GetPHY_CINR_RSSI=%d\n",ret);
+	}
+
+	return ID.deviceIndex;
+}
+
+static cmd_t cmd_list[] = {
+	{"cm_gdl", "It shows device list", NULL, cmd_get_dev_list},
+	{"cm_gs", "It shows the current WiMax state", "[device index: default 1]",
+								cmd_get_status},
+	{"cm_ru", "RF up.", "[device index: default 1]", cmd_rf_up},
+	{"cm_rd", "RF down.", "[device index: default 1]", cmd_rf_down},
+	{"cm_gl", "Get link status.", "[device index: default 1]", cmd_get_link_status},
+	{"cm_gp", "Get profile list.", "[device index: default 1]", cmd_get_profile_list},
+	{"cm_sp", "Set profile.", "profile-index [device index: default 1]", cmd_set_profile},
+	{"cm_gnl", "It shows network list.", "[device index: default 1]", cmd_get_net_list},
+	{"cm_gnbl", "It shows neighbor list.", "[device index: default 1]",
+								cmd_get_neighbor_list},
+	{"cm_cn", "It connects to network", "[profile-ID] [device index: default 1]",
+								cmd_connect_net},
+	{"cm_auto_cn", "Auto connection on/off", "on|off [device index: default 1]",
+								cmd_auto_connect_net},
+	{"cm_dn", "It disconnects from network", "[device index: default 1]",
+								cmd_disconnect_net},
+	{"cm_scit", "Set scan interval(second)", "interval [device index: default 1]",
+								cmd_set_autoscan_interval},
+	{"cm_scan", "It scan network", "scan-mode [device index: default 1]"
+								"\n              scan-mode 0: wide scan"
+								"\n              scan-mode 1: all subscriptions scan"
+								"\n              scan-mode 2: current subscription scan",
+								cmd_scan},
+	{"cm_auth", "This command is not used no more.", NULL, cmd_auth},
+	{"cm_dc", "Delete Cert.", "cert-index", cmd_delete_cert},
+	{"cm_gcs", "Get Cert.'s status", NULL, cmd_get_cert_status},
+	{"cm_gcm", "Get Cert.'s mask", NULL, cmd_get_cert_mask},
+	{"cm_scm", "Set Cert.'s mask.", "cert-mask", cmd_set_cert_mask},
+	{"cm_gci", "Get Cert.'s information.", NULL, cmd_get_cert_info},
+	{"cm_sd", "Set debug level.", "level", cmd_debug_level},
+	{"cm_rfile", "Read file.", "host-file target-file [device index: default 1]",
+								cmd_read_file},
+	{"cm_wfile", "Write file.", "host-file target-file [device index: default 1]",
+								cmd_write_file},
+	{"cm_dfile", "Delete file.", "target-file [device index: default 1]",
+								cmd_delete_file},
+	{"cm_rimg", "Read image.", "type image-path [device index: default 1]"
+								"\n              type 7: EEPROM Bootloader (All bootloader block: 12KB)"
+								"\n              type 0x100: oma-xml"
+								"\n              type 0x101: device Cert(private-key should be merged)"
+								"\n              type 0x102: server root CA"
+								"\n              type 0x103: sub CA #1"
+								"\n              type 0x104: sub CA #2"
+								"\n              type 0x106: combined CA",
+								cmd_read_image},
+	{"cm_wimg", "Write image.", "type image-path [device index: default 1]"
+								"\n              type 0: kernel"
+								"\n              type 1: filesystem"
+								"\n              type 7: EEPROM Bootloader"
+								"\n              type 0x100: oma-xml"
+								"\n              type 0x101: device Cert(private-key should be merged)"
+								"\n              type 0x102: server root CA"
+								"\n              type 0x103: sub CA #1"
+								"\n              type 0x104: sub CA #2"
+								"\n              type 0x106: combined CA",
+								cmd_write_image},
+	{"cm_cimg", "Control image.", "type command [device index: default 1]"
+								"\n              type 0x101: device Cert(private-key should be merged)"
+								"\n              type 0x102: server root CA"
+								"\n              type 0x103: sub CA #1"
+								"\n              type 0x104: sub CA #2"
+								"\n              type 0x105: eap parameter"
+								"\n              type 0x106: combined CA"
+								"\n              command 0: delete image"
+								"\n              command 1: get size of image"
+								"\n              command 2: get crc32 of image",
+								cmd_control_image},
+	{"cm_nv", "Read/Write NV parameters.", nv_param_usage, cmd_nv_param},
+	{"cm_scr", "Run script", "script-file [device index: default 1]", cmd_script},
+	{"cm_date", "Print current time", NULL, cmd_date},
+	{"cm_sleep", "Sleep function for script test", NULL, cmd_sleep},
+	{"cm_chk", "Check cm status", NULL, cmd_chk},
+	{"cm_test", "Test function", NULL, cmd_test},
+	{"cm_gst", "Get statistics", NULL, cmd_get_statistics},
+	{"cm_uicc", "UICC Test function", "on|off [device index: default 1]", cmd_uicc},
+	{"cm_macst", "Command MAC State", "type [device index: default 1]"
+								"\n              type 0: Enter Sleep Mode"
+								"\n              type 1: Exit Sleep Mode"
+								"\n              type 2: Enter Idle Mode"
+								"\n              type 3: Exit Idle Mode",
+								cmd_command_mac_state},
+	{"cm_idletm", "Set Idle Mode Timeout", "timeout-sec [device index: default 1]", cmd_set_idle_mode_timeout},
+	{"cm_gpmac", "Get PHY MAC Basic status", "[device index: default 1]", cmd_get_phy_mac_basic},
+	{"cm_gpmcs", "Get PHY MCS status", "[device index: default 1]", cmd_get_phy_mcs},
+	{"cm_gpcinr", "Get PHY CINR/RSSI", "[device index: default 1]", cmd_get_phy_cinr_rssi},	
+	#if defined(CONFIG_DM_INTERFACE)
+	{"cm_dmif", "DM interface on/off", "on/off", cmd_dmif},
+	#endif
+	#if defined(CONFIG_ENABLE_SERVICE_FLOW)
+	{"cm_gsf", "Get current service flow list", "[device index: default 1]", cmd_gsf},
+	{"cm_dsa_test", "Service Flow DSA Test function", "[device index: default 1]", cmd_dsa_test},
+	{"cm_dsc_test", "Service Flow DSC Test function", "sfid [device index: default 1]", cmd_dsc_test},
+	{"cm_dsd_test", "Service Flow DSD Test function", "sfid [device index: default 1]", cmd_dsd_test},
+	#endif // CONFIG_ENABLE_SERVICE_FLOW
+	{"shell", "Execute shell prompt", NULL, cmd_shell},
+	{"cm_exit", "Exit CM.", NULL, cmd_exit},
+	{"cm_help", "Print command list.", NULL, cmd_help},
+	{NULL, NULL, NULL, NULL}
+};
+
+static void print_cmd(cmd_t *cmd)
+{
+	cm_printf("%s: %s\n", cmd->cmd, cmd->desc ? cmd->desc : "");
+	cm_printf("    =>%s %s\n", cmd->cmd, cmd->param ? cmd->param : "");
+}
+
+static void print_cmd_usage(const char *cmd)
+{
+	cmd_t *list = cmd_list;
+
+	while (list->cmd) {
+		if (!strcmp(list->cmd, cmd)) {
+			print_cmd(list);
+			return;
+		}
+		list++;
+	}
+}
+
+static void print_cmd_list(const char *cmd)
+{
+	cmd_t *list = cmd_list;
+
+	if (!cmd)
+		cm_printf("----------------------[ Command list ]----------------------\n");
+	else
+		cm_printf("------------------------------------------------------------\n");
+
+	while (list->cmd) {
+		if (!cmd || !strcmp(cmd, list->cmd)) {
+			print_cmd(list);
+			if (cmd)
+				break;
+		}
+		list++;
+	}
+	cm_printf("------------------------------------------------------------\n");
+}
+
+static int do_cmd(char *cmd_line, int len)
+{
+	char buf[1024];
+	cmd_t *list = cmd_list;
+	int argc;
+	char *argv[16];
+
+	memcpy(buf, cmd_line, len);
+	__get_token_arg(buf, &argc, argv);
+
+	if (argc) {
+		while (list->cmd) {
+			if (!strcmp(list->cmd, argv[0])) {
+				return list->func(argc, argv);
+			}
+			list++;
+		}
+	}
+
+	return NO_CM_CMD;
+}
+
+static int is_foreground_process(void)
+{
+	if (tcgetpgrp(STDIN_FILENO) == getpgrp())
+		return 1;
+	else
+		return 0;
+}
+
+void cmd_run(void)
+{
+	GDEV_ID ID;
+	cm_common_conf_t *pconf = &cm_common_conf;
+	char buf[1024];
+	int readn, ret;
+	GCT_API_RET gret = 0;
+
+	ID.apiHandle = cm_api_handle;
+
+	if (pconf->run_script_file[0] && !access(pconf->run_script_file, 0))
+		run_script(DEFAULT_DEVICE, pconf->run_script_file);
+
+	if (!isatty(STDIN_FILENO) || !is_foreground_process()) {
+		cm_printf("Background!\n");
+		while (1);
+	}
+
+	while (fgets(buf, sizeof(buf), stdin)) {
+		readn = strlen(buf);
+		ret = do_cmd(buf, readn);
+		if (ret == EXIT_CM_CMD)
+			break;
+		if (cm_odev_cnt) {
+			if (ret == NO_CM_CMD || ret > 0) {
+				if (ret == NO_CM_CMD) {
+					if (!(ret = get_first_odev()))
+						continue;
+				}
+				else
+					readn = 1;
+				buf[readn-1] = '\n';
+				ID.deviceIndex = ret;
+				gret = send_print_string(&ID, buf, readn);
+			}
+		}
+	}
+}
diff --git a/cm/dhclient.c b/cm/dhclient.c
new file mode 100644
index 0000000..b8ebc71
--- /dev/null
+++ b/cm/dhclient.c
@@ -0,0 +1,308 @@
+// 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 <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <pthread.h>
+#include <dirent.h>
+#include <stdarg.h>
+#include <wchar.h>
+#include <linux/version.h>
+#include <signal.h>
+
+#include "cm.h"
+
+//#define PARALLEL_DHCLIENT_THREAD
+//#define FORCE_SYNCHRONOUS_DHCLIENT
+
+#define IP_ACQUISITION_TIMER_MS			1000
+#define DISCONNECT_ON_IP_ALLOCATION_TIMEOUT
+
+#define DHCLIENT_APP	"/sbin/dhclient"
+
+static void start_dhclient(int dev_idx)
+{
+	char *devname = cm_get_dev_idx2name(dev_idx);
+	char argv[4][64];
+	#if defined(FORCE_SYNCHRONOUS_DHCLIENT)
+	char cmd_line[256];
+	#endif
+
+	#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,25)
+	char ifcfg_file[256] = "/etc/sysconfig/network-scripts/ifcfg-";
+	int fd;
+
+	strcat(ifcfg_file, devname);
+	if (access(ifcfg_file, F_OK)) {
+		if ((fd = open(ifcfg_file, O_CREAT|O_WRONLY|O_TRUNC, 0755)) < 0) {
+			cm_eprintf("cannot create ifcfg-%s!!!\n", devname);
+			return;
+		}
+		close(fd);
+	}
+	#endif
+
+	strcpy(argv[0], DHCLIENT_APP);
+	strcpy(argv[1], "-pf");
+	sprintf(argv[2], "/var/run/dhclient.%s.pid", devname);
+	if (!access(argv[2], F_OK))
+		unlink(argv[2]);
+	strcpy(argv[3], devname);
+
+	#if defined(FORCE_SYNCHRONOUS_DHCLIENT)
+	sprintf(cmd_line, "%s %s %s %s", argv[0], argv[1], argv[2], argv[3]);
+	system(cmd_line);
+	exit(0);
+	#else
+	if (execl(argv[0], argv[0], argv[1], argv[2], argv[3], NULL) < 0) {
+		cm_eprintf("execl failed\n");
+		exit(1);
+	}
+	#endif
+}
+
+static void stop_dhclient(int dev_idx)
+{
+	char *devname = cm_get_dev_idx2name(dev_idx);
+	char dhclient_lock[256];
+	FILE *fp;
+	pid_t pid;
+
+	sprintf(dhclient_lock, "/var/run/dhclient.%s.pid", devname);
+	if ((fp = fopen(dhclient_lock, "r")) != NULL) {
+		#if 0
+		dev_conf_t *dconf = &cm_dev_conf[dev_idx];
+		char dhclient_start[256];
+		cm_printf("Release ip ...\n");
+		sprintf(dhclient_start, "%s -r -pf %s %s 2>/dev/null",
+			DHCLIENT_APP, dhclient_lock, devname);
+		system(dhclient_start);
+		#endif
+		fscanf(fp, "%d", &pid);
+		fclose(fp);
+		cm_printf("Kill dhclient...\n");
+		kill(pid, SIGTERM);
+		unlink(dhclient_lock);
+	}
+	else if (errno != ENOENT) {
+		cm_eprintf("Open fail(%s) %s(%d)\n", dhclient_lock, strerror(errno), errno);
+	}
+}
+
+static void job_after_ip_allocated(int dev_idx)
+{
+}
+
+static void job_timeout_ip_allocating(int dev_idx)
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+
+	cm_printf("Timeout(%d sec.) ip allocating!\n", pconf->ip_allocation_timeout_sec);
+	if (pconf->disconnct_on_ip_failure) {
+		cm_printf("Disconnect network due to ip allocation failure!\n");
+		cm_disconnect_net(dev_idx);
+	}
+}
+
+static void ip_acquisition_timer_callback(void *data)
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+	int dev_idx = (int) data;
+	dev_conf_t *dconf = &cm_dev_conf[dev_idx];
+	char ip[64];
+	int restart_timer_ms = IP_ACQUISITION_TIMER_MS;
+
+	if (!cm_get_dhcp_ip(dev_idx, ip)) {
+		cm_printf("device[%d] ip=%s\n", dev_idx, ip);
+		job_after_ip_allocated(dev_idx);
+	}
+	else {
+		if (dconf->ip_acq_timed < pconf->ip_allocation_timeout_sec*1000) {
+			dconf->ip_acq_timed += IP_ACQUISITION_TIMER_MS;
+			if (dconf->wimax_status == WIMAX_API_DEVICE_STATUS_Data_Connected) {
+				cm_printf("Restart ip acq timer(%d ms.)\n", restart_timer_ms);
+				cm_start_timer(&dconf->ip_acq_timer, restart_timer_ms);
+			}
+		}
+		else
+			job_timeout_ip_allocating(dev_idx);
+	}
+}
+
+static void ip_acquisition_timer_start(int dev_idx)
+{
+	dev_conf_t *dconf = &cm_dev_conf[dev_idx];
+	cm_init_timer(&dconf->ip_acq_timer, ip_acquisition_timer_callback,
+		(void *)dev_idx);
+	dconf->ip_acq_timed = 1;
+	cm_start_timer(&dconf->ip_acq_timer, IP_ACQUISITION_TIMER_MS);
+}
+
+static int run_dhclient(int dev_idx)
+{
+	dev_conf_t *dconf = &cm_dev_conf[dev_idx];
+	pid_t pid;
+	int ret = 0, i, status;
+
+	pid = fork();
+	if (pid == 0) {
+		/*Close all FDs*/
+		for (i = 3; i < 64; i++)
+			close(i);
+
+		cm_printf("Starting dhclient...\n");
+		start_dhclient(dev_idx);
+		cm_printf("Nerver returns...\n");
+	}
+	else if (pid != -1) {
+		dconf->dhclient_pid = pid;
+		ip_acquisition_timer_start(dev_idx);
+		cm_dprintf("+waitpid(%d)\n", pid);
+		waitpid(pid, &status, 0);
+		cm_dprintf("-waitpid(%d)\n", pid);
+		dconf->dhclient_pid = 0;
+		if ((!WIFEXITED(status) || WEXITSTATUS(status))) {
+			cm_eprintf("waitpid: status=%d!\n", WEXITSTATUS(status));
+			return -1;
+		}
+	}
+	else
+		cm_printf("fork failed\n");
+	return ret;
+}
+
+#if defined(PARALLEL_DHCLIENT_THREAD)
+static void *run_dhclient_thread(void *data)
+{
+	int dev_idx = (int) data;
+
+	cm_dprintf("Start dhclient thread(%d)\n", dev_idx);
+	run_dhclient(dev_idx);
+	cm_dprintf("End dhclient thread(%d)\n", dev_idx);
+	return NULL;
+}
+#endif
+
+static int test_kill_dhclient_pid(int dev_idx)
+{
+	dev_conf_t *dconf = &cm_dev_conf[dev_idx];
+
+	if (dconf->dhclient_pid > 0) {
+		cm_dprintf("kill dhclient(pid=%d)\n", dconf->dhclient_pid);
+		kill(dconf->dhclient_pid, SIGTERM);
+		dconf->dhclient_pid = 0;
+		return 1;
+	}
+	return 0;
+}
+
+static void kill_dhclient(int dev_idx)
+{
+	test_kill_dhclient_pid(dev_idx);
+	stop_dhclient(dev_idx);
+}
+
+#define DHCLIENT_ON		(int)(1)
+#define DHCLIENT_OFF	(int)(0)
+#define DHCLIENT_EXIT	(int)(-1)
+
+static void *cm_dhclient_thread(void *data)
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+	dev_conf_t *dconf;
+	cm_msg_cb_t *msg_cb;
+	int dev_idx = DEFAULT_DEVICE, event;
+
+	msg_cb = &pconf->dhclient_msg;
+	cm_msg_init(msg_cb);
+
+	cm_printf("dhclient thread is ready!\n");
+	stop_dhclient(dev_idx);
+	while (1) {
+		dev_idx = DEFAULT_DEVICE;
+		if (cm_msg_recv(msg_cb, &dev_idx, (void **) &event) < 0) {
+			cm_eprintf("dhclient cm_msg_recv error\n");
+			break;
+		}
+
+		if (event == DHCLIENT_ON) {
+			dconf = &cm_dev_conf[dev_idx];
+			#if defined(PARALLEL_DHCLIENT_THREAD)
+			{
+				pthread_t thread;
+				pthread_create(&thread, NULL, run_dhclient_thread, (void *)dev_idx);
+				pthread_detach(thread);
+			}
+			#else
+			run_dhclient(dev_idx);
+			#endif
+		}
+		else if (event == DHCLIENT_OFF)
+			kill_dhclient(dev_idx);
+		else {	/*DHCLIENT_EXIT*/
+			break;
+		}
+	}
+	
+	cm_msg_deinit(msg_cb);
+	pconf->dhclient_thr = (pthread_t) NULL;
+	cm_printf("dhclient thread finished!\n");
+	return NULL;
+}
+
+void dh_create_dhclient(void)
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+
+	if (pconf->dhclient_thr) {
+		cm_eprintf("dhclient thread has been started already!\n");
+		return;
+	}
+	pthread_create(&pconf->dhclient_thr, NULL, cm_dhclient_thread, NULL);
+}
+
+void dh_delete_dhclient(void)
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+	pthread_t thread;
+
+	if ((thread = pconf->dhclient_thr)) {
+		cm_msg_send(&pconf->dhclient_msg, DEFAULT_DEVICE, (void *) DHCLIENT_EXIT);
+		pthread_join(thread, NULL);
+		cm_dprintf("dhclient thread deleted!\n");
+	}
+}
+
+void dh_start_dhclient(int dev_idx)
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+
+	if (pconf->api_mode == GCT_WIMAX_API_PRIVILEGE_READ_ONLY)
+		return;
+
+	test_kill_dhclient_pid(dev_idx);
+	cm_msg_send(&pconf->dhclient_msg, dev_idx, (void *) DHCLIENT_ON);
+}
+
+void dh_stop_dhclient(int dev_idx)
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+
+	if (pconf->api_mode == GCT_WIMAX_API_PRIVILEGE_READ_ONLY)
+		return;
+
+	test_kill_dhclient_pid(dev_idx);
+	cm_msg_send(&pconf->dhclient_msg, dev_idx, (void *) DHCLIENT_OFF);
+}
diff --git a/cm/dhclient.h b/cm/dhclient.h
new file mode 100644
index 0000000..da6786a
--- /dev/null
+++ b/cm/dhclient.h
@@ -0,0 +1,17 @@
+// 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.
+
+#if !defined(DHCLIENT_H_20100409)
+#define DHCLIENT_H_20100409
+
+#include <netinet/in.h>
+#include "../sdk/gctapi.h"
+#include "cm_msg.h"
+
+void dh_start_dhclient(int dev_idx);
+void dh_stop_dhclient(int dev_idx);
+void dh_create_dhclient(void);
+void dh_delete_dhclient(void);
+
+#endif
diff --git a/cm/dm_if.c b/cm/dm_if.c
new file mode 100644
index 0000000..b1c5486
--- /dev/null
+++ b/cm/dm_if.c
@@ -0,0 +1,393 @@
+// 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.
+
+#if defined(CONFIG_DM_INTERFACE)
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
+#include <linux/types.h>
+#endif
+#include <linux/if_packet.h>
+#include <assert.h>
+#include <pthread.h>
+#include <netinet/in.h>
+
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "cm.h"
+#include "exitcb.h"
+
+#if defined(CONFIG_DM_NET_DEVICE)
+#define ETHERNET_DEVICE		CONFIG_DM_NET_DEVICE
+#else
+#define ETHERNET_DEVICE		"eth0"
+#endif
+#define DM_TOOL_PORT		9801
+
+//#define DM_IF_DEBUG
+
+typedef struct dm_sub_s {
+	unsigned short code;
+	unsigned short op;
+	unsigned short result;
+} __attribute__((packed)) dm_sub_t;
+
+/*HCI*/
+#define WIMAX_MON_TOOL_REQUEST			0x0326
+#define WIMAX_MON_TOOL_REPORT			0x8327
+	#define MANUAL_CONNECT				0x0014
+	#define CODE_CONNECT				0x0015
+	#define CODE_DISCONNECT				0x0016
+	#define OP_REQUEST					0x0000
+	#define OP_RESPONSE					0x0001
+	#define RET_SUCCESS					0x0000
+	#define RET_FAILURE					0x0001
+
+extern int get_first_odev(void);
+extern APIHAND cm_api_handle;
+static pthread_t dm_thread;
+static int dm_listener;
+
+int dmif_init(void);
+int dmif_deinit(void);
+
+static int get_ip(const char *dev_name, char *ip)
+{
+#define sizeof_sa_sin_port	2
+#define inaddrr(x) (*(struct in_addr *) &ifr.x[sizeof_sa_sin_port])
+	struct ifreq ifr;
+	int fd;
+	int ret = 0;
+
+	fd = socket(PF_PACKET, SOCK_DGRAM, IPPROTO_IP);
+	if (fd < 0) {
+		cm_printf("Socket error %s(%d)\n", strerror(errno), errno);
+		return -1;
+	}
+
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, dev_name, IFNAMSIZ);
+	if ((ret = ioctl(fd, SIOCGIFADDR, &ifr)) < 0) {
+		cm_printf("ioctl SIOCGIFFLAGS %s(%d)\n", strerror(errno), errno);
+		goto out;
+	}
+	strcpy(ip, inet_ntoa(inaddrr(ifr_addr.sa_data)));
+	
+	#if defined(DM_IF_DEBUG)
+	cm_printf("ip: %s\n", ip);
+	#endif
+
+out:
+	close(fd);
+	return ret;
+}
+
+int send_dm_tool(void *data, int len)
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+	#if defined(DM_IF_DEBUG)
+	hci_t *hci = (hci_t *) data;
+	#endif
+	int cfd = pconf->dm_interface_cfd;
+	int ret;
+
+	if (cfd <= 0) {
+		cm_printf("Invalied DM Tool's file descriptor\n");
+		return 0;
+	}
+
+	ret = send(cfd, data, len, 0);
+	#if defined(DM_IF_DEBUG)
+	cm_printf("Sent: 0x%04X, %d(%d)\n", _B2H(hci->cmd_evt), _B2H(hci->length), ret);
+	#endif
+	return ret;
+}
+
+int dm_ind_connetion(int connect, int success)
+{
+	char buf[HCI_MAX_PACKET] __attribute__((aligned(4)));
+	hci_t *hci = (hci_t *) buf;
+	dm_sub_t *dsub = (dm_sub_t *) hci->data;
+
+	hci->cmd_evt = _H2B(WIMAX_MON_TOOL_REPORT);
+	hci->length = _H2B(sizeof(dm_sub_t));
+
+	if (connect)
+		dsub->code = _H2B(CODE_CONNECT);
+	else
+		dsub->code = _H2B(CODE_DISCONNECT);
+
+	dsub->op = _H2B(OP_RESPONSE);
+
+	if (success)
+		dsub->result = _H2B(RET_SUCCESS);
+	else
+		dsub->result = _H2B(RET_FAILURE);
+
+	return send_dm_tool(buf, HCI_HEADER_SIZE+sizeof(dm_sub_t));
+}
+
+static int dm_handle_host_cmd(GDEV_ID_P pID, hci_t *hci)
+{
+	dm_sub_t *dsub = (dm_sub_t *) hci->data;
+	WIMAX_API_NSP_INFO NSPInfo;
+	int list_cnt = 1;
+	int ret = 0;
+	
+	if (_B2H(hci->cmd_evt) == WIMAX_MON_TOOL_REQUEST) {
+		switch (_B2H(dsub->code)) {
+			case CODE_CONNECT:			
+				if (GAPI_GetNetworkList(pID, &NSPInfo, (UINT32 *) &list_cnt)
+					!= GCT_API_RET_SUCCESS) {
+					cm_eprintf("Get network list failure\n");
+					ret = -1;
+				}
+				else if (!list_cnt) {
+					cm_eprintf("Network list is 0\n");
+					ret = -1;
+				}
+				else if (GAPI_CmdConnectToNetwork(pID, NSPInfo.NSPName, 0)
+					!= GCT_API_RET_SUCCESS) {
+					cm_eprintf("Connect failure\n");
+					ret = -1;
+				}
+
+				if (ret < 0)
+					dm_ind_connetion(1, 0);
+				break;
+			case CODE_DISCONNECT:
+				if (GAPI_CmdDisconnectFromNetwork(pID) != GCT_API_RET_SUCCESS) {
+					cm_eprintf("Disconnect failure\n");
+					dm_ind_connetion(0, 0);
+				}
+				break;
+			case MANUAL_CONNECT:
+				if (_B2H(dsub->op) == 0)
+					cm_enable_auto_connet(1, get_first_odev());
+				else
+					cm_enable_auto_connet(0, 0);
+				break;
+		}
+		ret = 1;
+	}
+
+	return ret;
+}
+
+static int accept_dm_hci(int sfd)
+{
+	cm_common_conf_t *pconf = &cm_common_conf;
+	char buf[HCI_MAX_PACKET] __attribute__((aligned(4)));
+	hci_t *hci = (hci_t *) buf;
+	GDEV_ID ID;
+	struct sockaddr_in	saddr_c;
+	int cfd, ret, len, hci_len;
+	unsigned int ulen = sizeof(struct sockaddr);
+
+	cm_printf("Wait for DM tool to be accepted...\n");
+	if ((pconf->dm_interface_cfd = cfd = 
+		accept(sfd, (struct sockaddr *)&saddr_c, &ulen)) < 0) {
+		cm_printf("accept error %s(%d)\n", strerror(errno), errno);
+		return -1;
+	}
+	cm_printf("Accepted %s\n", inet_ntoa(saddr_c.sin_addr));
+
+	ID.apiHandle = cm_api_handle;
+
+	while (1) {
+		if ((len = ret = recv(cfd, buf, sizeof(buf), 0)) < 0) {
+			if (errno == ECONNRESET) {
+				ret = 0;
+				break;
+			}
+			cm_printf("read error %s(%d)\n", strerror(errno), errno);
+			break;
+		}
+		if (!ret)
+			break;
+
+		if (ret < HCI_HEADER_SIZE) {
+			cm_printf("Invalid length(%d)\n", ret);
+			continue;
+		}
+
+		if (!(ID.deviceIndex = get_first_odev())) {
+			cm_printf("There is no any attached device!!\n");
+			continue;
+		}
+
+		hci = (hci_t *) buf;
+		while (len >= HCI_HEADER_SIZE) {
+			hci_len = _B2H(hci->length);
+
+			#if defined(DM_IF_DEBUG)
+			cm_printf("DM: 0x%04X(%d), len=%d\n", _B2H(hci->cmd_evt), hci_len, len);
+			#endif
+
+			if (!dm_handle_host_cmd(&ID, hci)) {
+				if (GAPI_WriteHCIPacket(&ID, (char *) hci, HCI_HEADER_SIZE+hci_len)
+					!= GCT_API_RET_SUCCESS) {
+					cm_eprintf("Write HCI Failed\n");
+					goto out;
+				}
+			}
+
+			hci = (hci_t *) ((char *) hci + HCI_HEADER_SIZE + hci_len);
+			len -= HCI_HEADER_SIZE + hci_len;
+		}
+
+		if (len > 0)
+			cm_printf("Unhandled length is %d\n", len);
+	}
+out:
+	pconf->dm_interface_cfd = -1;
+	close(cfd);
+	return ret;
+}
+
+static void *dm_receiver_thread(void *data)
+{
+	const char *dev_name = (const char *) data;
+	struct sockaddr_in	saddr_s;
+	char ip[32];
+	int port = DM_TOOL_PORT;
+	int ret;
+
+	if (get_ip(dev_name, ip) < 0)
+		return NULL;
+
+	memset(&saddr_s, 0, sizeof(saddr_s));
+
+	saddr_s.sin_family = AF_INET;	/* AF_INET, PF_INET are same */
+	if (inet_aton(ip, &saddr_s.sin_addr) < 0) {
+		cm_printf("Fail: inet_aton %s\n", ip);
+		ret = -1;
+		goto out;
+	}
+	saddr_s.sin_port = htons(port);
+
+	if ((dm_listener = ret = socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) < 0) {
+		cm_printf("DM socket error %s(%d)\n", strerror(errno), errno);
+		goto out;
+	}
+	if ((ret = bind(dm_listener, (struct sockaddr *) &saddr_s, 
+		sizeof(struct sockaddr_in))) < 0) {
+		cm_printf("DM bind error %s(%d)\n", strerror(errno), errno);
+		goto out;
+	}
+	listen(dm_listener, 1);
+
+	while (1) {
+		if ((ret = accept_dm_hci(dm_listener)) < 0) {
+			cm_printf("accept_dm_hci error\n");
+			break;
+		}
+	}
+out:
+	if (dm_listener > 0) {
+		close(dm_listener);
+		dm_listener = 0;
+	}
+	return NULL;
+}
+
+static int dm_receiver_create(void)
+{
+	pthread_create(&dm_thread, NULL, dm_receiver_thread, ETHERNET_DEVICE);
+	return 0;
+}
+
+static int dm_stop_bmode(void)
+{
+	const u8 stop_packet[] = {0x00, 0x04, 0x00, 0x02, 0xAD, 0xBC, 0x7E};
+	GDEV_ID ID;
+	char buf[HCI_MAX_PACKET] __attribute__((aligned(4)));
+	hci_t *hci = (hci_t *) buf;
+	int ret = 0, len;
+
+	ID.apiHandle = cm_api_handle;
+	if (!(ID.deviceIndex = get_first_odev())) {
+		cm_printf("There is no any attached device!!\n");
+		return -1;
+	}
+
+	len = sizeof(stop_packet);
+	hci->cmd_evt = _H2B(WIMAX_DM_CMD);
+	hci->length = _H2B(len);
+	memcpy(hci->data, stop_packet, len);
+
+	if (GAPI_WriteHCIPacket(&ID, buf, HCI_HEADER_SIZE+len) != GCT_API_RET_SUCCESS) {
+		cm_printf("Write HCI Failed\n");
+		ret = -1;
+	}
+	return ret;
+}
+
+static int dm_receiver_delete(void)
+{
+	pthread_t thread;
+	int ret = 0;
+
+	if ((thread = dm_thread)) {
+		dm_thread = (pthread_t) NULL;
+		pthread_cancel(thread);
+		pthread_join(thread, NULL);
+		if (dm_listener > 0) {
+			close(dm_listener);
+			dm_listener = 0;
+		}
+
+		ret = dm_stop_bmode();
+	}
+
+	return ret;
+}
+
+static void cb_dm_deinit(int signal/*, void *info*/)
+{
+	dmif_deinit();
+}
+
+int dmif_init(void)
+{
+	int ret;
+
+	register_exit_cb(cb_dm_deinit);
+
+	ret = dm_receiver_create();
+	return ret;
+}
+
+int dmif_deinit(void)
+{
+	int ret;
+
+	unregister_exit_cb(cb_dm_deinit);
+
+	ret = dm_receiver_delete();
+	return ret;
+}
+#endif
+
diff --git a/cm/exitcb.c b/cm/exitcb.c
new file mode 100644
index 0000000..fa444e5
--- /dev/null
+++ b/cm/exitcb.c
@@ -0,0 +1,145 @@
+// 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 <signal.h>
+#include <string.h>
+#include <strings.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "cm.h"
+
+#define MAX_EXIT_CB_CNT		8
+
+typedef void (*exit_cb_t)(int);
+
+static int signal_active = 0;
+static exit_cb_t exit_cb_list[MAX_EXIT_CB_CNT];
+static int control_signals[] = {
+#if 0
+	SIGKILL,
+	SIGQUIT,
+	SIGTSTP,
+	SIGABRT,
+	SIGTERM,
+	SIGSEGV,
+#endif
+	SIGINT
+};
+
+static int ignore_signals[] = {
+	SIGPIPE
+};
+
+
+int register_exit_cb(void (*cb)(int sig))
+{
+	exit_cb_t *cb_list = exit_cb_list;
+	int i;
+
+	for (i = 0; i < MAX_EXIT_CB_CNT; i++) {
+		if (cb_list[i] == cb)
+			return -1;
+	}
+    
+	for (i = 0; i < MAX_EXIT_CB_CNT; i++) {
+		if (NULL == cb_list[i]) {
+			cb_list[i] = (void *)cb;
+			return 0;
+		}
+	}
+
+	assert(0);
+	return -1;
+}
+
+int unregister_exit_cb(void (*cb)(int sig))
+{
+	exit_cb_t *cb_list = exit_cb_list;
+	int i;
+
+	for (i = 0; i < MAX_EXIT_CB_CNT; i++) {
+		if (cb_list[i] == cb) {
+			cb_list[i] = NULL;
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+static void __do_exit_cb(int sig)
+{
+	exit_cb_t *cb_list = exit_cb_list;
+	int nr_sigs = sizeof(control_signals)/sizeof(control_signals[0]);
+	int i;
+
+	for (i = 0; i < nr_sigs; i++) {
+		if (control_signals[i] == sig)
+			break;
+	}
+	assert(!sig || i < nr_sigs);
+
+	if (0 == signal_active) {
+		signal_active = 1;
+		
+		for (i = 0; i < MAX_EXIT_CB_CNT; i++) {
+			if (cb_list[i]) {
+				cb_list[i](sig);
+				cb_list[i] = NULL;
+			}
+		}
+
+		if (sig > 0) {
+			cm_printf("signal(%d) issued\n", sig);
+			exit(0);
+		}
+
+		signal_active = 0;
+	}
+}
+
+static void __ignore_signal_cb(int sig)
+{
+	cm_printf("signal(%d) ignored\n", sig);
+}
+
+static void __exit_cb(void)
+{
+	if (!signal_active)
+		cm_printf("exit() called\n");
+}
+
+void init_exit_cb(void)
+{
+	struct sigaction act;
+	int i;
+
+	atexit(__exit_cb);
+
+	memset(exit_cb_list, 0, sizeof(exit_cb_list));
+	memset(&act, 0, sizeof(act));
+
+	sigemptyset(&act.sa_mask);
+	act.sa_handler = __do_exit_cb;
+	for (i = 0; i < sizeof(control_signals)/sizeof(control_signals[0]); i++)
+		if (sigaction(control_signals[i], &act, NULL) < 0)
+			cm_eprintf("sigaction(%d) error %s(%d)\n", control_signals[i], strerror(errno), errno);
+
+	act.sa_handler = __ignore_signal_cb;
+	act.sa_flags = SA_RESTART;
+	for (i = 0; i < sizeof(ignore_signals)/sizeof(ignore_signals[0]); i++)
+		if (sigaction(ignore_signals[i], &act, NULL) < 0)
+			cm_eprintf("sigaction(%d) error %s(%d)\n", ignore_signals[i], strerror(errno), errno);
+}
+
+void process_exit_cb(void)
+{
+	__do_exit_cb(0);
+}
+
diff --git a/cm/exitcb.h b/cm/exitcb.h
new file mode 100644
index 0000000..8c5ad91
--- /dev/null
+++ b/cm/exitcb.h
@@ -0,0 +1,13 @@
+// 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.
+
+#ifndef EXITCB_H_04212008
+#define EXITCB_H_04212008
+
+int register_exit_cb(void (*cb)(int sig));
+int unregister_exit_cb(void (*cb)(int sig));
+void init_exit_cb(void);
+void process_exit_cb(void);
+
+#endif
diff --git a/cm/ind.c b/cm/ind.c
new file mode 100644
index 0000000..645cd38
--- /dev/null
+++ b/cm/ind.c
@@ -0,0 +1,600 @@
+// 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
+	
+}
diff --git a/cm/list.h b/cm/list.h
new file mode 100644
index 0000000..d748467
--- /dev/null
+++ b/cm/list.h
@@ -0,0 +1,329 @@
+// 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.
+
+#ifndef LINUX_LIST_H_12042009
+#define LINUX_LIST_H_12042009
+#include <pthread.h>
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized list entries.
+ */
+#define LIST_POISON1  ((void *) 0x00100100)
+#define LIST_POISON2  ((void *) 0x00200200)
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+struct list2_head {
+	struct list_head head;
+	pthread_mutex_t lock;
+	int cnt;
+
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+	struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+	(ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+#define INIT_LIST2(ptr) do { \
+	INIT_LIST_HEAD(&(ptr)->head);\
+	pthread_mutex_init(&(ptr)->lock, NULL);\
+	(ptr)->cnt = 0;\
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+			      struct list_head *prev,
+			      struct list_head *next)
+{
+	next->prev = new;
+	new->next = next;
+	new->prev = prev;
+	prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return TRUE after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	entry->next = LIST_POISON1;
+	entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+        __list_del(list->prev, list->next);
+        list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+				  struct list_head *head)
+{
+        __list_del(list->prev, list->next);
+        list_add_tail(list, head);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+	return head->next == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is
+ * empty _and_ checks that no other CPU might be
+ * in the process of still modifying either member
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ *
+ * @head: the list to test.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+	struct list_head *next = head->next;
+	return (next == head) && (next == head->prev);
+}
+
+static inline void __list_splice(struct list_head *list,
+				 struct list_head *head)
+{
+	struct list_head *first = list->next;
+	struct list_head *last = list->prev;
+	struct list_head *at = head->next;
+
+	first->prev = head;
+	head->next = first;
+
+	last->next = at;
+	at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+	if (!list_empty(list))
+		__list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+				    struct list_head *head)
+{
+	if (!list_empty(list)) {
+		__list_splice(list, head);
+		INIT_LIST_HEAD(list);
+	}
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:	the &struct list_head pointer.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+   ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+/**
+ * list_for_each	-	iterate over a list
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @head:	the head for your list.
+ */
+#define list_for_each(pos, head) \
+	for (pos = (head)->next; pos != (head); \
+        	pos = pos->next)
+
+/**
+ * __list_for_each	-	iterate over a list
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @head:	the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+	for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev	-	iterate over a list backwards
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @head:	the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+	for (pos = (head)->prev; pos != (head); \
+        	pos = pos->prev)
+
+/**
+ * list_for_each_safe	-	iterate over a list safe against removal of list entry
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @n:		another &struct list_head to use as temporary storage
+ * @head:	the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+	for (pos = (head)->next, n = pos->next; pos != (head); \
+		pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry	-	iterate over list of given type
+ * @pos:	the type * to use as a loop counter.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member)				\
+	for (pos = list_entry((head)->next, typeof(*pos), member);	\
+	     &pos->member != (head); 	\
+	     pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos:	the type * to use as a loop counter.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member)			\
+	for (pos = list_entry((head)->prev, typeof(*pos), member);	\
+	     &pos->member != (head); 	\
+	     pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use as a start point in
+ *			list_for_each_entry_continue
+ * @pos:	the type * to use as a start point
+ * @head:	the head of the list
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_prepare_entry(pos, head, member) \
+	((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue -	iterate over list of given type
+ *			continuing after existing point
+ * @pos:	the type * to use as a loop counter.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_continue(pos, head, member) 		\
+	for (pos = list_entry(pos->member.next, typeof(*pos), member);	\
+	     &pos->member != (head);	\
+	     pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos:	the type * to use as a loop counter.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member)			\
+	for (pos = list_entry((head)->next, typeof(*pos), member),	\
+		n = list_entry(pos->member.next, typeof(*pos), member);	\
+	     &pos->member != (head); 					\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+#endif
+
diff --git a/cm/main.c b/cm/main.c
new file mode 100644
index 0000000..a86cd9e
--- /dev/null
+++ b/cm/main.c
@@ -0,0 +1,50 @@
+// 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 <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "cm.h"
+#include "exitcb.h"
+
+#define CM_VERSION "1.4.5"
+extern int cm_init(int read_only);
+extern int cm_deinit(void);
+extern void cmd_run(void);
+
+int main(int argc, char *argv[])
+{
+	int ret;
+
+	printf("\n");
+	printf("***************************************************************************\n");
+	printf("*                                                                         *\n");
+	printf("*                 WiMax CM Text Version %5s                             *\n", CM_VERSION);
+	printf("*                 Copyright (c) 2008-2010 GCT Research, Inc.              *\n");
+	printf("*                                                                         *\n");
+	printf("***************************************************************************\n\n");	
+
+	init_exit_cb();
+
+	if (argc == 1)
+		ret = cm_init(0);	/*Read/Write Mode*/
+	else
+		ret = cm_init(1);	/*Read Only Mode*/
+
+	cmd_run();
+
+	cm_deinit();
+
+	process_exit_cb();
+
+	printf("Exit CM main\n");
+
+	return ret;
+}
diff --git a/cm/param.h b/cm/param.h
new file mode 100644
index 0000000..ff610ae
--- /dev/null
+++ b/cm/param.h
@@ -0,0 +1,246 @@
+// 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.
+
+#if !defined(PARAM_H_20090415)
+#define PARAM_H_20090415
+
+#define MAGIC					0x720F
+#define MAP_VERSION_V1		0x01
+#define MAP_VERSION_V2		0x02
+
+#define WB_INFO_BLOCK_OFFSET	0x400
+#define WB_BOARD_BLOCK_OFFSET	0x440
+#define WB_RFCAL_BLOCK_OFFSET	0x470
+
+
+struct wb_cfg_header {
+	unsigned short	magic;		// 0x720F
+	unsigned char	version;
+	unsigned char	crc;
+} __attribute__((packed));
+
+#define WB_INFO_BLOCK_OFFSET_V2			0x400
+#define WB_BOARD_BLOCK_OFFSET_V2		0x4A0
+#define WB_RFCAL_BLOCK_OFFSET_V2		0x4E0
+#define WB_TEMP_BLOCK1_OFFSET_V2		0x6F0
+#define WB_TEMP_BLOCK2_OFFSET_V2		0xB70
+#define WB_WIDE_SCAN_BLOCK_OFFSET_V2	0xFA0
+#define WB_OMA_DMT_BLOCK_OFFSET_V2		0x1500
+
+#define WB_DEV_CERT_BLOCK_OFFSET_V2		0x2500
+#define WB_CERT1_UP_BLOCK_OFFSET_V2		0x3500
+#define WB_CERT1_LO_BLOCK_OFFSET_V2		0x3D00
+#define WB_VEND_BLOCK_OFFSET_V2			0x5000
+#define WB_CERT2_BLOCK_OFFSET_V2		0x5400
+#define WB_EAP_BLOCK_OFFSET_V2			0x5C00
+#define WB_CERT3_BLOCK_OFFSET_V2		0x8400
+
+#define WB_OMA_DMT_BLOCK_SIZE			0x1000
+#define WB_MAX_CERT_BLOCK_SIZE			WB_CERT3_BLOCK_SIZE
+#define WB_DEV_CERT_BLOCK_SIZE			0x1000
+#define WB_CERT1_UP_BLOCK_SIZE			0x0800
+#define WB_CERT1_LO_BLOCK_SIZE			0x0800
+#define WB_VEND_BLOCK_SIZE				0x0400
+#define WB_CERT2_BLOCK_SIZE				0x0800
+#define WB_EAPP_BLOCK_SIZE				0x0800
+#define WB_CERT3_BLOCK_SIZE				0x5000
+
+/*
+ * struct wb_config_block_v2 defines the WiBro configuration parameters
+ * stored in either EEPROM or NOR Flash.
+ */
+struct wb_info_block_v2 {
+	unsigned short	magic;		// 0x720F
+	unsigned char	version;	// 2
+	unsigned char	crc;
+
+	unsigned char	mac_address[6];
+	
+	unsigned char	band_sel_code;
+	
+	unsigned char	fa_list_size;	// number of FA list
+	unsigned int	fa_list[16];		// frequency in kHz
+	unsigned char 	IMEI[8];
+	unsigned char	PID[12];			// Product ID
+	unsigned char	ATR_lock;	// ATR lock/unlock
+					// 0: default (KT lock0
+					// 1: Add service provider here
+					// 0xFF : unlock
+	unsigned short	freq_bitmap;	// Frequency bitmap
+	unsigned char	BS_vendor;		// For BS-vendor specific setting
+	unsigned short	USB_VID;
+	unsigned short	USB_PID;
+	unsigned char	eeprom_boot_delay;
+	unsigned char	reserved[39];
+	char            Serial[16];     // Product serial number (especially for USB serial number);
+} __attribute__((packed));
+
+
+/* struct wb_board_config_block defines the board specific
+ * configurations.
+ */
+struct wb_board_config_block_v2 {
+	unsigned short	magic;		// 0x720F
+	unsigned char	version;	// 2
+	unsigned char	crc;		// computed over the following bytes
+
+	unsigned int	rf_ctrl_polarity0;
+	unsigned int	rf_ctrl_polarity1;
+	
+	char 			tx_dynamic_corr_fact;	// Tx dynamic correction factor
+	char	mt_ofs1;	// for manual tuning
+	char 	mt_ofs2;
+
+	char	uicc_level_trans;   // For internal UICC, level translator is controlled by this setting
+	/* Ethan2007.03.19 - Add 16-bytes for LED control */
+	char			reserved[12];
+	unsigned short	leds[8];
+
+	char			reserved1[20];
+} __attribute__((packed));
+
+
+#define CALTBL_NUM	16
+
+/*
+ * struct wb_rf_calibr_block defines the WiBro RF calibration
+ * information stored in either EEPROM or NOR Flash.
+ */
+struct wb_rf_calibr_block_v2 {
+	unsigned short	magic;		// 0x720F
+	unsigned char	version;	// 2
+	unsigned char	crc;		// computed over the following bytes
+
+	/* Common fields */
+	char			valid;
+	char			dcc_offset_i;
+	char			dcc_offset_q;
+	char			rx_i_imb;
+	char			rx_q_imb;
+	unsigned short	pags_th;
+	unsigned char	pags_gpio;
+	char 			max_tpwr;
+	char			c_gs_par;
+	char			reserved[2];
+
+	/* Per channel data */
+	struct {
+		unsigned 	valid: 8;	// Bit0: Cal, Bit1: DCC-OFS, Bit2: DCC-VAL
+		unsigned 	freq: 24;		// kHz
+		char		rssi_ofs0[3];
+		char		rssi_ofs1[3];
+		unsigned char tc_rssi;		// Temp value measured while RSSI cal
+		char		cinr_ofs[2];	// CINR ofs for main/diversity
+		unsigned char tpwr_valid;	// power_ofs is applied when this flas is 1
+		unsigned char tc_tpwr;		// Temp value measured while TX power cal
+		char		power_ofs[10];	// for 10-point tx power cal
+		char		gs_par1;
+		char		gs_par2;
+		char		gs_th;
+		char		mt_ofs1;
+		char		mt_ofs2;
+		char		reserved[2];
+	} __attribute__((packed)) cal_tbl[CALTBL_NUM];
+} __attribute__((packed));
+
+/*
+ * struct wb_temp_block_v2 defines the WiBro RF calibration
+ * information stored in either EEPROM or NOR Flash.
+ */
+struct wb_temp_block_v2 {
+	unsigned short	magic;		// 0x720F
+	unsigned char	version;	// 2
+	unsigned char	crc;		// computed over the following bytes
+
+	/* Common fields */
+	char			valid;
+	unsigned char	ofs23_adc_idx[47];	// 43-point thermistor value per temperature for Tx power temperature compensation
+	char			reserved[1];
+	unsigned char 	rssi_adc_idx[11];	// 11-point thermistor value per temperature for RSSI temperature compensation
+	char 			reserved1[16];
+	char			rssi_cf[3][11];
+	char			reserved2[15];
+
+	/* Per channel data */
+	struct {
+		unsigned 	valid: 8;	// Bit0: Cal, Bit1: DCC-OFS, Bit2: DCC-VAL
+		unsigned 	freq: 24;		// kHz
+		char		ofs23_cf[47];
+		char		reserved[1];
+		char cpara_cf[9][7];
+		char		reserved1[13];
+	} __attribute__((packed)) temp_tbl[CALTBL_NUM];
+} __attribute__((packed));
+
+struct wb_temp_common_block_v2 {
+	unsigned short	magic;		// 0x720F
+	unsigned char	version;	// 2
+	unsigned char	crc;		// computed over the following bytes
+
+	/* Common fields */
+	char			valid;
+	unsigned char	ofs23_adc_idx[47];	// 43-point thermistor value per temperature for Tx power temperature compensation
+	char			reserved[1];
+	unsigned char 	rssi_adc_idx[11];	// 11-point thermistor value per temperature for RSSI temperature compensation
+	char 			reserved1[16];
+	char			rssi_cf[3][11];
+	char			reserved2[15];
+	char			fa[0];
+} __attribute__((packed));
+
+#define MAX_WIDE_SCAN_CHAN_PLAN		4
+
+/* Channel Plan for Wide Scan */
+
+struct wide_cp {
+	unsigned int	valid:8;
+	unsigned int	first_freq:24;
+	unsigned int	bw:8;
+	unsigned int	last_freq:24;
+	unsigned int	freq_step:16;
+	unsigned int	dummy:16;
+} __attribute__((packed));
+
+/*
+ * struct wb_wide_scan_block defines the board specific
+ * configurations.
+ */
+struct wb_wide_scan_block_v2 {
+	unsigned short	magic;		// 0x720F
+	unsigned char	version;	// 2
+	unsigned char	crc;		// computed over the following bytes
+
+	struct wide_cp	cp[MAX_WIDE_SCAN_CHAN_PLAN];
+} __attribute__((packed));
+
+
+#define MAX_OMA_DATA_SIZE	(0x1000 - 8)
+struct wb_oma_block_v2 {
+	unsigned short	magic;		// 0x720F
+	unsigned char	version;	// 2
+	unsigned char	crc;		// computed over the following bytes
+
+	unsigned int	length;
+	unsigned char	c_tree[MAX_OMA_DATA_SIZE];	// Compressed OMA Tree image
+} __attribute__((packed));
+
+struct wb_temp_fa_block_v2 {
+	unsigned 	valid: 8;	// Bit0: Cal, Bit1: DCC-OFS, Bit2: DCC-VAL
+	unsigned 	freq: 24;		// kHz
+	char		ofs23_cf[47];
+	char		reserved[1];
+	char 		cpara_cf[9][7];
+	char		reserved1[13];
+} __attribute__((packed));
+
+struct wb_temp_block1_v2 {
+	struct wb_temp_common_block_v2 common;
+	struct wb_temp_fa_block_v2 fa[8];
+} __attribute__((packed));
+
+struct wb_temp_block2_v2 {
+	struct wb_temp_fa_block_v2 fa[8];
+} __attribute__((packed));
+
+#endif
diff --git a/cm/profilestring.c b/cm/profilestring.c
new file mode 100644
index 0000000..c1fb3d1
--- /dev/null
+++ b/cm/profilestring.c
@@ -0,0 +1,336 @@
+// 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 <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <assert.h>
+
+#if defined(_WIN32) || defined(_WIN64)
+#pragma warning(disable : 4996)
+#define LINE_FEED_STR		"\r\n"
+#define BINARY_MODE			"b"
+#else
+#define LINE_FEED_STR		"\n"
+#define BINARY_MODE
+#endif
+#define LSECT_DELIMITER		'['
+#define RSECT_DELIMITER		']'
+#define KEY_DELIMITER		'='
+#define IS_LINEFEED(c)		((c) == '\r' || (c) == '\n')
+#define IS_TAB_SPACE(c)		((c) == ' ' || (c) == '\t')
+#define IS_COMMENT(c)		((c) == '#' || (c) == ';')
+#define BASE_BUF_SIZE		1024
+
+#if 0
+#define chrcmp(c1,c2)		((c1)==(c2)
+#else
+#define chrcmp(c1,c2)		(toupper(c1)==toupper(c2))
+#endif
+
+static int cp_key_value(char *buf, const char *line, int n)
+{
+	char *d = buf;
+
+	while (n--) {
+		if (IS_TAB_SPACE(*line)) {
+			line++;
+			continue;
+		}
+		if (IS_LINEFEED(*line)) {
+			if (n)
+				*d++ = 0;
+			break;
+		}
+		if (!(*d = *line)) 
+			break;
+		d++;
+		line++;
+	}
+	return d - buf;
+}
+
+static int cp_value(char *buf, const char *value, int n)
+{
+	char *d = buf;
+
+	while (n--) {
+		if (IS_TAB_SPACE(*value)) {
+			value++;
+			continue;
+		}
+		if (IS_LINEFEED(*value)) {
+			if (n)
+				*d = 0;
+			break;
+		}
+		if (!(*d = *value)) 
+			break;
+		d++;
+		value++;
+	}
+	return d - buf;
+}
+
+static int get_section(const char *line, char *section)
+{
+	char *pos = section;
+
+	if (*line++ != LSECT_DELIMITER)
+		return 0;
+
+	while (*line && !IS_LINEFEED(*line) && *line != RSECT_DELIMITER)
+		*pos++ = *line++;
+
+	if (*line == RSECT_DELIMITER) {
+		*pos++ = 0;
+		return pos-section;
+	}
+	else
+		return 0;
+}
+
+static const char * find_section(const char *line, const char *section)
+{
+	if (*line++ != LSECT_DELIMITER)
+		return NULL;
+
+	while (chrcmp(*line, *section)) {
+		line++;
+		section++;
+	}
+
+	if (!*section && *line == RSECT_DELIMITER)
+		return section;
+	else
+		return NULL;
+}
+
+static const char * find_key(const char *line, const char *key)
+{
+	while (chrcmp(*line, *key)) {
+		line++;
+		key++;
+	}
+
+	if (!*key) {
+		if (*line != KEY_DELIMITER && !IS_TAB_SPACE(*line))
+			return NULL;
+		while (*line && *line != KEY_DELIMITER)
+			line++;
+		if (*line == KEY_DELIMITER) {
+			return ++line;
+		}
+	}
+	return NULL;
+}
+
+int get_profile_section(const char *section, char *buf, int buf_size, const char *file)
+{
+	FILE *fp;
+	char line[BASE_BUF_SIZE];
+	const char *val = NULL;
+	char *pos = buf;
+	int available = buf_size;
+	int len;
+
+	if (!buf || !buf_size || !file) {
+		errno = EINVAL;
+		return 0;
+	}
+
+	if ((fp = fopen(file, "r"BINARY_MODE)) == NULL)
+		return 0;
+
+	while (fgets(line, sizeof(line), fp)) {
+		if ((val = find_section(line, section)))
+			break;
+	}
+
+	if (val) {
+		val = NULL;
+		while (available > 0 && fgets(line, sizeof(line), fp)) {
+			if (*line == LSECT_DELIMITER)
+				break;
+			if (IS_COMMENT(*line) || IS_TAB_SPACE(*line))
+				continue;
+			len = cp_key_value(pos, line, available);
+			available -= len;
+			pos += len;
+		}
+		if (available > 0)
+			*pos++ = 0;
+	}
+
+	fclose(fp);
+	return pos - buf;
+}
+
+int get_profile_section_names(char *buf, int buf_size, const char *file)
+{
+	FILE *fp;
+	char line[BASE_BUF_SIZE];
+	char *pos = buf;
+
+	if (!buf || !buf_size || !file) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if ((fp = fopen(file, "r"BINARY_MODE)) == NULL)
+		return -1;
+
+	while (fgets(line, sizeof(line), fp))
+		pos += get_section(line, pos);
+
+	*pos++ = 0;
+
+	fclose(fp);
+	return pos - buf;
+}
+
+int get_profile_string(const char *section, const char *key, const char *default_str,
+	char *buf, int buf_size, const char *file)
+{
+	FILE *fp;
+	char line[BASE_BUF_SIZE];
+	const char *val = NULL;
+	int len;
+
+	if (!section || !*section || !key || !*key || !buf || !buf_size || !file) {
+		errno = EINVAL;
+		return 0;
+	}
+
+	if ((fp = fopen(file, "r"BINARY_MODE)) == NULL)
+		goto default_value;
+
+	while (fgets(line, sizeof(line), fp)) {
+		if ((val = find_section(line, section)))
+			break;
+	}
+
+	if (val) {
+		val = NULL;
+		while (fgets(line, sizeof(line), fp)) {
+			if (*line == LSECT_DELIMITER)
+				break;
+			if (IS_COMMENT(*line))
+				continue;
+			if ((val = find_key(line, key)))
+				break;
+		}
+	}
+
+	fclose(fp);
+default_value:
+	if (!val) {
+		if (!default_str) {
+			errno = EINVAL;
+			return 0;
+		}
+		val = default_str;
+	}
+
+	len = cp_value(buf, val, buf_size);
+	return len;
+}
+
+int write_profile_string(const char *section, const char *key, const char *str,
+	const char *file)
+{
+	FILE *fp;
+	char line[BASE_BUF_SIZE];
+	const char *find = NULL;
+	char *rest_data = NULL;
+	int rpos = 0, wpos = 0, eof, len, ret = 0;
+
+	if (!section || !*section || !key || !*key || !str || !file) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (!(fp = fopen(file, "r+"BINARY_MODE))) {
+		if (!(fp = fopen(file, "w"BINARY_MODE)))
+			return -1;
+		goto append_section;
+	}
+
+	while (fgets(line, sizeof(line), fp)) {
+		if ((find = find_section(line, section)))
+			break;
+	}
+
+	if (find) {
+		find = NULL;
+		while (fgets(line, sizeof(line), fp)) {
+			if (*line == LSECT_DELIMITER) {
+				find = line;
+				if (!wpos)
+					wpos = rpos = ftell(fp) - strlen(line);
+				break;
+			}
+			if (IS_COMMENT(*line))
+				continue;
+			if (IS_LINEFEED(*line)) {
+				if (!wpos)
+					wpos = rpos = ftell(fp) - strlen(line);
+				continue;
+			}
+			if ((find = find_key(line, key))) {
+				rpos = ftell(fp);
+				wpos = rpos - strlen(line);
+				break;
+			}
+		}
+		if (find == NULL) {
+			len = strlen(line);
+			if (!IS_LINEFEED(line[len-1]) && !IS_LINEFEED(line[len-2]))
+				fputs(LINE_FEED_STR, fp);
+			goto append_key;	/*end of file*/
+		}
+	}
+
+	if (find) {
+		fseek(fp, 0, SEEK_END);
+		eof = ftell(fp);
+		fseek(fp, rpos, SEEK_SET);
+
+		len = eof - rpos;
+		rest_data = malloc(len);
+		assert(rest_data);
+		if (len != fread(rest_data, 1, len, fp)) {
+			ret = -1;
+			goto close;
+		}
+
+		/*Overwrite*/
+		fseek(fp, wpos, SEEK_SET);
+		sprintf(line, "%s=%s%s", key, str, LINE_FEED_STR);
+		fputs(line, fp);
+		if (len != fwrite(rest_data, 1, len, fp)) {
+			ret = -1;
+			goto close;
+		}
+	}
+	else {
+		len = strlen(line);
+		if (!IS_LINEFEED(line[len-1]) && !IS_LINEFEED(line[len-2]))
+			fputs(LINE_FEED_STR, fp);
+append_section:
+		sprintf(line, "[%s]%s", section, LINE_FEED_STR);
+		fputs(line, fp);
+append_key:
+		sprintf(line, "%s=%s%s", key, str, LINE_FEED_STR);
+		fputs(line, fp);
+	}
+close:
+	fclose(fp);
+	if (rest_data)
+		free(rest_data);
+	return ret;
+}
+
diff --git a/cm/profilestring.h b/cm/profilestring.h
new file mode 100644
index 0000000..3668e7f
--- /dev/null
+++ b/cm/profilestring.h
@@ -0,0 +1,15 @@
+// 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.
+
+#if !defined(PROFILE_H_20070923)
+#define PROFILE_H_20070923
+
+int get_profile_section(const char *section, char *buf, int buf_size, const char *file);
+int get_profile_section_names(char *buf, int buf_size, const char *file);
+int get_profile_string(const char *section, const char *key, const char *default_str,
+	char *buf, int buf_size, const char *file);
+int write_profile_string(const char *section, const char *key, const char *str,
+	const char *file);
+
+#endif
diff --git a/cm/sem.c b/cm/sem.c
new file mode 100644
index 0000000..aa3b630
--- /dev/null
+++ b/cm/sem.c
@@ -0,0 +1,94 @@
+// 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 "sem.h"
+#include <sys/time.h>
+
+static struct timespec *sem_get_timespec(struct timespec *ts, int timeout_sec)
+{
+	#define ps_timeval2timespec(tv,ts)	\
+		((ts)->tv_sec = (tv)->tv_sec, (ts)->tv_nsec = (tv)->tv_usec * 1000)
+	struct timeval tv;
+
+	gettimeofday(&tv, NULL);
+	ps_timeval2timespec(&tv, ts);
+	ts->tv_sec += timeout_sec;
+	return ts;
+}
+
+int sem_init(sem_t *psem, int count)
+{
+	int ret = 0;
+
+	psem->ps_count = count;
+
+	ret = pthread_mutex_init(&psem->ps_lock, NULL);
+	ret |= pthread_cond_init(&psem->ps_cond, NULL);
+
+	return ret;
+}
+
+int sem_destroy(sem_t *psem)
+{
+	int ret = 0;
+
+	psem->ps_count = 0;
+
+	ret = pthread_mutex_destroy(&psem->ps_lock);
+	ret |= pthread_cond_destroy(&psem->ps_cond);
+
+	return ret;
+}
+
+int sem_wait(sem_t *psem)
+{
+	int ret = 0;
+
+	pthread_mutex_lock(&psem->ps_lock);
+
+	if (--psem->ps_count < 0)
+		ret = pthread_cond_wait(&psem->ps_cond, &psem->ps_lock);
+
+	pthread_mutex_unlock(&psem->ps_lock);
+
+	return ret;
+}
+
+int sem_timedwait(sem_t *psem, int timeout_sec)
+{
+	struct timespec ts;
+	int ret = 0;
+
+	pthread_mutex_lock(&psem->ps_lock);
+
+	if (--psem->ps_count < 0) {
+		if (timeout_sec) {
+			sem_get_timespec(&ts, timeout_sec);
+			ret = pthread_cond_timedwait(&psem->ps_cond, &psem->ps_lock, &ts);
+		}
+		else
+			ret = pthread_cond_wait(&psem->ps_cond, &psem->ps_lock);
+	}
+
+	pthread_mutex_unlock(&psem->ps_lock);
+
+	return ret;
+}
+
+int sem_signal(sem_t *psem)
+{
+	int ret = 0;
+
+	pthread_mutex_lock(&psem->ps_lock);
+
+	if (psem->ps_count++ < 0) {
+		pthread_mutex_unlock(&psem->ps_lock);
+		ret = pthread_cond_signal(&psem->ps_cond);
+	}
+	else
+		pthread_mutex_unlock(&psem->ps_lock);
+
+	return ret;
+}
+
diff --git a/cm/sem.h b/cm/sem.h
new file mode 100644
index 0000000..3786e0e
--- /dev/null
+++ b/cm/sem.h
@@ -0,0 +1,24 @@
+// 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.
+
+#if !defined(SEM_H_20081208)
+#define SEM_H_20081208
+
+#include <pthread.h>
+
+typedef struct sem_s {
+	int ps_count;
+	pthread_mutex_t	ps_lock;
+	pthread_cond_t	ps_cond;
+
+} sem_t;
+
+int sem_init(sem_t *psem, int count);
+int sem_destroy(sem_t *psem);
+int sem_wait(sem_t *psem);
+int sem_timedwait(sem_t *psem, int timeout_sec);
+int sem_signal(sem_t *psem);
+
+#endif
+
diff --git a/firmware/gdmuimg.bin b/firmware/gdmuimg.bin
new file mode 100644
index 0000000..481548f
--- /dev/null
+++ b/firmware/gdmuimg.bin
Binary files differ
diff --git a/sdk/ChangeLog b/sdk/ChangeLog
new file mode 100644
index 0000000..598ac3d
--- /dev/null
+++ b/sdk/ChangeLog
@@ -0,0 +1,154 @@
+v.1.6.8
+	rtd is removed from neighbor information.
+
+v.1.6.7
+	Add eap parameters.
+		T_EAP_DECORATION
+		T_EAP_RAND_SEED
+		T_EAP_SESSIONTICKET_OFF
+
+v.1.6.6
+	Fix a bug that sdk status remains being connected even until 
+	auto-connection starts.
+
+v.1.6.5
+	Fix a bug that hci timeout occurs when cr801/TLS is issued.
+
+v.1.6.4
+	Fix a bug that stack overflow occurs when mbstowcs is invoked.
+
+v.1.6.3
+	Support auto-connection for partner network.
+	Add APIs as follow
+		GAPI_CmdMACState
+		GAPI_SetIdleModeTimeout
+		GAPI_GetPHY_MAC_Basic
+		GAPI_GetPHY_MCS
+		GAPI_GetPHY_CINR_RSSI	
+
+v.1.6.2
+	Change the way deciding OMA-DM provisioning session.
+
+v.1.6.1
+	Fix a bug that if CR801 is enable and Activated node is TRUE, then WIB does 
+	not work.
+
+v.1.6
+	Support DRMD.
+
+v.1.5
+	DMC initiates a session ever polling-interval even if Activated node is false.
+	Add IP-renew indication.
+	Fix a bug that if Suspend/Hibernate is issued seg-fault occurs.
+
+v.1.4
+	Support OMA-DM for Clearwire.
+	Fix a bug start_timer is invoked while a timer callback is executed.
+	Fix a bug that WiMAX state machine is not working correctly.
+	Replace getline with fgets for portability.
+
+v.1.3.2
+	Support KT (Korea Telecom) specific 8.75/10MHz bandwidth switching function. 
+	Support PollingAttempts for OMA-DM client-initiated session.
+	Add GAPI_PrintLog API.
+	Support multiple defining of EAP-TLS and EAP-AKA.
+	Fix a bug that GAPI_GetStatistics returns invalid statistics.
+	If SIB is not notified, WIB starts in 10 seconds after IP was acquired.
+	Move the code that reads eap-log file in E-EAP into SDK.
+	Change the mechanism printing to the log file.
+	Change the way setting default log level.
+	Fix a bug that GAPI_GetConnectedNSP returns invalid RSSI & CINR value.
+	Fix a bug that if recvmsg(netlink) returns ENOBUFS, io_receiver_thread is terminated.
+
+v.1.3.1
+	Add a function updating XML after finishing an OMA-DM session.
+	Add a defense code that client initiates an OMA-DM session if digest-mismatch occurs.
+	Fix a bug that if each certificate does not include enter-char('\n') at the end of file, chaind-CA is not loaded.
+	Change the way setting operator node(<x>) to be set up dynamically.
+	Add an API that subscribes OMA-DM Package URL for FUMO.
+		GAPI_SubscribeODMFwPkgURL
+
+v.1.3
+	Fix a bug that HCI response is missed.
+		-Use hci_send_wait instead of hci_send & hci_wait.
+	Fix a bug that if device certificate is not set up, eap initialization is failed.
+	Change the way setting default log level.
+
+v.1.2.1
+	Change some error messages related to connection failure to normal message.
+	Remove some warning errors.
+
+v.1.2
+	OMA-DM client has been tested.
+	Support CR801.
+
+v.1.1.8
+	Support Wide-Scan.
+
+v.1.1.7
+	Change the way getting SDK Log.
+	Add OMA-DM client but not tested.
+
+v.1.1.6
+	Support using NULL certificate for embedded EAP.
+	Support getting neighbor list.
+	Support indicating power-mode.
+
+v.1.1.5
+	Fix a bug that checking whether a file was encrypted doesn't work.
+	Change log message time format.
+
+v.1.1.4
+	Update Eaplib v1.1.36
+	
+v.1.1.3
+	Support setting NULL certificate.
+
+v.1.1.2
+	Support setting/getting connection-complte information.
+	Fix a bug that device certificate is not set to eaplib.
+
+v.1.1.1
+	Chagne log file path.
+	Fix a bug that GAPI_GetRFInform returns failure because of permission denial in read only mode.
+	Fix a bug that malloc is NULL when network list count is 0.
+
+v.1.1
+	Support EAP-AKA.
+
+v.1.0.8
+	Support APIs getting bootloader/FW version.
+		-Add GAPI_GetBootloaderVersion
+		-Update GAPI_GetDeviceInformation
+	Support indication for scanning.
+	Support an API getting RF statistic.
+		-Add GAPI_GetRFInform
+
+v.1.0.7
+	Fix how to calculate the index of wimax device.
+
+v.1.0.6
+	Fix a bug that SDK is not working on Big-Endian machine.
+	Change certification handling from file to memory.
+	Support applying combined certification from NVRAM.
+
+v.1.0.5
+	Support disconnect-reason notification.
+
+v.1.0.4
+	Fix a bug that to open stdin is failed with error code(Bad file descriptor).
+
+v.1.0.3
+	Support eap error notification.
+
+v.1.0.2
+	Support multiple certificate files.
+
+v.1.0.1
+	Change the mechnism to wait HCI.
+
+v.1.0
+	Change HCI interface from netdevive socket to netlink socket.
+
+v.0.1
+	First update
diff --git a/sdk/Makefile b/sdk/Makefile
new file mode 100644
index 0000000..1db3235
--- /dev/null
+++ b/sdk/Makefile
@@ -0,0 +1,42 @@
+# Configuration
+-include ../.config
+
+CC = gcc
+
+SDK = gdmwimax
+SDKLIB = lib$(SDK)
+obj-sdk = device.o io.o hci.o wimax.o nds.o log.o\
+	handle.o gctapi.o sdk.o timer.o msg.o error.o eap.o \
+	 fload.o netlink_u.o pthread_sem.o
+
+.EXPORT_ALL_VARIABLES:
+
+CFLAGS += ${GFLAGS}
+CFLAGS += -Wall
+CFLAGS += -g -O0 -fPIC
+
+ifeq ("$(CONFIG_TRANSPORT_TEST)", "y")
+CFLAGS += -DTRANSPORT_TEST
+endif
+
+ifdef CONFIG_LOG_FILE_BUF_SIZE
+CFLAGS += -DCONFIG_LOG_FILE_BUF_SIZE=$(CONFIG_LOG_FILE_BUF_SIZE)
+endif
+
+ifeq ("$(CONFIG_ENABLE_BW_SWITCHING_FOR_KT)", "y")
+CFLAGS += -DCONFIG_ENABLE_BW_SWITCHING_FOR_KT=$(CONFIG_ENABLE_BW_SWITCHING_FOR_KT)
+endif
+
+ifeq ("$(CONFIG_ENABLE_SERVICE_FLOW)", "y")
+obj-sdk += sf.o
+CFLAGS += -DCONFIG_ENABLE_SERVICE_FLOW
+endif
+
+all: $(SDK)
+
+$(SDK): $(obj-sdk)
+	ar rscv $(SDKLIB).a $(obj-sdk)
+#	$(CC) -fPIC -shared -W1,-soname,$(SDKLIB).so -o $(SDKLIB).so  $(obj-sdk)
+
+clean:
+	-rm -f $(SDK) *.a *.so *.elf *.gdb *.o disa nm
diff --git a/sdk/WiMaxType.h b/sdk/WiMaxType.h
new file mode 100644
index 0000000..0b828c2
--- /dev/null
+++ b/sdk/WiMaxType.h
@@ -0,0 +1,416 @@
+// 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.
+
+#if !defined (WIMAXTYPE_H_20100310)
+#define WIMAXTYPE_H_20100310
+#include <wchar.h>
+
+/**
+ * \file WiMaxType.h
+ * WiMaxType.h
+ * Defines the data types used throughout the WiMax Common API
+ * Version 1.2.1 Novemver 2 2007
+ */
+
+#define	TYPE_EXTENSION	/*defined by GCT*/
+
+/// maximum length of a NSP name
+#define MAX_SIZE_OF_NSP_NAME       (128+1)
+
+/// maximum length of a string buffer
+#define MAX_SIZE_OF_STRING_BUFFER  256
+
+/// unsigned 8-bit
+typedef unsigned char  UINT8;
+
+/// signed 16-bit
+typedef short          INT16;
+
+/// unsigned 16-bit
+typedef unsigned short UINT16;  
+
+/// unsigned 16-bit char
+#if 1	/*In linux, sizeof(wchar_t) is 4*/
+typedef wchar_t         UCHAR16;
+#else
+typedef UINT16         UCHAR16;
+#endif
+
+//
+// INT32 and UINT32 are already defined in windows.
+//
+#ifndef _WIN32 
+#ifndef _WIN64
+
+/// signed 32-bit
+typedef int INT32;
+
+/// unsigned 32-bit
+typedef unsigned int UINT32;
+
+#endif
+#endif
+
+#ifdef	TYPE_EXTENSION
+//
+// BOOL is already defined in windows.
+//
+#ifndef _WIN32 
+#ifndef _WIN64
+#if !defined(UICC_C_20090806)
+/// signed 32-bit
+typedef int BOOL;
+#endif
+
+#endif
+#endif
+
+/// signed 64-bit
+typedef long long          INT64; 
+
+/// unsigned 64-bit
+typedef unsigned long long UINT64; 
+#endif
+
+/// 8-bit string null terminated
+typedef UINT8*  WIMAX_API_STRING; 
+
+/// 16-bit string (unicode) UTF-16 null terminated
+typedef UCHAR16* WIMAX_API_WSTRING;  
+
+/// 32-bit profile id
+/// Profile id 0 is reserve to connection without specifying a user account.
+typedef UINT32  WIMAX_API_PROFILE_ID;     
+
+/// Enumeration of all the privilege level.
+typedef enum _WIMAX_API_PRIVILEGE
+{
+	WIMAX_API_PRIVILEGE_READ_WRITE, /**< Read Write privilege access. */
+	WIMAX_API_PRIVILEGE_READ_ONLY,  /**< Read Only privilege access. */
+} WIMAX_API_PRIVILEGE;
+
+
+/// Enumeration card presence state.
+typedef enum _WIMAX_API_DEVICE_PRESENCE
+{
+	WIMAX_API_CARD_REMOVAL,         /**< card removal enum value 0 */
+	WIMAX_API_CARD_INSERTION,       /**< card insertion enum value 1 */
+} WIMAX_API_DEVICE_PRESENCE;
+
+/// Enumeration device type.
+typedef enum _WIMAX_API_DEVICE_TYPE
+{
+	WIMAX_API_DEV_TYPE_WIMAX		/**< WiMax device type */
+} WIMAX_API_DEVICE_TYPE;
+
+/// device identification structure
+typedef struct _WIMAX_API_DEVICE_ID
+{
+	UINT32				  structureSize;        /**< size of this structure. */
+	UINT32				  sdkHandle;            /**< Handle that is configured by the vendor specific SDK and usage is limited inside the SDK for vendor specific references. */
+												/**< The SDK handle is set and used only by the SDK. This can be used to identify the calling application. */
+												/**< This is an implementation specific for each vendor. */
+	WIMAX_API_PRIVILEGE	  privilege;            /**< Read only or read write */
+	UINT8				  deviceIndex;          /**< The index of the device. The device index 0 is reserved. 0 equal no device. */
+	UINT32				  apiVersion;           /**< MSB 16bits are the major release number, LSB 16 bits are the minor release number */
+    BOOL                  devicePresenceStatus; /**< The device presence status */
+} WIMAX_API_DEVICE_ID, *WIMAX_API_DEVICE_ID_P;
+
+/// Hardware ID
+typedef struct _WIMAX_API_HW_DEVICE_ID
+{
+	UINT32					structureSize;     /**< size of this structure. */
+	UINT8					deviceIndex;       /**< The index of the device. The index must stay the same for a device until the SDK is closed. */
+	UCHAR16                 deviceName[MAX_SIZE_OF_STRING_BUFFER];  /**< Name of the device. Must be the same name then the OS device name.  */
+											   /**< For windows it shall be the same name appearing in the device driver. */
+	WIMAX_API_DEVICE_TYPE   deviceType;        /**< The type of the device */
+} WIMAX_API_HW_DEVICE_ID, *WIMAX_API_HW_DEVICE_ID_P;
+
+/// Device status enum
+typedef enum _WIMAX_API_LOCK_STATUS
+{
+	WIMAX_API_DEVICE_LOCKED,    /**< Device is locked */
+	WIMAX_API_DEVICE_UNLOCKED,  /**< Device is unlocked */
+} WIMAX_API_LOCK_STATUS, *WIMAX_API_LOCK_STATUS_P;
+
+/// Network type enum
+typedef enum _WIMAX_API_NETWORK_TYPE
+{
+	WIMAX_API_HOME,              /**< Home network */
+    WIMAX_API_PARTNER,           /**< Partner network, this is a NSP in the CAPL. This is treated as a home network. */
+	WIMAX_API_ROAMING_PARTNER,   /**< Roaming partner network, this is a NSP in the RAPL. */
+	WIMAX_API_UNKNOWN            /**< Unknown network */
+} WIMAX_API_NETWORK_TYPE;
+
+/// NSP information structure
+typedef struct _WIMAX_API_NSP_INFO
+{
+	UINT32                    structureSize;                 /**< size of this structure. */
+	UCHAR16                   NSPName[MAX_SIZE_OF_NSP_NAME]; /**< the name of the NSP */
+	UINT32                    NSPid;                         /**< Identifier */
+	UINT8                     RSSI;                          /**< RSSI value */
+	UINT8                     CINR;                          /**< CINR value */  
+	WIMAX_API_NETWORK_TYPE    networkType;                   /**< Current network type */    
+} WIMAX_API_NSP_INFO, *WIMAX_API_NSP_INFO_P;
+
+/// Link status information structure
+typedef struct _WIMAX_API_LINK_STATUS_INFO
+{
+	UINT32             structureSize;      /**< size of this structure. */
+	UINT32             centerFrequency;    /**< Center frequncy of the current link from device to network, in unit of KHz */
+   	UINT8              RSSI;               /**< Mean RSSI measured by device. As according to IEEE 802.16 standard, values are ranging from 0x00 to 0x53, where -123dBm is encoded as 0x00 and -40dBm encoded as 0x53 with 1dB increments. */ 
+	UINT8              CINR;               /**< Mean RSSI measured by device. As according to IEEE 802.16 standard, values are ranging from 0x00 to 0x3F, where -10dB is encoded as 0x00 and 53dB encoded as 0x3F with 1dB increments. */
+	UINT8              txPWR;              /**< Average transmit power for the last burst transmitted by the device. Based on IEEE802.16 standard, the values are ranging from 0xxx to 0xFF, where -84dBm is encoded as 0x00  and 43.5dBm is encoded as 0xFF with 0.5dB increment. */
+	UINT8              bsId[6];            /**< BS ID of the current serving BS as received from the network */
+} WIMAX_API_LINK_STATUS_INFO, *WIMAX_API_LINK_STATUS_INFO_P;
+
+/// Profile information structure
+typedef struct _WIMAX_API_PROFILE_INFO
+{
+	UINT32                structureSize;                          /**< size of this structure. */
+	WIMAX_API_PROFILE_ID  profileID;                              /**< profile ID. Profile id 0 is reserve to connection without specifying a user account. */
+	UCHAR16               profileName[MAX_SIZE_OF_STRING_BUFFER]; /**< profile name. The profile name is the name from teh OMA-DM tree.*/ 
+} WIMAX_API_PROFILE_INFO, *WIMAX_API_PROFILE_INFO_P;
+
+/// Device version
+typedef struct _WIMAX_API_DEVICE_VERSION
+{
+	UINT32    structureSize;                      /**< size of this structure. */
+	UCHAR16   name[MAX_SIZE_OF_STRING_BUFFER];    /**< name of the parts, such as ASIC, Board, RF, SW System. */
+	UCHAR16   version[MAX_SIZE_OF_STRING_BUFFER]; /**< Version of the part */
+} WIMAX_API_DEVICE_VERSION, *WIMAX_API_DEVICE_VERSION_P;
+
+/// Device information structure
+typedef struct _WIMAX_API_DEVICE_INFO
+{
+	UINT32                      structureSize;            /**< size of this structure. */
+	WIMAX_API_DEVICE_VERSION    hwVersion;                /**< Hardware version */
+	WIMAX_API_DEVICE_VERSION    swVersion;                /**< SW version */
+	WIMAX_API_DEVICE_VERSION    rfVersion;                /**< RF version */
+	WIMAX_API_DEVICE_VERSION    asicVersion;              /**< ASIC Version */
+ 	UINT8                       macAddress[6];            /**< AS defined by IEEE802.16 standard, 48bits device MAC address */
+	UCHAR16                     vendorName[MAX_SIZE_OF_STRING_BUFFER]; /**< Name of the hardware vendor */
+	BOOL                        vendorSpecificInfoIncl;   /**< Indicating the inclusion of vendor specific information */
+    UCHAR16                     vendorSpecificInfo[MAX_SIZE_OF_STRING_BUFFER]; /** <Vendor specific information */
+} WIMAX_API_DEVICE_INFO, *WIMAX_API_DEVICE_INFO_P;
+
+/// Device status enum
+typedef enum _WIMAX_API_DEVICE_STATUS
+{
+	WIMAX_API_DEVICE_STATUS_UnInitialized,  /**<  Device is uninitialized */
+	WIMAX_API_DEVICE_STATUS_RF_OFF_HW_SW,   /**<  Device RF Off(both H/W and S/W) */
+	WIMAX_API_DEVICE_STATUS_RF_OFF_HW,      /**<  Device RF Off(via H/W switch) */
+	WIMAX_API_DEVICE_STATUS_RF_OFF_SW,      /**<  Device RF Off(via S/W switch) */
+	WIMAX_API_DEVICE_STATUS_Ready,          /**<  Device is ready */
+	WIMAX_API_DEVICE_STATUS_Scanning,       /**<  Device is scanning */
+	WIMAX_API_DEVICE_STATUS_Connecting,     /**<  Connection in progress */
+	WIMAX_API_DEVICE_STATUS_Data_Connected	/**<  Layer 2 connected */
+} WIMAX_API_DEVICE_STATUS, *WIMAX_API_DEVICE_STATUS_P;
+
+/// Connection progress information structure
+typedef enum _WIMAX_API_CONNECTION_PROGRESS_INFO
+{
+	WIMAX_API_DEVICE_CONNECTION_PROGRESS_Ranging,                   /**< Device is in Ranging */
+	WIMAX_API_DEVICE_CONNECTION_PROGRESS_SBC,                       /**< Device is in SBC */
+	WIMAX_API_DEVICE_CONNECTION_PROGRESS_EAP_authentication_Device, /**< Device is in EAP authentication Device */
+	WIMAX_API_DEVICE_CONNECTION_PROGRESS_EAP_authentication_User,   /**< Device is in EAP authentication User */
+ 	WIMAX_API_DEVICE_CONNECTION_PROGRESS_3_way_handshake,           /**< Device is in 3-way-handshake */
+	WIMAX_API_DEVICE_CONNECTION_PROGRESS_Registration,              /**< Device is in Registration */
+	WIMAX_API_DEVICE_CONNECTION_PROGRESS_De_registration,           /**< Device is in De-registration */
+	WIMAX_API_DEVICE_CONNECTION_PROGRESS_Registered,		        /**< Device is registered (operational) */
+	WIMAX_API_DEVICE_CONNECTION_PROGRESS_Registration_DSX,          /**< Device is in Registration DSX */
+} WIMAX_API_CONNECTION_PROGRESS_INFO, *WIMAX_API_CONNECTION_PROGRESS_INFO_P;
+
+/// The ststus reason enum
+typedef enum _WIMAX_API_STATUS_REASON
+{
+	WIMAX_API_STATUS_REASON_Normal,
+	WIMAX_API_STATUS_REASON_Fail_to_connect_to_NW,           /**< Failed to complete NW entry with the selected operator (unspecified reason).  */
+	WIMAX_API_STATUS_REASON_Fail_to_connect_Ranging,         /**< Failed to complete ranging */
+	WIMAX_API_STATUS_REASON_Fail_to_connect_SBC,             /**< SBC phase failed */
+	WIMAX_API_STATUS_REASON_Fail_to_connect_EAP_AUTH_Device, /**< Security error. EAP authentication failed device level */
+	WIMAX_API_STATUS_REASON_Fail_to_connect_EAP_AUTH_user,   /**< Security error. EAP authentication failed user level */
+	WIMAX_API_STATUS_REASON_Fail_to_connect_3_Way_Handshake, /**< Security error. Handshake failed */
+	WIMAX_API_STATUS_REASON_Fail_to_connect_REG,             /**< Registration failed */
+	WIMAX_API_STATUS_REASON_Fail_to_connect_datapath	     /**< Failed to initialize the data path (failed to perform DSA to one UL and one DL SFs). */
+} WIMAX_API_STATUS_REASON;
+
+/// RF Status enum
+typedef struct _WIMAX_API_RF_SWITCHES_STATUS
+{
+	UINT32   structureSize; /**< size of this structure. */
+	BOOL     hw_RF_ON;      /**< Hardware RF is on */
+	BOOL     sw_RF_ON;      /**< Software RF is on */ 
+} WIMAX_API_RF_SWITCHES_STATUS, *WIMAX_API_RF_SWITCHES_STATUS_P;
+
+/// Connected NSP information structure
+typedef struct _WIMAX_API_CONNECTED_NSP_INFO
+{
+	UINT32                      structureSize;                 /**< size of this structure. */
+	UCHAR16                     NSPName[MAX_SIZE_OF_NSP_NAME]; /**< Name of NSP */
+	UCHAR16                     NSPRealm[MAX_SIZE_OF_NSP_NAME];/**< Name of NSP */
+	UINT32                      NSPid;                         /**< Identifier */
+	BOOL                        activated;                     /**< Is the device activated TRUE=Activated FALSE=NotActivated */
+	UINT8                       RSSI;                          /**< Mean RSSI measured by device. As according to IEEE 802.16 standard, values are ranging from 0x00 to 0x53, where -123dBm is encoded as 0x00 and -40dBm encoded as 0x53 with 1dB increments. */
+	UINT8                       CINR;                          /**< Mean RSSI measured by device. As according to IEEE 802.16 standard, values are ranging from 0x00 to 0x3F, where -10dB is encoded as 0x00 and 53dB encoded as 0x3F with 1dB increments. */
+	WIMAX_API_NETWORK_TYPE      networkType;                   /**< Current network type */
+} WIMAX_API_CONNECTED_NSP_INFO, *WIMAX_API_CONNECTED_NSP_INFO_P;
+
+/// Roaming mode
+typedef enum _WIMAX_API_ROAMING_MODE
+{  
+	WIMAX_API_ROAMING_ENABLED,  /**< Enable - Connection to roaming partner NSPs is allowed. */
+	WIMAX_API_ROAMING_DISABLED  /**< Disable - Connection to roaming partner NSPs is NOT allowed. */ 
+} WIMAX_API_ROAMING_MODE, *WIMAX_API_ROAMING_MODE_P;
+
+/// Connection statistic structure
+typedef struct _WIMAX_API_CONNECTION_STAT
+{
+	UINT32   structureSize;    /**< size of this structure. */
+	UINT32   totalRxByte;      /**< Total transmitted bytes of payload traffic*/
+	UINT32   totalTxByte;      /**< Total received bytes of payload traffic*/
+	UINT32   totalRxPackets;   /**< Total number of received packet. Equivalent to IP packet. */ 
+    UINT32   totalTxPackets;   /**< Total number of transmitted packet. Equivalent to IP packet. */
+} WIMAX_API_CONNECTION_STAT, *WIMAX_API_CONNECTION_STAT_P;
+
+/// Contact type as defined in Table 5 section A9.3.1.4.1 of NMG_OTA_Provisioning_Specifications_V0.5-OMA-DM see below. 
+/// 0 == Mandatory contact node for the operatorÂ’s Technical Support contact information. 
+/// 1 == Mandatory contact node for operatorÂ’s Subscription Portal contact information. 
+/// 2-199 == Reserved for future use. 
+/// 200-255 == operator defined URI Types (e.g.; My account, FAQ, etc.). 
+typedef UINT16 WIMAX_API_CONTACT_TYPE;
+
+/// Contact information structure
+typedef struct _WIMAX_API_CONTACT_INFO
+{
+	UINT32						structureSize;							/**< size of this structure. */
+	UCHAR16						textForURI[MAX_SIZE_OF_STRING_BUFFER];	/**< Text coming with URI. */
+																		/**< The text should be displayed to the user. The text shall be localized by the network. */
+	UCHAR16						URI[MAX_SIZE_OF_STRING_BUFFER];			/**< URI to be displayed. */
+	WIMAX_API_CONTACT_TYPE		contactType;                            /**< Contact type. */
+} WIMAX_API_CONTACT_INFO, *WIMAX_API_CONTACT_INFO_P;
+
+/// Provision operation enum
+/// When the device is not activated, receiving a update started notification can be interpreted as activating the device.
+typedef enum _WIMAX_API_PROV_OPERATION
+{
+	WIMAX_API_PROV_OPERATION_CFG_UPDATE_STARTED,                       /**< Update has started */
+	WIMAX_API_PROV_OPERATION_CFG_UPDATE_COMPLETED,	                   /**< Update has completed */
+	WIMAX_API_PROV_OPERATION_CFG_UPDATE_FAILED_NETWORK_DISCONNECT,     /**< Update failed because of network disconnect*/
+	WIMAX_API_PROV_OPERATION_CFG_UPDATE_FAILED,                        /**< Update failed */
+	WIMAX_API_PROV_OPERATION_CFG_UPDATE_FAILED_INVALID_PROVISIONING,   /**< Update failed because of invalid provisioning */
+	WIMAX_API_PROV_OPERATION_CFG_UPDATE_FAILED_BAD_AUTHENTICATION,     /**< Update failed because of authentication failure */
+	WIMAX_API_PROV_OPERATION_CFG_UPDATE_REQUEST_INITIAL_PROVISIONING,  /**< Update requested initial provisioning */
+	WIMAX_API_PROV_OPERATION_CFG_UPDATE_REQUEST_ONGOING_PROVISIONING,  /**< Update ongoing provisioning */
+	WIMAX_API_PROV_OPERATION_CFG_UPDATE_REQUEST_RESET_PROVISIONING,    /**< Update requested reset provisioning */
+	WIMAX_API_PROV_OPERATION_CFG_UPDATE_TRIGGER_CONTACT,               /**< Specifies to invoke the URI specified in the contact information. */
+																	   /**< The contactType parameter in the IndProvisioningOperation defines the contact URI to trigger. */
+																	   /**< Upon receiving the trgger contact notification, CM shall refresh the contact list by calling GetContactInformation. */
+} WIMAX_API_PROV_OPERATION;
+
+/// Package update enum
+typedef enum _WIMAX_API_PACK_UPDATE
+{
+	WIMAX_API_PACK_UPDATE_RECEIVED,                   /**< Request to download notification received. */
+	WIMAX_API_PACK_UPDATE_RECEIVED_LOWER_STACK,       /**< Update package received for firmware update only*/
+	WIMAX_API_PACK_UPDATE_RECEIVED_FULL_STACK,        /**< Update package received for firmware, SDK and driver*/
+	WIMAX_API_PACK_UPDATE_RECEIVED_OMA_DM_CLIENT,     /**< Update package received for OMA-DM client*/
+	WIMAX_API_PACK_UPDATE_STARTED,                    /**< Request to install package */
+	WIMAX_API_PACK_UPDATE_COMPLETED,                  /**< Update package successfully installed */
+	WIMAX_API_PACK_UPDATE_FAILED_NETWORK_DISCONNECTED,/**< Update package failed to install because of network disconnection*/
+	WIMAX_API_PACK_UPDATE_FAILED_INVALID_PACKAGE,     /**< Update package failed to install because of invalid package*/
+	WIMAX_API_PACK_UPDATE_FAILED_BAD_AUTHENTICATION,  /**< Update package failed to install because of bas authentication */
+	WIMAX_API_PACK_UPDATE_FAILED,                     /**< Update package failed to install */
+} WIMAX_API_PACK_UPDATE;
+
+/// Package information structure
+typedef struct _WIMAX_API_PACKAGE_INFO
+{
+	UINT32   structureSize;                       /**< size of this structure. */
+	UCHAR16  filePath[MAX_SIZE_OF_STRING_BUFFER]; /**< file path. */ 
+	UCHAR16  fileName[MAX_SIZE_OF_STRING_BUFFER]; /**< file name. */ 
+	BOOL     forceReboot;                         /**< (TRUE = Reboot required, FALSE No reboot required) 1.2 BEST PRACTICE, this f;ag shall not be used.*/
+	BOOL     mandatoryUpdate;                     /**< (TRUE = mandatory FALSE, optional) 1.2 BEST PRACTICE, this f;ag shall not be used. */
+	BOOL     warnUser;                            /**< (TRUE = warn user, FALSE = no user warning */
+} WIMAX_API_PACKAGE_INFO, *WIMAX_API_PACKAGE_INFO_P;
+
+/// Package update state
+typedef enum _WIMAX_API_PACKAGE_UPDATE_STATE
+{
+	WIMAX_API_PACKAGE_UPDATE_DELAY,		/**< Package update was not accepted by the user. */
+	WIMAX_API_PACKAGE_UPDATE_ACCEPTED,	/**< Package update was accepted by the user. */
+	WIMAX_API_PACKAGE_UPDATE_DENIED,	/**< Package update was denied by the user. */
+} WIMAX_API_PACKAGE_UPDATE_STATE;
+
+/// RF state enum
+typedef enum _WIMAX_API_RF_STATE
+{
+	WIMAX_API_RF_ON,   /**< RF is on. */
+    WIMAX_API_RF_OFF   /**< RF is off. */	
+} WIMAX_API_RF_STATE;
+
+/// Connection response enum
+typedef enum _WIMAX_API_NETWORK_CONNECTION_RESP
+{
+	WIMAX_API_CONNECTION_SUCCESS,     /**< connection success */
+	WIMAX_API_CONNECTION_FAILURE      /**< connection failure */ 
+} WIMAX_API_NETWORK_CONNECTION_RESP;
+
+/// IP Interface information structure
+typedef struct _WIMAX_API_INTERFACE_INFO
+{
+	UINT32   structureSize;								/**< size of this structure. */
+	UCHAR16  interfaceName[MAX_SIZE_OF_STRING_BUFFER];	/**< interface name. This is a string caption to be compatible for all OS. */ 
+} WIMAX_API_INTERFACE_INFO, *WIMAX_API_INTERFACE_INFO_P;
+
+/// The statuses provided by this API can generally be mapped to movements along the SDK common state machine. The indications may provide further detailed information using the APIÂ’s arguments when relevant.
+/// \param[in] pDeviceId - Pointer to Device Identifier passed on open of device.
+/// \param[in] deviceStatus - The device Status value
+/// \param[in] statusReason - The device status reason value
+/// \param[in] connectionProgressInfo - connection Progress value
+typedef void (*IndDeviceStatusUpdate)(WIMAX_API_DEVICE_ID_P pDeviceId, WIMAX_API_DEVICE_STATUS deviceStatus, WIMAX_API_STATUS_REASON statusReason, WIMAX_API_CONNECTION_PROGRESS_INFO connectionProgressInfo);
+
+
+/// Indicator about card insertion and removal
+/// \param[in] pDeviceId - Pointer to Device Identifier passed on open of device.
+/// \param[in] cardPresence - card presence boolean value.
+typedef void (*IndDeviceInsertRemove)(WIMAX_API_DEVICE_ID_P pDeviceId, BOOL cardPresence);
+
+
+/// Indication of RF on/off changes.  RF power may be generated from external RF off event caused by hardware switch/control.
+/// \param[in] pDeviceId - Pointer to Device Identifier passed on open of device.
+/// \param[in] powerState - Indication that the device changed this power state.
+typedef void (*IndControlPowerManagement)(WIMAX_API_DEVICE_ID_P pDeviceId, WIMAX_API_RF_STATE powerState);
+
+
+/// Network connect indication.
+/// \param[in] pDeviceId - Pointer to Device Identifier passed on open of device.
+/// \param[in] networkConnectionResponse - Connection status value.
+typedef void (*IndConnectToNetwork) (WIMAX_API_DEVICE_ID_P pDeviceId, WIMAX_API_NETWORK_CONNECTION_RESP networkConnectionResponse);
+
+
+/// Network disconnect indication.
+/// \param[in] pDeviceId - Pointer to Device Identifier passed on open of device.
+/// \param[in] networkConnectionResponse - Connection status value.
+typedef void (*IndDisconnectToNetwork) (WIMAX_API_DEVICE_ID_P pDeviceId, WIMAX_API_NETWORK_CONNECTION_RESP networkDisconnectResponse);
+
+
+/// Provide results of Wide Scan search.
+/// \param[in] pDeviceId - Pointer to Device Identifier passed on open of device.
+/// \param[in] pNspList - Pointer to a structure with information on Networks found during search.
+/// \param[in] listSize - Size of the Network list
+typedef void (*IndNetworkSearchWideScan) (WIMAX_API_DEVICE_ID_P pDeviceId, WIMAX_API_NSP_INFO_P pNspList, UINT32 listSize);
+
+
+/// Indicator for provisioning operation.
+/// \param[in]  pDeviceId - Pointer to Device Identifier passed on open of device.
+/// \param[out] pContactInfo - Provisioning information status.
+typedef void (*IndProvisioningOperation) (WIMAX_API_DEVICE_ID_P pDeviceId,  WIMAX_API_PROV_OPERATION provisoningOperation, WIMAX_API_CONTACT_TYPE contactType);
+
+
+/// Indicator for package update.
+/// \param[in]  pDeviceId - Pointer to Device Identifier passed on open of device.
+/// \param[out] packageUpdate - Package update status.
+typedef void (*IndPackageUpdate) (WIMAX_API_DEVICE_ID_P pDeviceId, WIMAX_API_PACK_UPDATE packageUpdate);
+#endif
diff --git a/sdk/device.c b/sdk/device.c
new file mode 100644
index 0000000..3552b9e
--- /dev/null
+++ b/sdk/device.c
@@ -0,0 +1,435 @@
+// 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 "global.h"
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include "error.h"
+#include "wimax.h"
+#include "wm_ioctl.h"
+#include "io.h"
+#include "device.h"
+#include "sdk.h"
+#include "log.h"
+
+#define dm_dev_ptr		dev_mng.devices
+
+dev_mng_t dev_mng;
+
+
+static void dm_cleanup_dev(int dev_idx)
+{
+	xfunc_in("dev=%d", dev_idx);
+	dm_device_lock(dev_idx);
+	if (dm_dev_ptr[dev_idx]) {
+		#if defined(FREE_DEVICE)
+		dm_dev_ptr[dev_idx]->ref_cnt = -1;
+		#endif
+		wm_cleanup_device(dev_idx);
+
+		sdk_free(dm_dev_ptr[dev_idx]);
+		dm_dev_ptr[dev_idx] = NULL;
+	}
+	dm_device_unlock(dev_idx);
+	xfunc_out();
+}
+
+static int dm_insert_device(int dev_idx, const char *dev_name, bool ind)
+{
+	dev_mng_t *dm = &dev_mng;
+	device_t *dev;
+
+	xfunc_in("dev=%d, ind=%d", dev_idx, ind);
+
+	pthread_mutex_lock(&dm->detect_lock);
+	dev = dm_dev_ptr[dev_idx];
+	
+	if (dev && dev->inserted) {
+		xprintf(SDK_ERR, "%s was already inserted\n", dev_name);
+		pthread_mutex_unlock(&dm->detect_lock);
+		return -1;
+	}
+
+	if (dm_dev_ptr[dev_idx] == NULL)
+		dm_dev_ptr[dev_idx] = (device_t *) sdk_malloc(sizeof(device_t));
+	dev = dm_dev_ptr[dev_idx];
+	memset(dev, 0, sizeof(device_t));
+	dev->inserted = TRUE;
+	strcpy(dev->name, dev_name);
+	dev->ind_thr = (pthread_t) NULL;
+	dev->net_fd = 0;
+	dev->io_nl.fd = 0;
+
+	dm->dev_cnt++;
+	pthread_mutex_unlock(&dm->detect_lock);
+
+	pthread_mutex_init(&dev->hci_wait_signal, NULL);
+	INIT_LIST_HEAD(&dev->hci_wait_list);
+
+	pthread_mutex_init(&dev->load_lock, NULL);
+
+	pthread_sem_init(&dev->sync_lock, 0);
+
+	if (ind)
+		sdk_ind_dev_insert_remove(dev_idx, TRUE);
+
+	xfunc_out("dev_cnt=%d", dm->dev_cnt);
+	return 0;
+}
+
+static int dm_remove_device(int dev_idx, const char *dev_name)
+{
+	dev_mng_t *dm = &dev_mng;
+	device_t *dev = dm_dev_ptr[dev_idx];
+	sdk_internal_t *sdk;
+
+	if (!dev) {
+		xprintf(SDK_ERR, "%s was not inserted!\n", dev->name);
+		return sdk_set_errno(ERR_INVALID);
+	}
+
+	xfunc_in("dev=%d", dev_idx);
+
+	dev->inserted = FALSE;
+
+	if ((sdk = sdk_get_rw_handle()))
+		sdk_internal_device_close(sdk, dev_idx);
+
+	sdk_ind_dev_insert_remove(dev_idx, FALSE);
+
+	hci_destroy_resp(dev_idx);
+	pthread_mutex_destroy(&dev->hci_wait_signal);
+
+	io_receiver_delete(dev_idx);
+
+	pthread_sem_destroy(&dev->sync_lock);
+
+	pthread_mutex_lock(&dm->detect_lock);
+	dm_device_lock(dev_idx);
+	#if defined(FREE_DEVICE)
+	if (!dev->ref_cnt)
+		dm_cleanup_dev(dev_idx);
+	#endif
+	dm_device_unlock(dev_idx);
+	dm->dev_cnt--;
+	pthread_mutex_unlock(&dm->detect_lock);
+
+	xfunc_out("dev_cnt=%d", dm->dev_cnt);
+	return 0;
+}
+
+static int dm_device_listup(void)
+{
+	FILE *fp;
+	char *dev_file = "/proc/net/dev";
+	char buf[512], *p_dev;
+	int index, ret = 0;
+	int dev_delimiter_pos = 6;
+
+	xfunc_in();
+	fp = fopen(dev_file, "rt");
+	if (fp == NULL) {
+		xprintf(SDK_STD_ERR, "%s fopen NULL\n", dev_file);
+		ret = sdk_set_errno(ERR_STD);
+		goto out;
+	}
+
+	while (fgets(buf, sizeof(buf), fp)) {
+		buf[dev_delimiter_pos] = '\0';
+		p_dev = strstr(buf, WM_DEV);
+		if (p_dev) {
+			if (sscanf(p_dev, WM_DEV"%d", &index) == 1) {
+				dm_insert_device(DEV_BASE_IDX+index, p_dev, FALSE);
+				ret++;
+			}
+		}
+	}
+
+	fclose(fp);
+out:
+	xfunc_out();
+	return ret;
+}
+
+static int dm_detector_open(dev_mng_t *dm)
+{
+	int fd;
+	struct sockaddr_nl sa;
+
+	fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+	if (fd < 0) {
+		xprintf(SDK_STD_ERR, "detector open\n");
+		return sdk_set_errno(ERR_STD);
+	}
+
+	memset(&sa, 0, sizeof(sa));
+	sa.nl_family = AF_NETLINK;
+	sa.nl_groups = RTMGRP_LINK;
+	sa.nl_pid = 0;
+	if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
+		xprintf(SDK_STD_ERR, "detector binding\n", fd);
+		close(fd);
+		return sdk_set_errno(ERR_STD);
+	}
+
+	dm->det_fd = fd;
+
+	xprintf(SDK_DBG, "detector open, fd=%d\n", fd);
+	return fd;
+}
+
+static void dm_detector_close(dev_mng_t *dm)
+{
+	if (dm->det_fd > 0) {
+		close(dm->det_fd);
+		xprintf(SDK_DBG, "detector close(%d)\n", dm->det_fd);
+		dm->det_fd = 0;
+	}
+}
+
+static int dm_detect_device(int fd)
+{
+	#define NETDEV_REG_UNREG	(~0U)
+	char buf[1024], *devname;
+	struct iovec iov = {buf, sizeof(buf) };
+	struct sockaddr_nl sa;
+	struct msghdr msg = {(void *)&sa, sizeof(sa), &iov, 1, NULL, 0, 0};
+	struct nlmsghdr *nlh;
+	int len, index;
+	struct ifinfomsg *ifi;
+	struct rtattr *rta;
+	int ret = 0;
+
+	assert(fd > 0);
+
+	len = recvmsg(fd, &msg, 0);
+
+	if (len <= (sizeof(struct nlmsghdr)+sizeof(struct ifinfomsg))) {
+		xprintf(SDK_STD_ERR, "recvmsg(%d), len=%d\n", fd, len);
+		ret = sdk_set_errno(ERR_STD);
+		goto out;
+	}
+
+	nlh = (struct nlmsghdr *)buf;
+	ifi = NLMSG_DATA(nlh);
+	if (ifi->ifi_change == NETDEV_REG_UNREG &&
+		(nlh->nlmsg_type == RTM_NEWLINK || nlh->nlmsg_type == RTM_DELLINK)) {
+		rta = IFLA_RTA(ifi);
+		len = nlh->nlmsg_len;
+		len -= NLMSG_LENGTH(sizeof(*ifi));
+		while (RTA_OK(rta, len)) {
+			if (rta->rta_type == IFLA_IFNAME) {
+				devname =  RTA_DATA(rta);
+				if (sscanf(devname, WM_DEV "%d", &index) == 1) {
+					if (nlh->nlmsg_type == RTM_NEWLINK)
+						ret = dm_insert_device(DEV_BASE_IDX+index, devname, TRUE);
+					else { /*RTM_DELLINK*/
+						ret = dm_remove_device(DEV_BASE_IDX+index, devname);
+						/*
+							If Suspend or Hibernate is issued,
+							device is inserted immediately after removing.
+							In that case, we need a time closing device(i.e. sdk_device_close).
+						*/
+						sleep(2);
+					}
+					if (ret < 0)
+						goto out;
+				}
+				else
+					xprintf(SDK_DBG, "Other device=%s\n", devname);
+				break;
+			}
+			rta = RTA_NEXT(rta, len);
+		}
+	}
+out:
+	return ret;
+}
+
+static void *dm_detector_thread(void *data)
+{
+	dev_mng_t *dm = (dev_mng_t *) data;
+	int fd, ret;
+
+	pthread_mutex_init(&dm->detect_lock, NULL);
+	fd = dm_detector_open(dm);
+	if (fd < 0)
+		goto out;
+
+	while (1) {
+		ret = dm_detect_device(fd);
+		if (ret < 0)
+			break;
+	}
+
+out:
+	dm_detector_close(dm);
+	return NULL;
+}
+
+int dm_init(void)
+{
+	dev_mng_t *dm = &dev_mng;
+	int ret = 0;
+
+	xfunc_in();
+
+	memset(dm, 0, sizeof(dev_mng_t));
+
+	ret = dm_device_listup();
+	if (ret >= 0)
+		pthread_create(&dm->detect_thr, NULL, dm_detector_thread, (void *)dm);
+
+	xfunc_out();
+	return ret;
+}
+
+int dm_deinit(void)
+{
+	dev_mng_t *dm = &dev_mng;
+	pthread_t thread;
+	int i;
+
+	xfunc_in();
+
+	pthread_mutex_lock(&dm->detect_lock);
+	for (i = 0; i < MAX_DEVICE; i++) {
+		if (dm_dev_ptr[i])
+			dm_cleanup_dev(i);
+	}
+	pthread_mutex_unlock(&dm->detect_lock);
+
+	if ((thread = dm->detect_thr)) {
+		dm->detect_thr = (pthread_t) NULL;
+		pthread_cancel(thread);
+		pthread_join(thread, NULL);
+	}
+
+	xfunc_out();
+	return 0;
+}
+
+device_t *dm_get_dev(int dev_idx)
+{
+	device_t *dev;
+
+	dm_device_lock(dev_idx);
+	if (!(dev = dm_dev_ptr[dev_idx])) {
+		xprintf(SDK_ERR, "device(%d) is invalid\n", dev_idx);
+		sdk_set_errno(ERR_INVALID_DEV);
+	}
+	#if defined(FREE_DEVICE)
+	else
+		dev->ref_cnt++;
+	#endif
+	dm_device_unlock(dev_idx);
+	return dev;
+}
+
+#if defined(FREE_DEVICE)
+void dm_put_dev(int dev_idx)
+{
+	device_t *dev;
+
+	dm_device_lock(dev_idx);
+	dev = dm_dev_ptr[dev_idx];
+	assert(dev);
+	if (--dev->ref_cnt == 0 && !dev->inserted)
+		dm_cleanup_dev(dev_idx);
+	dm_device_unlock(dev_idx);
+}
+#endif
+
+int dm_open_device(int dev_idx)
+{
+	device_t *dev;
+	int ret = 0;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	if (dev->open_cnt == 0) {
+		wm_open_device(dev_idx);
+		assert(dev->wimax->subs_list.head.prev && dev->wimax->subs_list.head.next);
+
+		io_receiver_create(dev_idx);
+	}
+
+	dev->open_cnt++;
+	xprintf(SDK_INFO, "[%d] open device, cnt=%d\n", dev_idx, dev->open_cnt);
+	dm_put_dev(dev_idx);
+	xfunc_out();
+	return ret;
+}
+
+int dm_close_device(int dev_idx)
+{
+	device_t *dev;
+	int ret = 0;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return 0;
+		
+	if (dev->open_cnt == 0) {
+		xprintf(SDK_ERR, "dev(%d) was not opened!\n", dev_idx);
+		ret = sdk_set_errno(ERR_INVALID);
+		goto out;
+	}
+	
+	dev->open_cnt--;
+
+	if (dev->open_cnt == 0) {
+		if (dev->inserted) {
+			if (dev->wimax->scan.sf_mode && sdk_get_rw_handle())
+				wm_disable_sf_mode(dev_idx);
+			ret = io_receiver_delete(dev_idx);
+		}
+		wm_close_device(dev_idx);
+	}
+out:
+	xprintf(SDK_INFO, "[%d] close device, cnt=%d\n", dev_idx, dev->open_cnt);
+	dm_put_dev(dev_idx);
+	xfunc_out();
+	return ret;
+}
+
+int dm_get_status(int dev_idx, int *m_status, int *c_status)
+{
+	fsm_t fsm;
+	int ret = 0;
+
+	xfunc_in("m_s=%d, c_s=%d", *m_status, *c_status);
+
+	if (net_ioctl_get_data(dev_idx, SIOC_DATA_FSM, &fsm, sizeof(fsm)) > 0) {
+		*m_status = fsm.m_status;
+		*c_status = fsm.c_status;
+	}
+
+	xfunc_out("m_s=%d, c_s=%d", *m_status, *c_status);
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+int dm_set_status(int dev_idx, int m_status, int c_status)
+{
+	fsm_t fsm;
+	int ret = 0;
+	
+	xfunc_in("m_s=%d, c_s=%d", m_status, c_status);
+
+	fsm.m_status = m_status;
+	fsm.c_status = c_status;
+	ret = net_ioctl_set_data(dev_idx, SIOC_DATA_FSM, &fsm, sizeof(fsm));
+	if (ret > 0) ret = 0;
+
+	xfunc_out("m_s=%d, c_s=%d", fsm.m_status, fsm.c_status);
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
diff --git a/sdk/device.h b/sdk/device.h
new file mode 100644
index 0000000..242a1f1
--- /dev/null
+++ b/sdk/device.h
@@ -0,0 +1,114 @@
+// 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.
+
+#if !defined(DEVICE_H_20080709)
+#define DEVICE_H_20080709
+#include "global.h"
+#include "pthread_sem.h"
+#include "hci.h"
+#include "wm_ioctl.h"
+#include "netlink_u.h"
+
+#define MAX_DEVICE		256
+#define DEV_BASE_IDX	1
+#define WM_DEV			"wm"
+
+/* #define FREE_DEVICE */
+
+typedef struct device_s {
+	bool inserted;
+	#if defined(FREE_DEVICE)
+	int ref_cnt;
+	#endif
+
+	int open_cnt;
+	char name[256];
+
+	int ifindex;
+
+	/* Indicator */
+	pthread_t ind_thr;
+
+	/*Network*/
+	int net_fd;
+
+	/*In/Out*/
+	hnetlink_t io_nl;
+
+	/*The list of entries to wait hci.*/
+	struct list_head hci_wait_list;
+	/*The signal to wake up entries that are waiting for hci.*/
+	pthread_mutex_t hci_wait_signal;
+
+	/*For UL/DL Image(or Param)*/
+	pthread_mutex_t load_lock;
+
+	/*App status*/
+	int a_status;
+
+	fsm_t fsm;
+
+	/*Synchronizer*/
+	pthread_sem_t sync_lock;
+
+	struct wimax_s *wimax;
+
+	u32 capability;
+
+	pthread_t dm_thr;
+	int dm_listener;
+} device_t;
+
+#define ENC_XML_ENABLED(dev)		(dev->capability & W_CAPABILITY_ENC_XML)
+#define E_EAP_TLS_ENABLED(dev)		(dev->capability & W_CAPABILITY_E_EAP_TLS)
+#define ODM_ENABLED(dev)			(dev->capability & W_CAPABILITY_ODM)
+#define E_EAP_AKA_ENABLED(dev)		(dev->capability & W_CAPABILITY_E_EAP_AKA)
+#define CAPL_INFO_ENABLED(dev)		(dev->capability & W_CAPABILITY_CAPL_INFO)
+#define E_EAP_ENABLED(dev)			(E_EAP_TLS_ENABLED(dev) || E_EAP_AKA_ENABLED(dev))
+
+typedef struct dev_mng_s {
+	int dev_cnt;
+	device_t *devices[MAX_DEVICE];
+
+	pthread_t detect_thr;
+	pthread_mutex_t detect_lock;
+	int det_fd;
+
+} dev_mng_t;
+
+extern dev_mng_t dev_mng;
+
+
+static __inline dev_mng_t *dm_get_dev_mng(void)
+{
+	return &dev_mng;
+}
+
+static __inline bool dm_isopen_dev(device_t *dev)
+{
+	if (dev->open_cnt == 0)
+		return FALSE;
+	else
+		return TRUE;
+}
+
+int dm_init(void);
+int dm_deinit(void);
+#define dm_tst_dev(dev_idx)		(dev_mng.devices[dev_idx])
+device_t *dm_get_dev(int dev_idx);
+#if defined(FREE_DEVICE)
+void dm_put_dev(int dev_idx);
+#define dm_device_lock(dev_idx)
+#define dm_device_unlock(dev_idx)
+#else
+#define dm_put_dev(dev_idx)	do { } while(0)
+#define dm_device_lock(dev_idx)
+#define dm_device_unlock(dev_idx)
+#endif
+int dm_open_device(int dev_idx);
+int dm_close_device(int dev_idx);
+int dm_get_status(int dev_idx, int *m_status, int *c_status);
+int dm_set_status(int dev_idx, int m_status, int c_status);
+
+#endif
diff --git a/sdk/eap.c b/sdk/eap.c
new file mode 100644
index 0000000..7f1087e
--- /dev/null
+++ b/sdk/eap.c
@@ -0,0 +1,200 @@
+// 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 <string.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "gcttype.h"
+#include "error.h"
+#include "device.h"
+#include "wimax.h"
+#include "hci.h"
+#include "fload.h"
+#include "log.h"
+#include "eap.h"
+#include "sdk.h"
+
+
+#define EAP_TMP_DIR			"./eaptmp"
+#define EAP_LOG_DIR			"eaplog"
+#define PCAP_LOG_FILE		"pcap.pcap"
+#define DEC_LOG_FILE		"dec.log"
+
+unsigned int ParsingOuterNAI(const char *Outer_NAI,			// IN
+						  char		 *routing_info,			// OUT
+						  char		 *wm_decoration,		// OUT
+						  char		 *userid,				// OUT
+						  char		 *realm)				// OUT
+{
+	char		  ch;
+	enum { OUT_SCOPE, IN_SCOPE };
+
+	unsigned char fRoutingInfo		= OUT_SCOPE;
+	unsigned char fWiMAXDecoration	= OUT_SCOPE;
+	unsigned char fRealm			= OUT_SCOPE;
+
+	unsigned int  i;
+	unsigned int  nRoutingInfo		= 0;	//index for Routing Info.
+	unsigned int  nWiMAXDecoration  = 0;	//index for wm_decoration.
+	unsigned int  nUserID			= 0;
+	unsigned int  nRealm			= 0;
+
+	if( Outer_NAI == NULL )
+		return -1;
+
+	if( strlen(Outer_NAI) == 0 )
+		return -2;
+
+	if (routing_info)
+		routing_info[0] = 0;
+	if (wm_decoration)
+		wm_decoration[0] = 0;
+	if (userid)
+		userid[0] = 0;
+	if (realm)
+		realm[0] = 0;
+
+	for( i = 0; i < strlen(Outer_NAI) ; i++ )
+	{
+		ch = Outer_NAI[i];
+
+		if( ( ch == ' ') || (ch == '\t') || (ch == '\n') || (ch == '\r')) // skip character.
+			continue;
+
+		if( ch == '[' )
+		{
+			fRoutingInfo = IN_SCOPE;
+			if (routing_info)
+				routing_info[nRoutingInfo++] = ch;
+		}
+		else if( (fRoutingInfo == IN_SCOPE ) && ( ch == ']') )
+		{
+			fRoutingInfo = OUT_SCOPE;
+			if (routing_info)
+				routing_info[nRoutingInfo++] = ch;
+		}
+		else if( fRoutingInfo == IN_SCOPE )
+		{
+			if (routing_info)
+				routing_info[nRoutingInfo++] = ch;
+		}
+		else if( ch == '{')
+		{
+			fWiMAXDecoration = IN_SCOPE;
+			if (wm_decoration)
+				wm_decoration[nWiMAXDecoration++] = ch;
+		}
+		else if( (fWiMAXDecoration == IN_SCOPE) && ( ch == '}') )
+		{
+			fWiMAXDecoration = OUT_SCOPE;
+			if (wm_decoration)
+				wm_decoration[nWiMAXDecoration++] = ch;
+		}
+		else if( fWiMAXDecoration == IN_SCOPE )
+		{
+			if (wm_decoration)
+				wm_decoration[nWiMAXDecoration++] = ch;
+		}
+		else if( ch == '@' )
+		{
+			fRealm = IN_SCOPE;
+			if (realm)
+				realm[nRealm++] = ch;
+		}
+		else if( fRealm == IN_SCOPE )
+		{
+			if (realm)
+				realm[nRealm++] = ch;
+		}
+		else
+		{
+			if (userid)
+				userid[nUserID++] = ch;
+		}
+	}
+
+	if (userid)
+		userid[nUserID]						= 0;
+	if (realm)
+		realm[nRealm]						= 0;
+	if (wm_decoration)
+		wm_decoration[nWiMAXDecoration]	= 0;
+	if (routing_info)
+		routing_info[nRoutingInfo]			= 0;	//NULL Terminated String.
+
+	return i;
+}
+
+static void *get_eaplog_thread(void *data)
+{
+	#define FW_PCAP_LOG			"/log/pcap.pcap"
+	#define FW_DEC_LOG			"/log/dec.log"
+
+	int dev_idx = (int) data;
+	const char *host_file, *target_file;
+	int ret, lmask = SDK_INFO;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	target_file = FW_PCAP_LOG;
+	host_file = sdk_mng.eap_pcap;
+	ret = fl_read_file(dev_idx, target_file, host_file, NULL);
+	if (ret > 0)
+		xprintf(lmask, "\t%s <= %s (%d bytes)\n", host_file, target_file, ret);
+
+	target_file = FW_DEC_LOG;
+	host_file = sdk_mng.eap_dec;
+	ret = fl_read_file(dev_idx, target_file, host_file, NULL);
+	if (ret > 0)
+		xprintf(lmask, "\t%s <= %s (%d bytes)\n", host_file, target_file, ret);
+
+	xfunc_out();
+	return NULL;
+}
+
+void eap_start_e_eaplog_thread(int dev_idx)
+{
+	pthread_t pthread;
+
+	xfunc_in();
+	pthread_create(&pthread, NULL, get_eaplog_thread, (void *)dev_idx);
+	pthread_detach(pthread);
+	xfunc_out();
+}
+
+void eap_prepare_log_env(int dev_idx, bool enable)
+{
+	device_t *dev;
+	static bool inited;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return;
+
+	xfunc_in();
+
+	if (enable && !inited && sdk_get_rw_handle()) {
+		char path[256];
+		char *p_pcap = sdk_mng.eap_pcap;
+		char *p_dec = sdk_mng.eap_dec;
+
+		inited = TRUE;
+
+		sprintf(path, "%s/%s", sdk_mng.log_path, EAP_LOG_DIR);
+		mkdir(path, 0644);
+
+		sprintf(p_pcap, "%s/%s", path, PCAP_LOG_FILE);
+		sprintf(p_dec, "%s/%s", path, DEC_LOG_FILE);
+	}
+
+	dm_put_dev(dev_idx);
+	xfunc_out();
+}
+
diff --git a/sdk/eap.h b/sdk/eap.h
new file mode 100644
index 0000000..362cdf3
--- /dev/null
+++ b/sdk/eap.h
@@ -0,0 +1,73 @@
+// 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.
+
+#ifndef EAP_H_20081010
+#define EAP_H_20081010
+
+#define CR801_SERVER_REJECT_LIMIT	3
+
+#define WIMAX_EAP_STR_LEN			256
+#define WIMAX_EAP_FILE_LEN			256
+#define WIMAX_EAP_MSK_LEN			64
+#define WIMAX_EAP_EMSK_LEN			64
+
+#define MAX_DECORATION_NR			2
+#define DECORATION_IDX1				0
+#define DECORATION_IDX2				1
+#define WIMAX_EAP_DECO_LEN			128
+
+#define MAX_EAP_PARAM_SIZE			256
+#define EAP_CHECK_REALM_LIST_SIZE	8
+
+#define MAX_EAP_BUF_SIZE			2048
+
+#define E_WM_CR801_EAP_FAILURE		-201
+#define E_WM_UNKNOWN_SERVER_REALM	-202
+
+#define OMA_EAP_SERVER_REALMS	2
+#define CR801_DISABLE		0
+#define CR801_TTLS			1
+#define CR801_TLS			2
+
+typedef struct wm_eap_tls_param_s {
+	/*Parameters*/
+	u8		type;
+	u16		frag_size;
+	char	use_delimiter;
+	bool	dev_cert_null;
+	bool	ca_cert_null;
+	bool	disable_resumptoin;
+	bool	disable_sessionticket;
+
+	bool	use_nv_info;
+	char	userid[WIMAX_EAP_STR_LEN];		/*Inner NAI*/
+	char	userid_pwd[WIMAX_EAP_STR_LEN];	/*Inner NAI password*/
+	char	anony_id[WIMAX_EAP_STR_LEN];	/*Outer NAI*/
+	char	pri_key_pwd[WIMAX_EAP_STR_LEN];
+	char	visited_realm[WIMAX_EAP_STR_LEN];
+
+	char	decoration[MAX_DECORATION_NR][WIMAX_EAP_DECO_LEN];
+
+	bool	cr801_enabled;
+	u8		cr801_mode;
+	int		cr801_server_reject_cnt;
+
+	bool	cr901_enabled;
+	bool	cr1074_enabled;
+	bool	check_realm;
+	int		configured_realm_list_cnt;
+	char	configured_realm_list[EAP_CHECK_REALM_LIST_SIZE][MAX_EAP_PARAM_SIZE];
+
+	bool	log_enabled;
+} wm_eap_param_t;
+
+void eap_start_e_eaplog_thread(int dev_idx);
+void eap_prepare_log_env(int dev_idx, bool enable);
+
+unsigned int ParsingOuterNAI(const char *Outer_NAI,			// IN
+						  char		 *routing_info,			// OUT
+						  char		 *wm_decoration,		// OUT
+						  char		 *userid,				// OUT
+						  char		 *realm);
+#endif
diff --git a/sdk/error.c b/sdk/error.c
new file mode 100644
index 0000000..d10badb
--- /dev/null
+++ b/sdk/error.c
@@ -0,0 +1,34 @@
+// 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 <stdlib.h>
+#include <sys/types.h>
+#include <assert.h>
+
+#include "error.h"
+#include "device.h"
+#include "log.h"
+
+
+static int sdk_errno;
+
+int sdk_set_errno(int err_no)
+{
+	int lmask = SDK_ERR;
+
+	switch (err_no) {
+		case ERR_PERM:
+			xprintf(lmask, "Permission denied.\n");
+			break;
+	}
+	sdk_errno = err_no;
+
+	return -1;
+}
+
+int sdk_get_errno(void)
+{
+	return sdk_errno;
+}
diff --git a/sdk/error.h b/sdk/error.h
new file mode 100644
index 0000000..0144975
--- /dev/null
+++ b/sdk/error.h
@@ -0,0 +1,31 @@
+// 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.
+
+#if !defined(ERROR_H_20080715)
+#define ERROR_H_20080715
+
+
+enum
+{
+	ERR_STD = 1,
+	ERR_INVALID,
+	ERR_INVALID_DEV,
+	ERR_REMOVED_DEV,
+	ERR_PERM,
+	ERR_BUSY,
+	ERR_ENV,
+	ERR_ALREADY,
+	ERR_UNKNOWN_STAT,
+	ERR_NO_NSPID,
+	ERR_UNEXPECTED_TLV,
+	ERR_NORESP_CMD,
+	ERR_HCI,
+	
+	END_ERR
+};
+
+
+int sdk_set_errno(int err_no);
+int sdk_get_errno(void);
+#endif
diff --git a/sdk/fload.c b/sdk/fload.c
new file mode 100644
index 0000000..b1d865a
--- /dev/null
+++ b/sdk/fload.c
@@ -0,0 +1,154 @@
+// 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 <zlib.h>
+#include "global.h"
+#include "error.h"
+#include "wimax.h"
+#include "wm_ioctl.h"
+#include "io.h"
+#include "device.h"
+#include "hci.h"
+#include "log.h"
+#include "fload.h"
+
+typedef const char * ld_file_t;
+
+typedef struct {
+	void *p;
+	int size;
+} ld_buf_t;
+
+typedef struct {
+	bool	is_file;
+	union {
+		ld_file_t path;
+		ld_buf_t buf;
+	} u;
+} ld_dst_t;
+
+int bl_upload(int dev_idx, int type, void *buf, int size, void (*progress)(int bytes))
+{
+	xprintf(SDK_ERR, "%s: not supported!\n", __func__);
+		return -1;
+}
+
+int bl_download(int dev_idx, int type, void *buf, int size, void (*progress)(int bytes))
+{
+	xprintf(SDK_ERR, "%s: not supported!\n", __func__);
+		return -1;
+}
+
+static int do_read_file(int dev_idx, const char *target_file,
+		ld_dst_t *dst, void (*progress)(int bytes))
+{
+	device_t *dev;
+	u8 send_buf[HCI_MAX_PACKET];
+	u8 recv_buf[HCI_MAX_PACKET];
+	hci_file_read_t *file = (hci_file_read_t *) send_buf;
+	hci_file_response_t *rsp;
+	u32 offset = 0;
+	int fd = 0;
+	int ret = -1, len, max_size = 0;
+	char *p = NULL;
+	u16 cmd;
+	void *param;
+	int plen;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	xfunc_in("[%d]", dev_idx);
+
+	if (dst->is_file) {
+		if ((fd = open(dst->u.path, O_CREAT|O_WRONLY|O_TRUNC, 0644)) < 0) {
+			xprintf(SDK_STD_ERR, "open(%s) fail\n", dst->u.path);
+			goto out;
+		}
+	}
+	else {
+		if (!dst->u.buf.p || !dst->u.buf.size) {
+			xprintf(SDK_ERR, "buf=%p, size=%d\n", dst->u.buf.p, dst->u.buf.size);
+			goto out;
+		}
+		p = dst->u.buf.p;
+		max_size = dst->u.buf.size;
+	}
+
+	strcpy((char *)file->path, target_file);
+	cmd = WIMAX_READ_FILE;
+	param = file;
+	plen = sizeof(hci_file_read_t) + strlen((char *)file->path) + 1/*null*/;
+
+	pthread_mutex_lock(&dev->load_lock);
+	while (1) {
+		file->offset = DH2B(offset);
+		ret = hci_send_wait(dev_idx, cmd, param, plen,
+				WIMAX_FILE_RESULT, recv_buf, sizeof(recv_buf), 0, 0, 3);
+		if (ret < 0)
+			break;
+
+		rsp = (hci_file_response_t *) recv_buf;
+		if (!(len = DB2H(rsp->result))) {
+			ret = 0;
+			break;
+		}
+		if (len < 0) {
+			xprintf(SDK_ERR, "Read file failed(%d)\n", ret);
+			ret = -1;
+			break;
+		}
+
+		if (dst->is_file) {
+			ret = write(fd, file_response_data(rsp), len);
+			if (ret <= 0) {
+				xprintf(SDK_ERR, "Write fail %s(%d!=%d)\n", dst->u.path, ret, len);
+				ret = -1;
+				break;
+			}
+		}
+		else {
+			if (offset + len > max_size) {
+				xprintf(SDK_ERR, "buffer is too small(%d > %d)\n",
+					offset + len, max_size);
+				ret = -1;
+				break;
+			}
+			memcpy(p+offset, file_response_data(rsp), len);
+		}
+
+		offset += len;
+		if (progress)
+			progress(offset);
+	}
+	pthread_mutex_unlock(&dev->load_lock);
+
+out:
+	if (fd > 0)
+		close(fd);
+	xprintf(SDK_INFO, "Read file size=%d\n", offset);
+	if (!ret) {
+		if (!offset)
+			ret = -ENOENT;
+		else
+			ret = offset;
+	}
+
+	xfunc_out("ret=%d", ret);
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+int fl_read_file(int dev_idx, const char *target_file,
+		const char *host_file, void (*progress)(int bytes))
+{
+	ld_dst_t dst;
+	int ret;
+	
+	dst.is_file = TRUE;
+	dst.u.path = host_file;
+	ret = do_read_file(dev_idx, target_file, &dst, progress);
+
+	return ret;
+}
diff --git a/sdk/fload.h b/sdk/fload.h
new file mode 100644
index 0000000..33dfdcc
--- /dev/null
+++ b/sdk/fload.h
@@ -0,0 +1,16 @@
+// 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.
+
+#if !defined(FLOAD_H_20080930)
+#define FLOAD_H_20080930
+#include "global.h"
+
+int bl_upload(int dev_idx, int type, void *buf, int size, void (*progress)(int bytes));
+int bl_download(int dev_idx, int type, void *buf, int size, void (*progress)(int bytes));
+
+int fl_read_file(int dev_idx, const char *target_file,
+		const char *host_file, void (*progress)(int bytes));
+
+#endif
+
diff --git a/sdk/gctapi.c b/sdk/gctapi.c
new file mode 100644
index 0000000..24fffc7
--- /dev/null
+++ b/sdk/gctapi.c
@@ -0,0 +1,1506 @@
+// 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 <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <assert.h>
+#include <wchar.h>
+
+#include "gctapi.h"
+#include "error.h"
+#include "handle.h"
+#include "sdk.h"
+#include "wimax.h"
+#include "wm_ioctl.h"
+#include "device.h"
+#include "log.h"
+
+
+typedef struct gct_ind_s {
+	GIndRcvHCIPacket			recv_hci;
+	GIndPowerModeChange			power_mode;
+	GIndDeviceInsertRemove		insert_remove;
+	GIndControlPowerManagement	pow_mng;
+	GIndDeviceStatusUpdate		stat_update;
+	GIndConnectToNetwork		connect_net;
+	GIndDisconnectFromNetwork	disconnect_net;
+	GIndNetworkSearchWideScan	net_search_wscan;
+	GIndProvisioningOperation	provisioning;
+	GIndPackageUpdate			package_update;
+	GIndNotification			notification;
+
+	#if defined(CONFIG_ENABLE_SERVICE_FLOW)
+	GIndNotiServiceFlow			noti_service_flow;
+	#endif // CONFIG_ENABLE_SERVICE_FLOW
+
+} gct_ind_t;
+
+typedef struct gct_api_s {
+	u32 struct_size;
+	GCT_WIMAX_API_OPEN_MODE mode;
+	gct_ind_t ind;
+
+} gct_api_t;
+
+GCT_API_RET GAPI_CheckHandle(APIHAND hapi)
+{
+	api_hand_t *api = (api_hand_t *) hapi;
+
+	if (api == NULL) {
+		xprintf(SDK_ERR, "API handle is NULL\n");
+		return GCT_API_RET_INVALID_PARAMETER;
+	}
+	if (api->struct_size != sizeof(api_hand_t)) {
+		xprintf(SDK_ERR, "Wrong structure size(%d!=%d)\n",
+			api->struct_size, sizeof(api_hand_t));
+		return GCT_API_RET_INVALID_PARAMETER;
+	}
+
+	return GCT_API_RET_SUCCESS;
+}
+
+GCT_API_RET GAPI_Initialize(GCT_WIMAX_SDK_MODE mode, GCT_WIMAX_API_PARAM *param)
+{
+	if (sdk_init(mode, param) < 0)
+		return GCT_API_RET_FAILED;
+
+	xprintf(SDK_NOTICE, "SDK Version:%s\n", sdk_version());
+	xprintf(SDK_INFO, "BUILT TIME: %s, %s\n", __DATE__, __TIME__);
+	return GCT_API_RET_SUCCESS;
+}
+
+GCT_API_RET GAPI_DeInitialize(void)
+{
+	if (sdk_deinit() < 0)
+		return GCT_API_RET_FAILED;
+	
+	return GCT_API_RET_SUCCESS;
+}
+
+GCT_API_RET GAPI_WiMaxAPIOpen(APIHAND *phAPI, GCT_WIMAX_API_OPEN_MODE mode)
+{
+	api_hand_t *api_hand;
+	gct_api_t *gcti;
+	GCT_API_RET gret = GCT_API_RET_SUCCESS;
+	int sdk_mode = 0;
+
+	if (mode & GCT_WIMAX_API_PRIVILEGE_READ_ONLY)
+		sdk_mode |= sdk_read_only;
+	if (mode & GCT_WIMAX_API_OPEN_MODE_ENG)
+		sdk_mode |= sdk_eng_mode;
+
+	api_hand = sdk_api_open(sdk_mode);
+	if (api_hand) {
+		gcti = (gct_api_t *) sdk_malloc(sizeof(gct_api_t));
+		assert(gcti != NULL);
+		memset(gcti, 0, sizeof(gct_api_t));
+		gcti->struct_size = sizeof(gct_api_t);
+		gcti->mode = mode;
+		api_hand->api = gcti;
+	}
+	else
+		gret = GCT_API_RET_FAILED;
+
+	*phAPI = (APIHAND) api_hand;
+	return gret;
+}
+
+GCT_API_RET GAPI_WiMaxAPIClose(APIHAND hAPI)
+{
+	api_hand_t *api_hand = (api_hand_t *) hAPI;
+	gct_api_t *gcti;
+	GCT_API_RET gret;
+
+	if ((gret = GAPI_CheckHandle(hAPI)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	gcti = (gct_api_t *) api_hand->api;
+
+	if (sdk_api_close(api_hand) < 0)
+		return GCT_API_RET_FAILED;
+	else {
+		sdk_free(gcti);
+		return GCT_API_RET_SUCCESS;
+	}
+}
+
+GCT_API_RET GAPI_SetDebugLevel(APIHAND hAPI, int level, int *prev_level)
+{
+	api_hand_t *api_hand = (api_hand_t *) hAPI;
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(hAPI)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	if ((ret = sdk_debug_level(api_hand, level)) < 0)
+		return GCT_API_RET_FAILED;
+
+	if (prev_level)
+		*prev_level = ret;
+	return GCT_API_RET_SUCCESS;
+}
+
+GCT_API_RET GAPI_PrintLog(APIHAND hAPI, int flag, const char *title, const char *fmt, ...)
+{
+	api_hand_t *api_hand = (api_hand_t *) hAPI;
+	char buf[2048];
+	va_list args;
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(hAPI)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	va_start(args, fmt);
+	vsprintf(buf, fmt, args);
+	ret = sdk_print_log(api_hand, flag, title, buf);
+	va_end(args);
+
+	if (ret < 0)
+		return GCT_API_RET_FAILED;
+	return GCT_API_RET_SUCCESS;
+}
+
+static void Ind_RcvHCIPacketFunc(dev_hand_t *hand,
+	char *buf, int len)
+{
+	api_hand_t *api_hand = (api_hand_t *) hand->api;
+	gct_api_t *gcti;
+	GDEV_ID id;
+
+	xfunc_in();
+	id.apiHandle = api_hand;
+	id.deviceIndex = hand->dev_idx;
+	gcti = (gct_api_t *) api_hand->api;
+	assert(gcti->ind.recv_hci != NULL);
+	gcti->ind.recv_hci(&id, buf, len);
+	xfunc_out();
+}
+
+GCT_API_RET GAPI_RegRcvHCIPacketFunc(APIHAND hAPI, GIndRcvHCIPacket pFunc)
+{
+	api_hand_t *api_hand = (api_hand_t *) hAPI;
+	gct_api_t *gcti;
+
+	gcti = (gct_api_t *) api_hand->api;
+	gcti->ind.recv_hci = pFunc;
+
+	if (sdk_reg_recv_hci_packet(api_hand, Ind_RcvHCIPacketFunc) < 0)
+		return GCT_API_RET_FAILED;
+	else
+		return GCT_API_RET_SUCCESS;
+}
+
+GCT_API_RET GAPI_DeRegRcvHCIPacketFunc(APIHAND hAPI)
+{
+	api_hand_t *api_hand = (api_hand_t *) hAPI;
+	gct_api_t *gcti;
+
+	gcti = (gct_api_t *) api_hand->api;
+	gcti->ind.recv_hci = NULL;
+
+	if (sdk_unreg_recv_hci_packet(api_hand) < 0)
+		return GCT_API_RET_FAILED;
+	else
+		return GCT_API_RET_SUCCESS;
+}
+
+static void Ind_PowerModeChange(dev_hand_t *hand, GCT_API_POWER_MODE nPowerMode)
+{
+	api_hand_t *api_hand = (api_hand_t *) hand->api;
+	gct_api_t *gcti;
+	GDEV_ID id;
+
+	xfunc_in();
+	id.apiHandle = api_hand;
+	id.deviceIndex = hand->dev_idx;
+	gcti = (gct_api_t *) api_hand->api;
+	assert(gcti->ind.power_mode != NULL);
+	gcti->ind.power_mode(&id, nPowerMode);
+	xfunc_out();
+}
+
+GCT_API_RET GAPI_RegPowerModeChange(APIHAND hAPI, GIndPowerModeChange pFunc)
+{
+	api_hand_t *api_hand = (api_hand_t *) hAPI;
+	gct_api_t *gcti;
+
+	gcti = (gct_api_t *) api_hand->api;
+	gcti->ind.power_mode= pFunc;
+
+	if (sdk_reg_mode_change(api_hand, Ind_PowerModeChange) < 0)
+		return GCT_API_RET_FAILED;
+	else
+		return GCT_API_RET_SUCCESS;
+}
+
+GCT_API_RET GAPI_DeRegPowerModeChange(APIHAND hAPI)
+{
+	api_hand_t *api_hand = (api_hand_t *) hAPI;
+	gct_api_t *gcti;
+
+	gcti = (gct_api_t *) api_hand->api;
+	gcti->ind.power_mode = NULL;
+
+	if (sdk_unreg_recv_hci_packet(api_hand) < 0)
+		return GCT_API_RET_FAILED;
+	else
+		return GCT_API_RET_SUCCESS;
+}
+
+GCT_API_RET GAPI_WiMaxDeviceOpen(GDEV_ID_P pID)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_device_open(pID->apiHandle, pID->deviceIndex);
+	if (!ret)
+		return GCT_API_RET_SUCCESS;
+	else
+		return GCT_API_RET_FAILED;
+}
+
+GCT_API_RET GAPI_WiMaxDeviceClose(GDEV_ID_P pID)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_device_close(pID->apiHandle, pID->deviceIndex);
+	if (!ret)
+		return GCT_API_RET_SUCCESS;
+	else
+		return GCT_API_RET_FAILED;
+}
+
+GCT_API_RET GAPI_GetDeviceStatus(GDEV_ID_P pID, WIMAX_API_DEVICE_STATUS_P pDeviceStatus,
+	WIMAX_API_CONNECTION_PROGRESS_INFO_P pConnectionProgressInfo)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_get_device_status(pID->apiHandle, pID->deviceIndex,
+			pDeviceStatus, pConnectionProgressInfo);
+	if (!ret)
+		return GCT_API_RET_SUCCESS;
+	else
+		return GCT_API_RET_FAILED;
+}
+
+GCT_API_RET GAPI_WriteHCIPacket(GDEV_ID_P pID, char *szBuf, int nBufSize)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_write_hci_packet(pID->apiHandle, pID->deviceIndex, szBuf, nBufSize);
+	if (!ret)
+		return GCT_API_RET_SUCCESS;
+	else
+		return GCT_API_RET_FAILED;
+}
+
+GCT_API_RET GAPI_GetListDevice(APIHAND hAPI, WIMAX_API_HW_DEVICE_ID_P pHwDeviceIdList,
+				UINT32* pHwDeviceIdListSize)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(hAPI)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	if (*pHwDeviceIdListSize == 0)
+		return GCT_API_RET_INVALID_PARAMETER;
+
+	ret = sdk_get_device_list(hAPI, pHwDeviceIdList, pHwDeviceIdListSize);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_CmdControlPowerManagement(GDEV_ID_P pID, WIMAX_API_RF_STATE powerState)
+{	
+	rf_stat_t rf_stat = (rf_stat_t) powerState;
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+	
+	ret = sdk_set_power_control(pID->apiHandle, pID->deviceIndex, rf_stat);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_SetServiceProviderUnLock(GDEV_ID_P pID, WIMAX_API_WSTRING lockCode)
+{
+	GCT_API_RET gret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+	#if defined( NO_IMPLIMENT )
+	#else
+	gret = GCT_API_RET_NOT_IMPLEMENTED;
+	#endif
+	return gret;
+}
+
+GCT_API_RET GAPI_GetServiceProviderLockStatus(GDEV_ID_P pID, 
+				WIMAX_API_LOCK_STATUS_P pLockStatus, UCHAR16 *NSPName)
+{
+	GCT_API_RET gret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+	#if defined( NO_IMPLIMENT )
+	#else
+	gret = GCT_API_RET_NOT_IMPLEMENTED;
+	#endif
+	wcscpy((wchar_t *)NSPName, L"NOT Implemented!");
+
+	return gret;
+}
+
+GCT_API_RET GAPI_GetContactInformation(GDEV_ID_P pID, WIMAX_API_WSTRING nspName,
+				WIMAX_API_CONTACT_INFO_P pContactInfo, 	UINT32* pSizeOfContactList)
+{
+	GCT_API_RET gret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+	#if defined( NO_IMPLIMENT )
+	#else
+	*pSizeOfContactList = 0;
+	gret = GCT_API_RET_NOT_IMPLEMENTED;
+	#endif
+
+	return gret;
+}
+
+GCT_API_RET GAPI_GetStatistics(GDEV_ID_P pID, WIMAX_API_CONNECTION_STAT_P pStatistics)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_get_statistics(pID->apiHandle, pID->deviceIndex, pStatistics);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else {
+		gret = GCT_API_RET_SUCCESS;
+	}
+
+	return gret;
+}
+
+GCT_API_RET GAPI_GetLinkStatus(GDEV_ID_P pID, WIMAX_API_LINK_STATUS_INFO_P pLinkStatus)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_get_linkstatus(pID->apiHandle, pID->deviceIndex, pLinkStatus);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else {
+		gret = GCT_API_RET_SUCCESS;
+	}
+
+	return gret;
+}
+
+GCT_API_RET GAPI_GetConnectedNSP(GDEV_ID_P pID, WIMAX_API_CONNECTED_NSP_INFO_P pNspInfo)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_get_connected_nsp(pID->apiHandle, pID->deviceIndex, pNspInfo);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else {
+		gret = GCT_API_RET_SUCCESS;
+	}
+
+	return gret;
+}
+
+GCT_API_RET GAPI_GetNetworkList(GDEV_ID_P pID, WIMAX_API_NSP_INFO_P pNSPInfo,
+				UINT32* pListCnt)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_get_network_list(pID->apiHandle, pID->deviceIndex, pNSPInfo, pListCnt);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_CmdConnectToNetwork(GDEV_ID_P pID, WIMAX_API_WSTRING nspName,
+				WIMAX_API_PROFILE_ID profileID)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+				
+	ret = sdk_connect_network(pID->apiHandle, pID->deviceIndex, nspName, profileID);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_CmdDisconnectFromNetwork(GDEV_ID_P pID)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_disconnect_network(pID->apiHandle, pID->deviceIndex);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_GetSelectProfileList(GDEV_ID_P pID,
+				WIMAX_API_PROFILE_INFO_P pProfileList, UINT32* pListCnt)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_get_profile_list(pID->apiHandle, pID->deviceIndex,
+			pProfileList, (int *)pListCnt);
+
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_SetProfile(GDEV_ID_P pID, WIMAX_API_PROFILE_ID profileID)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_set_profile(pID->apiHandle, pID->deviceIndex, profileID);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_SetScanInterval(GDEV_ID_P pID, UINT32 intervalSec)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_set_scan_interval(pID->apiHandle, pID->deviceIndex, intervalSec);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_SetEap(GDEV_ID_P pID, GCT_API_EAP_PARAM_P eap)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_set_eap(pID->apiHandle, pID->deviceIndex, eap);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_GetDeviceInformation(GDEV_ID_P pID, WIMAX_API_DEVICE_INFO_P pDeviceInfo)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_get_device_info(pID->apiHandle, pID->deviceIndex, pDeviceInfo);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_SetFrequency(GDEV_ID_P pID, UINT32 nFreq, UINT32 nBandWidth,
+	UINT32 nFFTSize)
+{
+	return GCT_API_RET_FAILED;
+}
+
+GCT_API_RET GAPI_GetRFInform(GDEV_ID_P pID, GCT_API_RF_INFORM_P pRFInform)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_get_rf_info(pID->apiHandle, pID->deviceIndex, pRFInform);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_GetBootloaderVersion(GDEV_ID_P pID, char *str, int size)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_get_bl_ver(pID->apiHandle, pID->deviceIndex, str, size);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_GetCapability(GDEV_ID_P pID, CAPABILITY_BIT_P cap)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_get_capability(pID->apiHandle, pID->deviceIndex, (u32 *) cap);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_SetCapability(GDEV_ID_P pID, CAPABILITY_BIT cap)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_set_capability(pID->apiHandle, pID->deviceIndex, (u32) cap);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_GetNeighborList (GDEV_ID_P pID, 
+				GCT_API_NEIGHBOR_LIST_P pNeighborList, UINT32* pArrayLength)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_get_neighbor_list(pID->apiHandle, pID->deviceIndex,
+			pNeighborList, (int *) pArrayLength);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_NetworkSearchScan(GDEV_ID_P pID, GCT_API_SCAN_TYPE type)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_net_search_scan(pID->apiHandle, pID->deviceIndex, type);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_CancelWideScan(GDEV_ID_P pID)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_cancel_scan(pID->apiHandle, pID->deviceIndex);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_CmdMACState(GDEV_ID_P pID, GCT_API_CMD_MAC_STATE_TYPE type)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_cmd_mac_state(pID->apiHandle, pID->deviceIndex, type);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_SetIdleModeTimeout(GDEV_ID_P pID, UINT16 timeoutSec)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_set_idle_mode_timeout(pID->apiHandle, pID->deviceIndex, timeoutSec);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_GetPHY_MAC_Basic(GDEV_ID_P pID, GCT_API_MAC_PHY_MAC_BASIC_P pData)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_get_phy_mac_basic(pID->apiHandle, pID->deviceIndex, pData);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_GetPHY_MCS(GDEV_ID_P pID, GCT_API_MAC_PHY_MCS_P pData)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_get_phy_mcs(pID->apiHandle, pID->deviceIndex, pData);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_GetPHY_CINR_RSSI(GDEV_ID_P pID, GCT_API_MAC_PHY_CINR_RSSI_P pData)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_get_phy_cinr_rssi(pID->apiHandle, pID->deviceIndex, pData);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+#if defined(CONFIG_ENABLE_SERVICE_FLOW)
+GCT_API_RET GAPI_BeginSFRead(GDEV_ID_P pID)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_sf_BeginSFRead(pID->apiHandle, pID->deviceIndex);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_EndSFRead(GDEV_ID_P pID)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_sf_EndSFRead(pID->apiHandle, pID->deviceIndex);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_GetNextSF(GDEV_ID_P pID,
+				WIMAX_SERVICE_FLOW *pSF,
+				UINT8 Direction,
+				WIMAX_SERVICE_FLOW **ppRetSF)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_sf_GetNextSF(pID->apiHandle, pID->deviceIndex, pSF, Direction, ppRetSF);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_GetServiceFlow(GDEV_ID_P pID,
+				UINT32 SFID,
+				WIMAX_SERVICE_FLOW **ppRetSF)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_sf_GetServiceFlow(pID->apiHandle, pID->deviceIndex, SFID, ppRetSF);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}	
+
+GCT_API_RET GAPI_GetNextClfrRule(GDEV_ID_P pID, 
+				WIMAX_SERVICE_FLOW *pSF,
+				WIMAX_CLFR_RULE *pCLFRRule,
+				WIMAX_CLFR_RULE **ppRetCLFRRule)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_sf_GetNextClfrRule(pID->apiHandle, pID->deviceIndex, pSF, pCLFRRule, ppRetCLFRRule);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_GetClfrRule(GDEV_ID_P pID, 
+				WIMAX_SERVICE_FLOW *pSF,
+				UINT16 PacketClassfierRuleIndex,
+				WIMAX_CLFR_RULE **ppRetCLFRRule)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_sf_GetClfrRule(pID->apiHandle, pID->deviceIndex, pSF, PacketClassfierRuleIndex, ppRetCLFRRule);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_GetNextPHSRule(GDEV_ID_P pID, 
+				WIMAX_SERVICE_FLOW *pSF,
+				WIMAX_PHS_RULE *pPHSRule,
+				WIMAX_PHS_RULE **ppRetPHSRule)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_sf_GetNextPHSRule(pID->apiHandle, pID->deviceIndex, pSF, pPHSRule, ppRetPHSRule);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_GetPHSRule(GDEV_ID_P pID, 
+				WIMAX_SERVICE_FLOW *pSF, 
+				UINT8 PHSI,
+				WIMAX_PHS_RULE **ppRetPHSRule)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_sf_GetPHSRule(pID->apiHandle, pID->deviceIndex, pSF, PHSI, ppRetPHSRule);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_CmdAddSF(GDEV_ID_P pID,
+				WIMAX_SF_PARAM_P pSFParam,
+				WIMAX_CLFR_RULE_P pClfrRule,
+				WIMAX_PHS_RULE_P pPHSRule)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_sf_CmdAddSF(pID->apiHandle, pID->deviceIndex, pSFParam, pClfrRule, pPHSRule);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+}
+
+GCT_API_RET GAPI_CmdChangeSF(GDEV_ID_P pID,
+				WIMAX_SF_PARAM_P pSFParam,
+				WIMAX_CLFR_DSC_ACTION CLFRDSCAction,
+				WIMAX_CLFR_RULE_P pClfrRule,
+				WIMAX_PHS_DSC_ACTION PHSDSCAction,
+				WIMAX_PHS_RULE_P pPHSRule)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_sf_CmdChangeSF(pID->apiHandle, pID->deviceIndex, pSFParam, CLFRDSCAction, pClfrRule, PHSDSCAction, pPHSRule);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+
+}	
+
+GCT_API_RET GAPI_CmdDeleteSF(GDEV_ID_P pID,
+				WIMAX_SF_PARAM_P pSFParam)
+{
+	GCT_API_RET gret;
+	int ret;
+
+	if ((gret = GAPI_CheckHandle(pID->apiHandle)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	ret = sdk_sf_CmdDeleteSF(pID->apiHandle, pID->deviceIndex, pSFParam);
+	if (ret < 0)
+		gret = GCT_API_RET_FAILED;
+	else
+		gret = GCT_API_RET_SUCCESS;
+
+	return gret;
+
+}
+#endif // CONFIG_ENABLE_SERVICE_FLOW
+
+static void Ind_DeviceInsertRemove(dev_hand_t *hand,
+	BOOL cardPresence)
+{
+	api_hand_t *api_hand = (api_hand_t *) hand->api;
+	gct_api_t *gcti;
+	GDEV_ID id;
+
+	xfunc_in();
+	id.apiHandle = api_hand;
+	id.deviceIndex = hand->dev_idx;
+	gcti = (gct_api_t *) api_hand->api;
+	assert(gcti->ind.insert_remove != NULL);
+	gcti->ind.insert_remove(&id, cardPresence);
+	xfunc_out();
+}
+
+GCT_API_RET GAPI_SubscribeDeviceInsertRemove(APIHAND hAPI,
+				GIndDeviceInsertRemove pCallbackFunc)
+{
+	api_hand_t *api_hand = (api_hand_t *) hAPI;
+	gct_api_t *gcti;
+	GCT_API_RET gret;
+
+	if ((gret = GAPI_CheckHandle(hAPI)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	if (sdk_reg_dev_insert_remove(api_hand, Ind_DeviceInsertRemove) < 0)
+		return GCT_API_RET_FAILED;
+	else {
+		gcti = (gct_api_t *) api_hand->api;
+		gcti->ind.insert_remove = pCallbackFunc;
+		return GCT_API_RET_SUCCESS;
+	}
+}
+
+static void Ind_ControlPowerManagement(dev_hand_t *hand,
+	WIMAX_API_RF_STATE powerState)
+{
+	api_hand_t *api_hand = (api_hand_t *) hand->api;
+	gct_api_t *gcti;
+	GDEV_ID id;
+
+	xfunc_in();
+	id.apiHandle = api_hand;
+	id.deviceIndex = hand->dev_idx;
+	gcti = (gct_api_t *) api_hand->api;
+	gcti->ind.pow_mng(&id, powerState);
+	xfunc_out();
+}
+
+GCT_API_RET GAPI_SubscribeControlPowerManagement(APIHAND hAPI,
+				GIndControlPowerManagement pCallbackFunc)
+{
+	api_hand_t *api_hand = (api_hand_t *) hAPI;
+	gct_api_t *gcti;
+	GCT_API_RET gret;
+
+	if ((gret = GAPI_CheckHandle(hAPI)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	if (sdk_reg_ctrl_power_mng(api_hand, Ind_ControlPowerManagement) < 0)
+		return GCT_API_RET_FAILED;
+	else {
+		gcti = (gct_api_t *) api_hand->api;
+		gcti->ind.pow_mng = pCallbackFunc;
+		return GCT_API_RET_SUCCESS;
+	}
+}
+
+static void Ind_ConnectToNetwork(dev_hand_t *hand,
+	WIMAX_API_NETWORK_CONNECTION_RESP networkConnectionResponse)
+{
+	api_hand_t *api_hand = (api_hand_t *) hand->api;
+	gct_api_t *gcti;
+	GDEV_ID id;
+
+	xfunc_in();
+	id.apiHandle = api_hand;
+	id.deviceIndex = hand->dev_idx;
+	gcti = (gct_api_t *) api_hand->api;
+	gcti->ind.connect_net(&id, networkConnectionResponse);
+	xfunc_out();
+}
+
+GCT_API_RET GAPI_SubscribeConnectToNetwork(APIHAND hAPI,
+				GIndConnectToNetwork pCallbackFunc)
+{
+	api_hand_t *api_hand = (api_hand_t *) hAPI;
+	gct_api_t *gcti;
+	GCT_API_RET gret;
+
+	if ((gret = GAPI_CheckHandle(hAPI)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	if (sdk_reg_connect_network(api_hand, Ind_ConnectToNetwork) < 0)
+		return GCT_API_RET_FAILED;
+	else {
+		gcti = (gct_api_t *) api_hand->api;
+		gcti->ind.connect_net = pCallbackFunc;
+		return GCT_API_RET_SUCCESS;
+	}
+}
+
+static void Ind_DisconnectFromNetwork(dev_hand_t *hand,
+	WIMAX_API_NETWORK_CONNECTION_RESP networkDisconnectResponse)
+{
+	api_hand_t *api_hand = (api_hand_t *) hand->api;
+	gct_api_t *gcti;
+	GDEV_ID id;
+
+	xfunc_in();
+	id.apiHandle = api_hand;
+	id.deviceIndex = hand->dev_idx;
+	gcti = (gct_api_t *) api_hand->api;
+	gcti->ind.disconnect_net(&id, networkDisconnectResponse);
+	xfunc_out();
+}
+
+GCT_API_RET GAPI_SubscribeDisconnectFromNetwork(APIHAND hAPI,
+				GIndDisconnectFromNetwork pCallbackFunc)
+{
+	api_hand_t *api_hand = (api_hand_t *) hAPI;
+	gct_api_t *gcti;
+	GCT_API_RET gret;
+
+	if ((gret = GAPI_CheckHandle(hAPI)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	if (sdk_reg_disconnect_network(api_hand, Ind_DisconnectFromNetwork) < 0)
+		return GCT_API_RET_FAILED;
+	else {
+		gcti = (gct_api_t *) api_hand->api;
+		gcti->ind.disconnect_net = pCallbackFunc;
+		return GCT_API_RET_SUCCESS;
+	}
+}
+
+static void Ind_NetworkSearchWideScan(dev_hand_t *hand,
+	WIMAX_API_NSP_INFO_P pNspInfo, UINT32 nListSize)
+{
+	api_hand_t *api_hand = (api_hand_t *) hand->api;
+	gct_api_t *gcti;
+	GDEV_ID id;
+
+	xfunc_in();
+	id.apiHandle = api_hand;
+	id.deviceIndex = hand->dev_idx;
+	gcti = (gct_api_t *) api_hand->api;
+	gcti->ind.net_search_wscan(&id, pNspInfo, nListSize);
+	xfunc_out();
+}
+
+GCT_API_RET GAPI_SubscribeNetworkSearchWideScan(APIHAND hAPI,
+				GIndNetworkSearchWideScan pCallbackFunc)
+{
+	api_hand_t *api_hand = (api_hand_t *) hAPI;
+	gct_api_t *gcti;
+	GCT_API_RET gret;
+
+	if ((gret = GAPI_CheckHandle(hAPI)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	if (sdk_reg_network_search_wscn(api_hand, Ind_NetworkSearchWideScan) < 0)
+		return GCT_API_RET_FAILED;
+	else {
+		gcti = (gct_api_t *) api_hand->api;
+		gcti->ind.net_search_wscan = pCallbackFunc;
+		return GCT_API_RET_SUCCESS;
+	}
+}
+
+static void Ind_ProvisioningOperation(dev_hand_t *hand,
+				WIMAX_API_PROV_OPERATION provisioning_operation,
+				WIMAX_API_CONTACT_TYPE contact_type)
+{
+	api_hand_t *api_hand = (api_hand_t *) hand->api;
+	gct_api_t *gcti;
+	GDEV_ID id;
+
+	xfunc_in();
+	id.apiHandle = api_hand;
+	id.deviceIndex = hand->dev_idx;
+	gcti = (gct_api_t *) api_hand->api;
+	gcti->ind.provisioning(&id, provisioning_operation, contact_type);
+	xfunc_out();
+}
+
+GCT_API_RET GAPI_SubscribeProvisioningOperation(APIHAND hAPI,
+				GIndProvisioningOperation pCallbackFunc)
+{
+	api_hand_t *api_hand = (api_hand_t *) hAPI;
+	gct_api_t *gcti;
+	GCT_API_RET gret;
+
+	if ((gret = GAPI_CheckHandle(hAPI)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	if (sdk_reg_provisioning_op(api_hand, Ind_ProvisioningOperation) < 0)
+		return GCT_API_RET_FAILED;
+	else {
+		gcti = (gct_api_t *) api_hand->api;
+		gcti->ind.provisioning = pCallbackFunc;
+		return GCT_API_RET_SUCCESS;
+	}
+}
+
+static void Ind_DeviceStatusChange(dev_hand_t *hand,
+	WIMAX_API_DEVICE_STATUS deviceStatus, 
+	WIMAX_API_STATUS_REASON statusReason, 
+	WIMAX_API_CONNECTION_PROGRESS_INFO connectionProgressInfo)
+{
+	api_hand_t *api_hand = (api_hand_t *) hand->api;
+	gct_api_t *gcti;
+	GDEV_ID id;
+
+	xfunc_in();
+	id.apiHandle = api_hand;
+	id.deviceIndex = hand->dev_idx;
+	gcti = (gct_api_t *) api_hand->api;
+	gcti->ind.stat_update(&id, deviceStatus, statusReason, connectionProgressInfo);
+	xfunc_out();
+}
+
+static void Ind_Notification(dev_hand_t *hand,
+	GCT_API_NOTI_CATEGORY nCategory,
+	GCT_API_NOTI_TYPE nType, int nBufSize, char *szBuf)
+{
+	api_hand_t *api_hand = (api_hand_t *) hand->api;
+	gct_api_t *gcti;
+	GDEV_ID id;
+
+	xfunc_in();
+	id.apiHandle = api_hand;
+	id.deviceIndex = hand->dev_idx;
+	gcti = (gct_api_t *) api_hand->api;
+	gcti->ind.notification(&id, nCategory, nType, nBufSize, szBuf);
+	xfunc_out();
+}
+
+#if defined(CONFIG_ENABLE_SERVICE_FLOW)
+static void Ind_NotiServiceFlow(dev_hand_t *hand, WIMAX_SF_EVENT_P pSfEvent)
+{
+	api_hand_t *api_hand = (api_hand_t *) hand->api;
+	gct_api_t *gcti;
+	GDEV_ID id;
+
+	xfunc_in();
+	id.apiHandle = api_hand;
+	id.deviceIndex = hand->dev_idx;
+	gcti = (gct_api_t *) api_hand->api;
+	gcti->ind.noti_service_flow(&id, pSfEvent);
+	xfunc_out();
+}
+#endif // CONFIG_ENABLE_SERVICE_FLOW
+
+GCT_API_RET GAPI_SubscribeDeviceStatusChange(APIHAND hAPI,
+				GIndDeviceStatusUpdate pCallbackFunc)
+{
+	api_hand_t *api_hand = (api_hand_t *) hAPI;
+	gct_api_t *gcti;
+	GCT_API_RET gret;
+
+	if ((gret = GAPI_CheckHandle(hAPI)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	if (sdk_reg_dev_stat_update(api_hand, Ind_DeviceStatusChange) < 0)
+		return GCT_API_RET_FAILED;
+	else {
+		gcti = (gct_api_t *) api_hand->api;
+		gcti->ind.stat_update = pCallbackFunc;
+		return GCT_API_RET_SUCCESS;
+	}
+}
+
+GCT_API_RET GAPI_SubscribeNotiFunc(APIHAND hAPI, GIndNotification pCallbackFunc)
+{
+	api_hand_t *api_hand = (api_hand_t *) hAPI;
+	gct_api_t *gcti;
+	GCT_API_RET gret;
+
+	if ((gret = GAPI_CheckHandle(hAPI)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	if (sdk_reg_notification(api_hand, Ind_Notification) < 0)
+		return GCT_API_RET_FAILED;
+	else {
+		gcti = (gct_api_t *) api_hand->api;
+		gcti->ind.notification = pCallbackFunc;
+		return GCT_API_RET_SUCCESS;
+	}
+}
+
+#if defined(CONFIG_ENABLE_SERVICE_FLOW)
+GCT_API_RET GAPI_SubscribeNotiServiceFlow(APIHAND hAPI,
+						GIndNotiServiceFlow pCallbackFunc)
+{
+	api_hand_t *api_hand = (api_hand_t *) hAPI;
+	gct_api_t *gcti;
+	GCT_API_RET gret;
+
+	if ((gret = GAPI_CheckHandle(hAPI)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	if (sdk_reg_noti_service_flow(api_hand, Ind_NotiServiceFlow) < 0)
+		return GCT_API_RET_FAILED;
+	else {
+		gcti = (gct_api_t *) api_hand->api;
+		gcti->ind.noti_service_flow = pCallbackFunc;
+		return GCT_API_RET_SUCCESS;
+	}
+}
+#endif // CONFIG_ENABLE_SERVICE_FLOW
+
+GCT_API_RET GAPI_UnSubscribeDeviceInsertRemove(APIHAND hAPI)
+{
+	api_hand_t *api_hand = (api_hand_t *) hAPI;
+	gct_api_t *gcti;
+	GCT_API_RET gret;
+
+	if ((gret = GAPI_CheckHandle(hAPI)) != GCT_API_RET_SUCCESS)
+		return gret;
+	
+	if (sdk_unreg_dev_insert_remove(api_hand) < 0)
+		return GCT_API_RET_FAILED;
+	else {
+		gcti = (gct_api_t *) api_hand->api;
+		gcti->ind.insert_remove = NULL;
+		return GCT_API_RET_SUCCESS;
+	}
+}
+
+GCT_API_RET GAPI_UnSubscribeControlPowerManagement(APIHAND hAPI)
+{
+	api_hand_t *api_hand = (api_hand_t *) hAPI;
+	gct_api_t *gcti;
+	GCT_API_RET gret;
+
+	if ((gret = GAPI_CheckHandle(hAPI)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	if (sdk_unreg_ctrl_power_mng(api_hand) < 0)
+		return GCT_API_RET_FAILED;
+	else {
+		gcti = (gct_api_t *) api_hand->api;
+		gcti->ind.pow_mng = NULL;
+		return GCT_API_RET_SUCCESS;
+	}
+}
+
+GCT_API_RET GAPI_UnSubscribeConnectToNetwork(APIHAND hAPI)
+{
+	api_hand_t *api_hand = (api_hand_t *) hAPI;
+	gct_api_t *gcti;
+	GCT_API_RET gret;
+
+	if ((gret = GAPI_CheckHandle(hAPI)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	if (sdk_unreg_connect_network(api_hand) < 0)
+		return GCT_API_RET_FAILED;
+	else {
+		gcti = (gct_api_t *) api_hand->api;
+		gcti->ind.connect_net = NULL;
+		return GCT_API_RET_SUCCESS;
+	}
+}
+
+GCT_API_RET GAPI_UnSubscribeDisconnectToNetwork(APIHAND hAPI)
+{
+	api_hand_t *api_hand = (api_hand_t *) hAPI;
+	gct_api_t *gcti;
+	GCT_API_RET gret;
+
+	if ((gret = GAPI_CheckHandle(hAPI)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	if (sdk_unreg_disconnect_network(api_hand) < 0)
+		return GCT_API_RET_FAILED;
+	else {
+		gcti = (gct_api_t *) api_hand->api;
+		gcti->ind.disconnect_net = NULL;
+		return GCT_API_RET_SUCCESS;
+	}
+}
+
+GCT_API_RET GAPI_UnSubscribeNetworkSearchWideScan(APIHAND hAPI)
+{
+	api_hand_t *api_hand = (api_hand_t *) hAPI;
+	gct_api_t *gcti;
+	GCT_API_RET gret;
+
+	if ((gret = GAPI_CheckHandle(hAPI)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	if (sdk_unreg_network_search_wscn(api_hand) < 0)
+		return GCT_API_RET_FAILED;
+	else {
+		gcti = (gct_api_t *) api_hand->api;
+		gcti->ind.net_search_wscan = NULL;
+		return GCT_API_RET_SUCCESS;
+	}
+}
+
+GCT_API_RET GAPI_UnSubscribeProvisioningOperation(APIHAND hAPI)
+{
+	api_hand_t *api_hand = (api_hand_t *) hAPI;
+	gct_api_t *gcti;
+	GCT_API_RET gret;
+
+	if ((gret = GAPI_CheckHandle(hAPI)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	if (sdk_unreg_provisioning_op(api_hand) < 0)
+		return GCT_API_RET_FAILED;
+	else {
+		gcti = (gct_api_t *) api_hand->api;
+		gcti->ind.provisioning = NULL;
+		return GCT_API_RET_SUCCESS;
+	}
+}
+
+GCT_API_RET GAPI_UnSubscribeDeviceStatusChange(APIHAND hAPI)
+{
+	api_hand_t *api_hand = (api_hand_t *) hAPI;
+	gct_api_t *gcti;
+	GCT_API_RET gret;
+
+	if ((gret = GAPI_CheckHandle(hAPI)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	if (sdk_unreg_dev_stat_update(api_hand) < 0)
+		return GCT_API_RET_FAILED;
+	else {
+		gcti = (gct_api_t *) api_hand->api;
+		gcti->ind.stat_update = NULL;
+		return GCT_API_RET_SUCCESS;
+	}
+}
+
+GCT_API_RET GAPI_UnSubscribeNotiFunc(APIHAND hAPI)
+{
+	api_hand_t *api_hand = (api_hand_t *) hAPI;
+	gct_api_t *gcti;
+	GCT_API_RET gret;
+
+	if ((gret = GAPI_CheckHandle(hAPI)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	if (sdk_unreg_notification(api_hand) < 0)
+		return GCT_API_RET_FAILED;
+	else {
+		gcti = (gct_api_t *) api_hand->api;
+		gcti->ind.notification = NULL;
+		return GCT_API_RET_SUCCESS;
+	}
+}
+
+#if defined(CONFIG_ENABLE_SERVICE_FLOW)
+GCT_API_RET GAPI_UnSubscribeNotiServiceFlow(APIHAND hAPI)
+{
+	api_hand_t *api_hand = (api_hand_t *) hAPI;
+	gct_api_t *gcti;
+	GCT_API_RET gret;
+
+	if ((gret = GAPI_CheckHandle(hAPI)) != GCT_API_RET_SUCCESS)
+		return gret;
+
+	if (sdk_unreg_noti_service_flow(api_hand) < 0)
+		return GCT_API_RET_FAILED;
+	else {
+		gcti = (gct_api_t *) api_hand->api;
+		gcti->ind.noti_service_flow = NULL;
+		return GCT_API_RET_SUCCESS;
+	}
+}
+#endif // CONFIG_ENABLE_SERVICE_FLOW
diff --git a/sdk/gctapi.h b/sdk/gctapi.h
new file mode 100644
index 0000000..92d018f
--- /dev/null
+++ b/sdk/gctapi.h
@@ -0,0 +1,141 @@
+// 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.
+
+#ifndef	__GCT_API_H__
+#define	__GCT_API_H__
+
+#include "gcttype.h"
+
+//
+// GCT APIs
+//
+GCT_API_RET GAPI_Initialize(GCT_WIMAX_SDK_MODE mode, GCT_WIMAX_API_PARAM *param);
+GCT_API_RET GAPI_DeInitialize(void);
+GCT_API_RET GAPI_WiMaxAPIOpen(APIHAND *phAPI, GCT_WIMAX_API_OPEN_MODE mode);
+GCT_API_RET GAPI_WiMaxAPIClose(APIHAND hAPI);
+GCT_API_RET GAPI_SetDebugLevel(APIHAND hAPI, int level, int *prev_level);
+#define LOG_FLAG_NO_STDOUT_IN_LOGFILE	(1<<0)
+GCT_API_RET GAPI_PrintLog(APIHAND hAPI, int flag, const char *title, const char *fmt, ...);
+GCT_API_RET GAPI_RegRcvHCIPacketFunc(APIHAND hAPI, GIndRcvHCIPacket pFunc);
+GCT_API_RET GAPI_DeRegRcvHCIPacketFunc(APIHAND hAPI);
+GCT_API_RET GAPI_RegPowerModeChange(APIHAND hAPI, GIndPowerModeChange pFunc);
+GCT_API_RET GAPI_DeRegPowerModeChange(APIHAND hAPI);
+GCT_API_RET GAPI_WiMaxDeviceOpen(GDEV_ID_P pID);
+GCT_API_RET GAPI_WiMaxDeviceClose(GDEV_ID_P pID);
+GCT_API_RET GAPI_GetDeviceStatus(GDEV_ID_P pID, WIMAX_API_DEVICE_STATUS_P pDeviceStatus,
+				WIMAX_API_CONNECTION_PROGRESS_INFO_P pConnectionProgressInfo);
+GCT_API_RET GAPI_WriteHCIPacket(GDEV_ID_P pID, char *szBuf, int nBufSize);
+GCT_API_RET GAPI_GetListDevice(APIHAND hAPI, WIMAX_API_HW_DEVICE_ID_P pHwDeviceIdList,
+				UINT32* pHwDeviceIdListSize);
+GCT_API_RET GAPI_CmdControlPowerManagement(GDEV_ID_P pID, WIMAX_API_RF_STATE powerState);
+GCT_API_RET GAPI_SetServiceProviderUnLock(GDEV_ID_P pID, WIMAX_API_WSTRING lockCode);
+GCT_API_RET GAPI_GetServiceProviderLockStatus(GDEV_ID_P pID, 
+				WIMAX_API_LOCK_STATUS_P pLockStatus, UCHAR16 *NSPName);
+GCT_API_RET GAPI_GetContactInformation(GDEV_ID_P pID, WIMAX_API_WSTRING nspName,
+				WIMAX_API_CONTACT_INFO_P pContactInfo, 	UINT32* pSizeOfContactList);
+GCT_API_RET GAPI_GetStatistics(GDEV_ID_P pID, WIMAX_API_CONNECTION_STAT_P pStatistics);
+GCT_API_RET GAPI_GetLinkStatus(GDEV_ID_P pID, WIMAX_API_LINK_STATUS_INFO_P pLinkStatus);
+GCT_API_RET GAPI_GetConnectedNSP(GDEV_ID_P pID, WIMAX_API_CONNECTED_NSP_INFO_P pNspInfo);
+GCT_API_RET GAPI_GetNetworkList(GDEV_ID_P pID, WIMAX_API_NSP_INFO_P pNSPInfo,
+				UINT32* pListCnt);
+GCT_API_RET GAPI_CmdConnectToNetwork(GDEV_ID_P pID, WIMAX_API_WSTRING nspName,
+				WIMAX_API_PROFILE_ID profileID);
+GCT_API_RET GAPI_CmdDisconnectFromNetwork(GDEV_ID_P pID);
+GCT_API_RET GAPI_GetSelectProfileList(GDEV_ID_P pID,
+				WIMAX_API_PROFILE_INFO_P pProfileList, UINT32* pListCnt);
+GCT_API_RET GAPI_SetProfile(GDEV_ID_P pID, WIMAX_API_PROFILE_ID profileID);
+GCT_API_RET GAPI_SetScanInterval(GDEV_ID_P pID, UINT32 intervalSec);
+GCT_API_RET GAPI_SetEap(GDEV_ID_P pID, GCT_API_EAP_PARAM_P eap);
+GCT_API_RET GAPI_GetDeviceInformation(GDEV_ID_P pID, WIMAX_API_DEVICE_INFO_P pDeviceInfo);
+GCT_API_RET GAPI_SetFrequency(GDEV_ID_P pID, UINT32 nFreq, UINT32 nBandWidth,
+				UINT32 nFFTSize);
+GCT_API_RET GAPI_GetRFInform(GDEV_ID_P pID, GCT_API_RF_INFORM_P pRFInform);
+GCT_API_RET GAPI_GetBootloaderVersion(GDEV_ID_P pID, char *str, int size);
+GCT_API_RET GAPI_GetCapability(GDEV_ID_P pID, CAPABILITY_BIT_P cap);
+GCT_API_RET GAPI_SetCapability(GDEV_ID_P pID, CAPABILITY_BIT cap);
+GCT_API_RET GAPI_GetNeighborList (GDEV_ID_P pID, 
+				GCT_API_NEIGHBOR_LIST_P pNeighborList, UINT32* pArrayLength);
+GCT_API_RET GAPI_NetworkSearchScan(GDEV_ID_P pID, GCT_API_SCAN_TYPE type);
+#define GAPI_NetworkSearchWideScan(pID)	GAPI_NetworkSearchScan(pID, GCT_API_SCAN_WIDE)
+GCT_API_RET GAPI_CancelWideScan(GDEV_ID_P pID);
+GCT_API_RET GAPI_CmdMACState(GDEV_ID_P pID, GCT_API_CMD_MAC_STATE_TYPE type);
+GCT_API_RET GAPI_SetIdleModeTimeout(GDEV_ID_P pID, UINT16 timeoutSec);
+GCT_API_RET GAPI_GetPHY_MAC_Basic(GDEV_ID_P pID, GCT_API_MAC_PHY_MAC_BASIC_P pData);
+GCT_API_RET GAPI_GetPHY_MCS(GDEV_ID_P pID, GCT_API_MAC_PHY_MCS_P pData);
+GCT_API_RET GAPI_GetPHY_CINR_RSSI(GDEV_ID_P pID, GCT_API_MAC_PHY_CINR_RSSI_P pData);
+
+#if defined(CONFIG_ENABLE_SERVICE_FLOW)
+GCT_API_RET GAPI_BeginSFRead(GDEV_ID_P pID);
+GCT_API_RET GAPI_EndSFRead(GDEV_ID_P pID);
+GCT_API_RET GAPI_GetNextSF(GDEV_ID_P pID,
+				WIMAX_SERVICE_FLOW *pSF,
+				UINT8 Direction,
+				WIMAX_SERVICE_FLOW **ppRetSF);
+GCT_API_RET GAPI_GetServiceFlow(GDEV_ID_P pID,
+				UINT32 SFID,
+				WIMAX_SERVICE_FLOW **ppRetSF);
+GCT_API_RET GAPI_GetNextClfrRule(GDEV_ID_P pID, 
+				WIMAX_SERVICE_FLOW *pSF,
+				WIMAX_CLFR_RULE *pCLFRRule,
+				WIMAX_CLFR_RULE **ppRetCLFRRule);
+GCT_API_RET GAPI_GetClfrRule(GDEV_ID_P pID, 
+				WIMAX_SERVICE_FLOW *pSF,
+				UINT16 PacketClassfierRuleIndex,
+				WIMAX_CLFR_RULE **ppRetCLFRRule);
+GCT_API_RET GAPI_GetNextPHSRule(GDEV_ID_P pID, 
+				WIMAX_SERVICE_FLOW *pSF,
+				WIMAX_PHS_RULE *pPHSRule,
+				WIMAX_PHS_RULE **ppRetPHSRule);
+GCT_API_RET GAPI_GetPHSRule(GDEV_ID_P pID, 
+				WIMAX_SERVICE_FLOW *pSF, 
+				UINT8 PHSI,
+				WIMAX_PHS_RULE **ppRetPHSRule);
+GCT_API_RET GAPI_CmdAddSF(GDEV_ID_P pID,
+				WIMAX_SF_PARAM_P pSFParam,
+				WIMAX_CLFR_RULE_P pClfrRule,
+				WIMAX_PHS_RULE_P pPHSRule);
+GCT_API_RET GAPI_CmdChangeSF(GDEV_ID_P pID,
+				WIMAX_SF_PARAM_P pSFParam,
+				WIMAX_CLFR_DSC_ACTION CLFRDSCAction,
+				WIMAX_CLFR_RULE_P pClfrRule,
+				WIMAX_PHS_DSC_ACTION PHSDSCAction,
+				WIMAX_PHS_RULE_P pPHSRule);
+GCT_API_RET GAPI_CmdDeleteSF(GDEV_ID_P pID,
+				WIMAX_SF_PARAM_P pSFParam);
+#endif // CONFIG_ENABLE_SERVICE_FLOW
+
+GCT_API_RET GAPI_SubscribeDeviceInsertRemove(APIHAND hAPI,
+						GIndDeviceInsertRemove pCallbackFunc);
+GCT_API_RET GAPI_SubscribeControlPowerManagement(APIHAND hAPI,
+						GIndControlPowerManagement pCallbackFunc);
+GCT_API_RET GAPI_SubscribeConnectToNetwork(APIHAND hAPI,
+						GIndConnectToNetwork pCallbackFunc);
+GCT_API_RET GAPI_SubscribeDisconnectFromNetwork(APIHAND hAPI,
+						GIndDisconnectFromNetwork pCallbackFunc);
+GCT_API_RET GAPI_SubscribeNetworkSearchWideScan(APIHAND hAPI,
+						GIndNetworkSearchWideScan pCallbackFunc);
+GCT_API_RET GAPI_SubscribeProvisioningOperation(APIHAND hAPI,
+						GIndProvisioningOperation pCallbackFunc);
+GCT_API_RET GAPI_SubscribeDeviceStatusChange(APIHAND hAPI,
+						GIndDeviceStatusUpdate pCallbackFunc);
+GCT_API_RET GAPI_SubscribeNotiFunc(APIHAND hAPI,
+						GIndNotification pCallbackFunc);
+#if defined(CONFIG_ENABLE_SERVICE_FLOW)
+GCT_API_RET GAPI_SubscribeNotiServiceFlow(APIHAND hAPI,
+						GIndNotiServiceFlow pCallbackFunc);
+#endif // CONFIG_ENABLE_SERVICE_FLOW
+
+GCT_API_RET GAPI_UnSubscribeDeviceInsertRemove(APIHAND hAPI);
+GCT_API_RET GAPI_UnSubscribeControlPowerManagement(APIHAND hAPI);
+GCT_API_RET GAPI_UnSubscribeConnectToNetwork(APIHAND hAPI);
+GCT_API_RET GAPI_UnSubscribeDisconnectToNetwork(APIHAND hAPI);
+GCT_API_RET GAPI_UnSubscribeNetworkSearchWideScan(APIHAND hAPI);
+GCT_API_RET GAPI_UnSubscribeProvisioningOperation(APIHAND hAPI);
+GCT_API_RET GAPI_UnSubscribeDeviceStatusChange(APIHAND hAPI);
+GCT_API_RET GAPI_UnSubscribeNotiFunc(APIHAND hAPI);
+#if defined(CONFIG_ENABLE_SERVICE_FLOW)
+GCT_API_RET GAPI_UnSubscribeNotiServiceFlow(APIHAND hAPI);
+#endif // CONFIG_ENABLE_SERVICE_FLOW
+
+#endif
diff --git a/sdk/gcttype.h b/sdk/gcttype.h
new file mode 100644
index 0000000..643b89f
--- /dev/null
+++ b/sdk/gcttype.h
@@ -0,0 +1,799 @@
+// 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.
+
+#if !defined(GCTTYPE_H_20100310)
+#define GCTTYPE_H_20100310
+
+#include "WiMaxType.h"
+
+#if !defined(SDK_TYPEDEF)
+#define SDK_TYPEDEF
+typedef char 				bool;
+typedef unsigned char		u8;
+typedef unsigned short		u16;
+typedef unsigned int		u32;
+typedef unsigned long long	u64;
+typedef	signed char			s8;
+typedef signed short		s16;
+typedef int				s32;
+typedef long long			s64;
+#if 1
+typedef wchar_t				uchar;
+#else
+typedef unsigned short		uchar;
+#endif
+#endif
+
+#define GCT_API 
+#define INVALID_GHANDLE		0x000000000
+
+typedef enum _GCT_API_RET
+{
+	GCT_API_RET_FIRST_COMMON_ERROR = 0,
+	/// No errors
+	GCT_API_RET_SUCCESS,
+	/// Fail to obtain results
+	GCT_API_RET_FAILED,	
+	/// Buffer size pass in parameter is too small.
+	GCT_API_RET_BUFFER_SIZE_TOO_SMALL,	
+	/// Invalid privileges to execute the command
+	GCT_API_RET_PERMISSION_DENIED,	
+	/// Device specified is invalid.
+	GCT_API_RET_INVALID_DEVICE,	
+	/// Invalid Parameter Passed
+	GCT_API_RET_INVALID_PARAMETER,
+	/// Cannot perform the command mobile connection.
+	GCT_API_RET_ALREADY_CONNECTED,
+	/// Link is not connected, cannot obtain result.
+	GCT_API_RET_LINK_NOT_CONNECTED,
+	/// Connection to the network is prohibited
+	GCT_API_RET_NETWORK_PROHIBITED,
+	/// Device specified is missing because of just being removed!
+	GCT_API_RET_DEVICE_MISSING,
+	/// Profile specified is invalid.
+	GCT_API_RET_INVALID_PROFILE,	
+	/// Connection to a roaming network is not allowed.
+	GCT_API_RET_ROAMING_NOT_ALLOWED,	
+	/// Connection is already in progress
+	GCT_API_RET_CONNECTION_IN_PROGRESS,
+	/// Function not implemented
+	GCT_API_RET_NOT_IMPLEMENTED,
+	/// SDK is busy
+	GCT_API_RET_BUSY,
+
+	/// last error code
+	GCT_API_RET_LAST_COMMON_ERROR							
+} GCT_API_RET, *PGCT_API_RET;
+
+typedef void * APIHAND;
+
+typedef struct GDEV_ID_S {
+	APIHAND apiHandle;
+	u8 deviceIndex;
+
+} GDEV_ID, *GDEV_ID_P;
+
+typedef enum _GCT_WIMAX_SDK_MODE
+{
+	GCT_WIMAX_SDK_EMBEDDED_EAP_ENABLED = (1<<0),
+	GCT_WIMAX_SDK_OMA_DM_ENABLED = (1<<1),
+	GCT_WIMAX_SDK_MODE_MAX
+
+} GCT_WIMAX_SDK_MODE;
+
+typedef enum _GCT_WIMAX_API_OPEN_MODE
+{
+	GCT_WIMAX_API_PRIVILEGE_READ_WRITE = (1<<0), /**< Read Write privilege access.(default) */
+	GCT_WIMAX_API_PRIVILEGE_READ_ONLY = (1<<1),  /**< Read Only privilege access. */
+	
+	GCT_WIMAX_API_OPEN_MODE_NORMAL = (1<<2),
+	GCT_WIMAX_API_OPEN_MODE_ENG = (1<<3),
+	
+	GCT_WIMAX_API_OPEN_MODE_MAX
+
+} GCT_WIMAX_API_OPEN_MODE, *PGCT_WIMAX_API_OPEN_MODE;
+
+
+typedef struct _GCT_WIMAX_API_PARAM {
+	char nonvolatile_dir[256];
+	char log_path[256];
+	int log_level;
+
+} GCT_WIMAX_API_PARAM;
+
+typedef enum _GCT_API_POWER_MODE
+{
+	WiMAXPowerModeIdle,
+	WiMAXPowerModeSleep,
+	WiMAXPowerModeNormal,
+
+	WiMAXPowerModeMaximum
+
+} GCT_API_POWER_MODE, *GCT_API_POWER_MODE_P;
+
+typedef struct _GCT_API_NEIGHBOR_LIST
+{
+	UINT32	structureSize;		/**< size of this structure. */
+	UINT8	bsId[6];			/**< BS ID of the current serving BS as received from the network */
+	UINT8	rssi;				/**< RSSI value */
+	UINT8	cinr;				/**< CINR value */
+	UINT8	preamble;			/** preamble value */
+	//UINT16	roundTripTime;		/** round trip time from the base station measured in nanoseconds. */                 
+	UINT32	frequency;
+
+} GCT_API_NEIGHBOR_LIST, *GCT_API_NEIGHBOR_LIST_P;
+
+typedef struct gct_harq_statistics_s
+{
+	UINT32 NumDlHarqRetry[8];
+	UINT32 NumUlHarqRetry[8];
+
+} gct_harq_statistics_t;
+
+typedef struct gct_mcs_stats_s {
+	UINT8 ModulationFEC;
+	UINT8 RepetitionCode;
+	UINT8 IUC;
+	UINT8 Feature;
+	UINT8 NumBurst;
+	UINT8 NumBurstError;
+	UINT8 LenPDU;
+	UINT8 NumPDU;
+
+} gct_mcs_stats_t;
+
+typedef enum _GCT_API_EAP_TYPE
+{
+	GCT_WIMAX_NO_EAP = 0,
+	GCT_WIMAX_EAP_TLS = 1,
+	GCT_WIMAX_EAP_TTLS_MD5 = 2,
+	GCT_WIMAX_EAP_TTLS_MSCHAPV2 = 3,
+	GCT_WIMAX_EAP_TTLS_CHAP = 4,
+	GCT_WIMAX_EAP_AKA = 5
+
+} GCT_API_EAP_TYPE;
+#define GCT_API_IS_EAP_TLS(t)	((t)>=GCT_WIMAX_EAP_TLS && (t)<=GCT_WIMAX_EAP_TTLS_CHAP)
+#define GCT_API_IS_VALID_EAP(t)	((t)>=GCT_WIMAX_EAP_TLS && (t)<=GCT_WIMAX_EAP_AKA)
+
+typedef struct _GCT_API_EAP_PARAM
+{
+#define WIMAX_EAP_STR_LEN		256
+#define WIMAX_EAP_FILE_LEN		256
+#define WIMAX_EAP_DECO_LEN		128	/*decoration*/
+	GCT_API_EAP_TYPE	type;
+
+	UINT16		fragSize;
+	UINT8		useDelimiter;
+	UINT8		devCertNULL;
+	UINT8		caCertNULL;
+	UINT8		disableResumption;
+	UINT8		cr801Enable;
+	UINT8		disableSessionTicket;
+
+	UINT8		useNvramParam;
+	UINT8		userId[WIMAX_EAP_STR_LEN];
+	UINT8		userIdPwd[WIMAX_EAP_STR_LEN];
+	UINT8		anonymousId[WIMAX_EAP_STR_LEN];
+	UINT8		privateKeyPwd[WIMAX_EAP_STR_LEN];
+
+	UINT8		decoration[WIMAX_EAP_DECO_LEN];
+
+#define CACERT_NUM				10
+
+	UINT8		logEnable;
+} GCT_API_EAP_PARAM, *GCT_API_EAP_PARAM_P;
+
+typedef struct _GCT_API_ODM_PARAM
+{
+	UINT8		useODM;
+
+} GCT_API_ODM_PARAM, *GCT_API_ODM_PARAM_P;
+
+typedef struct _GCT_API_CERT_INFO
+{
+#define WIMAX_CERT_STR_LEN		256
+	UINT32		source;
+	UINT8		cert_type[WIMAX_CERT_STR_LEN];
+	UINT8		subject_cn[WIMAX_CERT_STR_LEN];
+	UINT8		issuer_cn[WIMAX_CERT_STR_LEN];
+	UINT8		expire_date[WIMAX_CERT_STR_LEN];
+
+} GCT_API_CERT_INFO, *GCT_API_CERT_INFO_P;
+
+typedef struct _GCT_API_RF_INFORM {
+	INT32		nPERReceiveCount;
+	INT32		nPERErrorCount;
+	UINT8		bsId[6];
+	UINT8		ULPermBase;
+	UINT8		DLPermBase;
+	UINT8		CurrentPreambleIndex;
+	UINT8		PreviousPreambleIndex;
+	UINT16		HandOverCount;
+	UINT16		HandOverFailCount;
+	UINT16		ResyncCount;	
+	UINT16		HoSignalLatency;
+	UINT8		CINR;
+	UINT8		CINR2;
+	UINT8		RSSI;
+	UINT8		RSSI2;
+	UINT16		PER;
+	UINT8		PowerControlMode;
+	UINT8		TxPower;
+	UINT8		TxPowerMax;
+	UINT8		ULBurstDataFECScheme;
+	UINT8		DLBurstDataFECScheme;
+	UINT8		ULBurstDataUIUC;
+	UINT8		DLBurstDataDIUC;
+	UINT32		Frequency;
+
+} GCT_API_RF_INFORM, *GCT_API_RF_INFORM_P;
+
+typedef enum _GCT_API_SCAN_TYPE {
+	GCT_API_SCAN_WIDE,
+	GCT_API_SCAN_ALL_SUBSCRIPTIONS,
+	GCT_API_SCAN_CURR_SUBSCRIPTION
+
+} GCT_API_SCAN_TYPE, *GCT_API_SCAN_TYPE_P;
+
+typedef enum _GCT_API_NOTI_CATEGORY {
+	GCT_API_ERROR_NOTI_EAP,
+	GCT_API_NOTI_EAP,
+	GCT_API_NOTI_ODM_NOTI,
+	GCT_API_NOTI_ODM_ERROR
+
+} GCT_API_NOTI_CATEGORY, *GCT_API_NOTI_CATEGORY_P;
+
+typedef enum _GCT_API_ODM_NOTI_TYPE_P {
+	GCT_API_ODM_NOTI_EXEC_REGISTRATION_PAGE_OPEN,
+	GCT_API_ODM_NOTI_CHANGE_ACTIVATED,				
+	GCT_API_ODM_NOTI_UNKNOWN_SERVER_REALM			// for CR1074
+
+} GCT_API_ODM_NOTI_TYPE, *GCT_API_ODM_NOTI_TYPE_P;
+
+typedef enum _GCT_API_NOTI_TYPE {
+	GCT_API_NOTI_TYPE_CODE,
+	GCT_API_NOTI_TYPE_TEXT	
+
+} GCT_API_NOTI_TYPE, *GCT_API_NOTI_TYPE_P;
+
+typedef enum _IMAGE_TYPE {
+	IMG_KERNEL = 0,
+	IMG_FS = 1,
+	IMG_CFG = 2,
+	IMG_CFG_RAM = 3,
+	IMG_FS2 = 4,
+	IMG_CLR_CFG = 5,
+	IMG_EAP_PARAM = 6,
+	IMG_BL_EEPROM = 7,
+	IMG_BL_FLASH = 8,
+
+	IMG_OMA_XML = 0x100,
+	IMG_DEV_CERT = 0x101,
+	IMG_CERT1_U = 0x102,
+	IMG_CERT1_L = 0x103,
+	IMG_CERT2_U = 0x104,
+	IMG_CERT2_L = 0x105,
+	IMG_CERT_BIG = 0x106,
+
+	IMG_END
+	
+} IMAGE_TYPE;
+
+typedef enum _CAPABILITY_BIT {
+	CAPABILITY_ENC_XML		= (1<<0),
+	CAPABILITY_E_EAP_TLS	= (1<<1),
+	CAPABILITY_ODM			= (1<<2),
+	CAPABILITY_E_EAP_AKA	= (1<<3),
+	CAPABILITY_CAPL_INFO	= (1<<4),
+
+	CAPABILITY_END
+
+} CAPABILITY_BIT, *CAPABILITY_BIT_P;
+
+#if defined(CONFIG_ENABLE_SERVICE_FLOW)
+/*----------------------------------------------------------------------
+ *
+ * Service Flow Management
+ *
+ *----------------------------------------------------------------------*/
+
+#include <netinet/in.h>
+
+#define WIMAX_MAX_SERVICE_FLOW		16
+#define WIMAX_MAX_RULES			16	/* MAX rules per SF */
+#define MAX_SERVICE_CLASS_NAME	128
+
+
+/* UL Grant Scheduling Type Parameter */
+#define UL_SCHED_TYPE_RESERVED		0
+#define UL_SCHED_TYPE_UNDEF		1
+#define UL_SCHED_TYPE_BE		2
+#define UL_SCHED_TYPE_nrtPS		3
+#define UL_SCHED_TYPE_rtPS		4
+#define UL_SCHED_TYPE_ertPS		5
+#define UL_SCHED_TYPE_UGS		6
+
+
+/* Type of Data Delivery Services parameter */
+#define DATA_SERVICE_UGS		0
+#define DATA_SERVICE_RT_VR		1
+#define DATA_SERVICE_NRT_VR		2
+#define DATA_SERVICE_BE			3
+#define DATA_SERVICE_ERT_VR		4
+
+#define MAX_PHSS	128
+
+struct wimax_sf_event_param {
+	uint8_t		cc;		/* confirm code */
+	uint8_t		ms_initiated;	/* MS initiated DSx */
+	uint32_t	sfid; 		/* SFID SF event took place on */
+	int8_t		clfr_action;	/* classification rule DSC action */
+	uint16_t	PacketClassificationRuleIndex; /* changed classfication rule index */
+	int8_t		phs_action;	/* phs rule changed DSC action */
+	uint16_t	PHSI;		/* changed PHSI */
+};
+
+typedef enum _WIMAX_SF_EVENT_TYPE {
+	/* Service flow-related events */
+	WIMAX_EVT_SERVICE_FLOW_ADDED,
+	WIMAX_EVT_SERVICE_FLOW_CHANGED,	
+	WIMAX_EVT_SERVICE_FLOW_DELETED,
+	WIMAX_EVT_CID_UPDATE,
+} WIMAX_SF_EVENT_TYPE;
+
+typedef struct _wimax_sf_event {
+	WIMAX_SF_EVENT_TYPE	code;
+	struct wimax_sf_event_param sf;
+} __attribute__((packed)) WIMAX_SF_EVENT, *WIMAX_SF_EVENT_P;
+
+typedef enum {
+	WIMAX_SF_SUCCESS = 0,
+	WIMAX_SF_OTHER,
+	WIMAX_SF_UNRECOGNIZED_CONF_SETTING,
+	WIMAX_SF_TEMPORARY,		// reject-resource
+	WIMAX_SF_PERMANANT,		// reject-admin
+	WIMAX_SF_NOT_OWNER,
+	WIMAX_SF_NOT_FOUND,
+	WIMAX_SF_EXISTS,
+	WIMAX_SF_REQIRED_PARAM_NOT_PRESENT,
+	WIMAX_SF_HEADER_SUPRESSION,
+	WIMAX_SF_UNKNOWN_TRANSACTION_ID,
+	WIMAX_SF_AUTH_FAILURE,
+	WIMAX_SF_ADD_ABORTED,
+	WIMAX_SF_EXCEEDED_DYNAMIC_SERVICE_LIMIT,
+	WIMAX_SF_NOT_AUTHORIZED_FOR_THE_REQUESTED_SAID,
+	WIMAX_SF_FAIL_TO_ESTABLISH_THE_REQUESTED_SA,
+	WIMAX_SF_NOT_SUPPORTED_PARAMETER,
+	WIMAX_SF_NOT_SUPPORTED_PARAMETER_VALUE
+} WIMAX_SF_CC;
+
+
+typedef enum {
+	DSC_ADD_CLASSIFIER = 0,
+	DSC_REPLACE_CLASSIFIER,
+	DSC_DELETE_CLASSIFIER,
+	DSC_NOP_CLASSIFIER,
+} WIMAX_CLFR_DSC_ACTION;
+
+
+typedef enum {
+	DSC_ADD_PHS = 0,
+	DSC_SET_PHS,		//TODO not tested
+	DSC_DELETE_PHS,
+	DSC_DELETE_ALL_PHS,	//TODO not supported
+	DSC_NOP_PHS,
+} WIMAX_PHS_DSC_ACTION;
+
+
+struct ipv4_addr {
+	struct in_addr	address;
+	struct in_addr  mask;
+} __attribute__((packed));
+
+
+struct ipv6_addr {
+	struct in6_addr address;
+	struct in6_addr mask;
+} __attribute__((packed));
+
+typedef struct wimax_classification_rule {
+	uint32_t	valid;
+
+	union {
+		uint16_t all;
+		struct {
+			uint16_t reserived:1;
+			uint16_t IPTypeOfService:1;
+			uint16_t Protocol:1;
+			uint16_t IPMaskedSrcAddress:1;
+			uint16_t IPMaskedDstAddress:1;
+			uint16_t ProtocolSrcPortRange:1;
+			uint16_t ProtocolDstPortRange:1;
+			uint16_t DstMacAddr:1;
+			uint16_t SrcMacAddr:1;
+			uint16_t Ethertype:1;
+			uint16_t IEEE802_1DUserPriority:1;
+			uint16_t IEEE802_1QVLANID:1;
+			uint16_t Reserved:5;
+		} fields;
+	} mask;    
+
+	/* Packet Classification Rule */
+	uint8_t 	ClassifierRulePriority;
+	struct {
+		uint8_t low;
+		uint8_t high;
+		uint8_t mask;
+	} __attribute__((packed)) IPTypeOfService;
+	
+	uint8_t	Protocol;
+	
+	struct ipv4_addr 	IPv4MaskedSourceAddress;
+	struct ipv6_addr	IPv6MaskedSourceAddress;
+	struct ipv4_addr	IPv4MaskedDestAddress;
+	struct ipv6_addr	IPv6MaskedDestAddress;	
+
+	struct {
+		uint16_t low;
+		uint16_t high;
+	} __attribute__((packed)) ProtocolSourcePort, ProtocolDestPort;
+
+	struct {
+		uint8_t	addr[6];
+		uint8_t	mask[6];
+	} __attribute__((packed)) EthernetDestMACAddress, EthernetSourceMACAddress;
+
+	struct {
+		uint8_t	type;
+		uint8_t	eprot1;
+		uint8_t	eprot2;
+	} __attribute__((packed)) EtherType;
+
+	struct {
+		uint8_t	low;
+		uint8_t high;
+	} __attribute__((packed)) IEEE802_1D_UserPriority;
+
+	uint16_t IEEE802_1Q_VLANID;
+
+	uint8_t 	AssociatedPHSI;
+	uint16_t 	PacketClassifierRuleIndex;
+	uint8_t		IPv6FlowLabel[3];
+	uint8_t		ContextID;
+} WIMAX_CLFR_RULE, *WIMAX_CLFR_RULE_P;
+
+
+typedef struct wimax_phs_rule {
+	uint32_t	valid;
+	struct wimax_phs_rule *next;	/* not used */
+	uint8_t		state;
+	uint8_t		PHSI;
+	uint8_t		PHSF[MAX_PHSS];
+	uint8_t		PHSM[(MAX_PHSS + 7) >> 3];
+	uint8_t		PHSS;
+	uint8_t		PHSV;
+} WIMAX_PHS_RULE, *WIMAX_PHS_RULE_P;
+
+
+typedef struct wimax_sf_param {
+	uint8_t		DL;
+	/* TLV - 11.13 */
+	uint32_t	SFID;
+	uint16_t	CID;
+	uint8_t		ServiceClassName[MAX_SERVICE_CLASS_NAME];
+	uint8_t		MBSService;
+	
+	uint8_t		QosParamSetType; /* Admitted, Active, Provisioned */
+	uint8_t		TrafficPriority; 		/* 6 */
+	uint32_t	MaxSustainedTrafficRate;
+	uint32_t	MaxTrafficBurst;
+	uint32_t	MinReservedTrafficRate;
+	uint32_t	MinTolerableRate;		/* 10 */
+	uint8_t		ULGrantSchedulingType;		/* 11 */
+	uint8_t		RequestTransmissionPolicy;	/* 12 */
+	uint32_t	ToleratedJitter;		/* 13 */
+	uint32_t	MaxLatency;			/* 14 */
+	
+	uint8_t		FixedLengthSDUIndicator;	/* 15 */
+	uint8_t		SDUSize;			/* 16 */
+	uint16_t	TargetSAID;			/* 17 */
+	
+	uint8_t		ARQEnable;			/* 18 */
+	uint16_t	ARQWindowSize;			/* 19 */
+	uint16_t	ARQTransmitterDelay;		/* 20 */
+	uint16_t	ARQReceiverDelay;		/* 21 */
+	uint16_t	ARQBlockLifeTime;		/* 22 */
+	uint16_t	ARQSyncLossTimeout;		/* 23 */
+	uint8_t		ARQDeliverInOrder;		/* 24 */
+	uint16_t	ARQRxPurgeTimeout;		/* 25 */
+	uint16_t	ARQBlockSize;			/* 26 */
+	uint8_t		ReceiverARQAckProcessingTime;	/* 27 */
+	
+	uint8_t		CSSpecification;		/* 28 */
+
+	uint8_t 	TypeOfDataDeliveryServices;	// 29
+	uint16_t 	SDUInterArrivalInterval;	// 30
+	uint16_t 	TimeBase;			// 31
+	uint8_t 	PagingPreference;		// 32
+	uint8_t 	MBSZoneID[8];			// 33
+	uint8_t 	TrafficPreferenceIndication;	// 34
+	uint8_t 	GlobalServiceClassName[6];	// 35
+	uint8_t 	SNFeedbackEnabled;		// 37
+	uint8_t 	FSNSize;			// 38
+	uint8_t 	Num_CIDAllocForActiveBSs;
+	uint16_t 	CIDAllocForActiveBSs[8];	// 39 ??
+	uint16_t 	UnsolicitedGrantInterval;	// 40
+	uint16_t 	UnsolicitedPollingInterval;	// 41
+	uint8_t 	PDUSNExtendedSubheaderForHARQReordering;	// 42
+	uint8_t 	Num_MBSContentsIDs;		// 43
+	uint16_t 	MBSContentsIDs[8];		// 43
+	uint8_t 	HARQServiceFlows;		// 44
+	uint8_t		AuthorizationToken;		// 45
+	uint8_t 	Num_HARQChannelMapping;		// 46
+	uint8_t 	HARQChannelMapping[16];		// 46
+} WIMAX_SF_PARAM, *WIMAX_SF_PARAM_P;
+
+typedef union wimax_sf_stats {
+    struct {
+	uint32_t	sdu_packets;
+	uint32_t	sdu_packets_dropped;
+	uint32_t	sdu_bytes;
+	uint32_t	sdu_bytes_dropped;
+	uint32_t	pdu_packets;
+	uint32_t	pdu_bytes;
+	
+	uint32_t	bw_req;
+	uint32_t	gmsh;
+	
+	uint32_t	arq_blocks;
+	uint32_t	arq_blocks_retry;
+	uint16_t	arq_discard;
+	uint16_t	arq_reset;
+	uint16_t	arq_sync_loss;		
+    } ul;
+    struct {
+	uint32_t	sdu_packets;
+	uint32_t	sdu_packets_dropped;
+	uint32_t	sdu_bytes;
+	uint32_t	sdu_bytes_dropped;
+	uint32_t	pdu_packets;
+	uint32_t	pdu_bytes;
+	
+	uint32_t	arq_blocks;
+	uint32_t	arq_blocks_retry;
+	uint16_t	arq_discard;
+	uint16_t	arq_reset;
+	uint16_t	arq_sync_loss;	
+    } dl;
+} WIMAX_SF_STATS, *WIMAX_SF_STATS_P;
+
+typedef struct wimax_service_flow {
+	uint8_t			valid;
+	struct wimax_sf_param 	param;
+	struct wimax_classification_rule classification_rule[WIMAX_MAX_RULES];
+	struct wimax_phs_rule	phs_rule[WIMAX_MAX_RULES];
+	union wimax_sf_stats	stats;
+} WIMAX_SERVICE_FLOW, *WIMAX_SERVICE_FLOW_P;
+
+
+extern const struct wimax_sf_param sf_param_init;
+extern const struct wimax_classification_rule classifier_rule_init;
+extern const struct wimax_phs_rule phs_rule_init;
+
+#endif // CONFIG_ENABLE_SERVICE_FLOW
+
+typedef enum _GCT_API_CMD_MAC_STATE_TYPE {
+	GCT_API_CMD_MAC_STATE_ENTER_SLEEP_MODE,
+	GCT_API_CMD_MAC_STATE_EXIT_SLEEP_MODE,
+	GCT_API_CMD_MAC_STATE_ENTER_IDLE_MODE,
+	GCT_API_CMD_MAC_STATE_EXIT_IDLE_MODE
+} GCT_API_CMD_MAC_STATE_TYPE, *GCT_API_CMD_MAC_STATE_TYPE_P;
+
+typedef enum _FEC_MOD {
+	OFDMA_FEC_MOD_QPSK_CC_H				= 0,
+	OFDMA_FEC_MOD_QPSK_CC_3Q			= 1,
+	OFDMA_FEC_MOD_QAM16_CC_H			= 2,
+	OFDMA_FEC_MOD_QAM16_CC_3Q			= 3,
+	OFDMA_FEC_MOD_QAM64_CC_H			= 4,
+	OFDMA_FEC_MOD_QAM64_CC_2O3			= 5,
+	OFDMA_FEC_MOD_QAM64_CC_3Q			= 6,
+	OFDMA_FEC_MOD_QPSK_BTC_H			= 7,
+	OFDMA_FEC_MOD_QPSK_BTC_3Q			= 8,
+	OFDMA_FEC_MOD_QAM16_BTC_3O5			= 9,
+	OFDMA_FEC_MOD_QAM16_BTC_4O5			= 10,
+	OFDMA_FEC_MOD_QAM64_BTC_5O8			= 11,
+	OFDMA_FEC_MOD_QAM64_BTC_4O5			= 12,
+	OFDMA_FEC_MOD_QPSK_CTC_H			= 13,
+	OFDMA_FEC_MOD_RESERVED14			= 14,
+	OFDMA_FEC_MOD_QPSK_CTC_3Q			= 15,
+	OFDMA_FEC_MOD_QAM16_CTC_H			= 16,
+	OFDMA_FEC_MOD_QAM16_CTC_3Q			= 17,
+	OFDMA_FEC_MOD_QAM64_CTC_H			= 18,
+	OFDMA_FEC_MOD_QAM64_CTC_2O3			= 19,
+	OFDMA_FEC_MOD_QAM64_CTC_3Q			= 20,
+	OFDMA_FEC_MOD_QAM64_CTC_5O6			= 21,
+	OFDMA_FEC_MOD_QPSK_ZTCC_H			= 22,
+	OFDMA_FEC_MOD_QPSK_ZTCC_3Q			= 23,
+	OFDMA_FEC_MOD_QAM16_ZTCC_H			= 24,
+	OFDMA_FEC_MOD_QAM16_ZTCC_3Q			= 25,
+	OFDMA_FEC_MOD_QAM64_ZTCC_H			= 26,
+	OFDMA_FEC_MOD_QAM64_ZTCC_2O3		= 27,
+	OFDMA_FEC_MOD_QAM64_ZTCC_3Q			= 28,
+	OFDMA_FEC_MOD_QPSK_SDPC_H			= 29,
+	OFDMA_FEC_MOD_QPSK_SDPC_2O3_A_CODE	= 30,
+	OFDMA_FEC_MOD_QPSK_LDPC_3Q_A_CODE	= 31,
+	OFDMA_FEC_MOD_QAM16_LDPC_H			= 32,
+	OFDMA_FEC_MOD_QAM16_LDPC_2O3_A_CODE	= 33,
+	OFDMA_FEC_MOD_QAM16_LDPC_3Q_A_CODE	= 34,
+	OFDMA_FEC_MOD_QAM64_LDPC_H			= 35,
+	OFDMA_FEC_MOD_QAM64_LDPC_2O3_A_CODE	= 36,
+	OFDMA_FEC_MOD_QAM64_LDPC_3Q_A_CODE	= 37,
+	OFDMA_FEC_MOD_QPSK_LDPC_2O3_B_CODE	= 38,
+	OFDMA_FEC_MOD_QPSK_LDPC_3Q_B_CODE	= 39,
+	OFDMA_FEC_MOD_QAM16_LDPC_2O3_B_CODE	= 40,
+	OFDMA_FEC_MOD_QAM16_LDPC_3Q_B_CODE	= 41,
+	OFDMA_FEC_MOD_QAM64_LDPC_2O3_B_CODE	= 42,
+	OFDMA_FEC_MOD_QAM64_LDPC_3Q_B_CODE	= 43,
+	OFDMA_FEC_MOD_QPSK_CC_OI_H			= 44,
+	OFDMA_FEC_MOD_QPSK_CC_OI_3Q			= 45,
+	OFDMA_FEC_MOD_QAM16_CC_OI_H			= 46,
+	OFDMA_FEC_MOD_QAM16_CC_OI_3Q		= 47,
+	OFDMA_FEC_MOD_QAM64_CC_OI_2O3		= 48,
+	OFDMA_FEC_MOD_QAM64_CC_OI_3Q		= 49,
+	OFDMA_FEC_MOD_QPSK_LDPC_5O6			= 50,
+	OFDMA_FEC_MOD_QAM16_LDPC_5O6		= 51,
+	OFDMA_FEC_MOD_QAM64_LDPC_5O6		= 52,
+	OFDMA_FEC_MODE_CNT,
+} FEC_MOD;
+
+typedef enum _REPETITION_CODE
+{
+	REPETITION_CODING_NOT_SPECIFIED		= 0,
+	NO_REPETITION_CODING				= 1,
+	REPETITION_CODING_OF_2_USED			= 2,
+	REPETITION_CODING_OF_4_USED			= 3,
+	REPETITION_CODING_OF_6_USED			= 4,
+	REPETITION_CODING_CNT,
+} REPETITION_CODE;
+
+typedef enum _MIMO_TYPE
+{
+	MINO_TYPE_NOT_SPEC					= 0,
+	MINO_TYPE2_ANT_STC_MATRIX_A			= 1,
+	MINO_TYPE2_ANT_STC_MATRIX_B_VC		= 2,
+	/*
+	MINO_TYPE2_ANT_STC_MATRIX_B_HC		= 3,
+	MINO_TYPE4_ANT_STC_MATRIX_A			= 4,
+	MINO_TYPE4_ANT_STC_MATRIX_B_VC		= 5,
+	MINO_TYPE4_ANT_STC_MATRIX_B_HC		= 6,
+	MINO_TYPE4_ANT_STC_MATRIX_C_VC		= 7,
+	MINO_TYPE4_ANT_STC_MATRIX_C_HC		= 8,
+	MINO_TYPE3_ANT_STC_MATRIX_A			= 9,
+	MINO_TYPE3_ANT_STC_MATRIX_B			= 10,
+	MINO_TYPE3_ANT_STC_MATRIX_C_VC		= 11,
+	MINO_TYPE3_ANT_STC_MATRIX_C_HC		= 12,
+	MIMO_NOT_USD						= 13,
+	*/
+	MIMO_TYPE_CNT,
+} MIMO_TYPE;
+
+typedef struct _GCT_API_MAC_PHY_MAC_BASIC {
+	u32	frame_number;
+	u32	fch;
+	u16	ttg;
+	u16	rtg;
+	u8	num_dl_symbol;
+	u8	num_ul_symbol;
+	u8	current_pi;	/*PreambleIndex*/
+	u8	previous_pi;	/*PreambleIndex*/
+	u8	ul_perm_base;
+	u8	mac_state;
+	u8	bsid[6];
+	s32	ul_time;
+	u32	frequency;
+	u16	bandwidth;
+	u16	pad;	// padding
+	u32	time_active;
+	u32	time_sleep;
+	u32	time_idle;
+	u16	basic_cid;
+	u16	primary_cid;
+} GCT_API_MAC_PHY_MAC_BASIC, *GCT_API_MAC_PHY_MAC_BASIC_P;
+
+typedef struct _GCT_API_MAC_PHY_MCS {
+struct struct_mac_phy_mcs_s {
+		u32 num_burst;
+		u32 num_burst_error;
+		u32 len_pdu;
+		u32 num_pdu;
+	} dl[OFDMA_FEC_MODE_CNT][REPETITION_CODING_CNT][MIMO_TYPE_CNT], ul[OFDMA_FEC_MODE_CNT][REPETITION_CODING_CNT][MIMO_TYPE_CNT];
+
+	bool dl_used[OFDMA_FEC_MODE_CNT][REPETITION_CODING_CNT][MIMO_TYPE_CNT];
+	bool ul_used[OFDMA_FEC_MODE_CNT][REPETITION_CODING_CNT][MIMO_TYPE_CNT];
+} GCT_API_MAC_PHY_MCS, *GCT_API_MAC_PHY_MCS_P;
+
+typedef struct _GCT_API_MAC_PHY_CINR_RSSI {
+	s8	cinr_mean;
+	s8	cinr_std_dev;
+	s8	rssi_mean;
+	s8	rssi_std_dev;
+	s8	cinr_a_mean;
+	s8	cinr_b_mean;
+	s8	cinr_main;
+	s8	cinr_diversity;
+	s8	rssi_main;
+	s8	rssi_diversity;
+	s8	preamble_cinr_reuse3;
+	s8	preamble_cinr_reuse1;
+} GCT_API_MAC_PHY_CINR_RSSI, *GCT_API_MAC_PHY_CINR_RSSI_P;
+
+typedef enum _FUMO_RESULT {
+	FUMO_SUCCESSFUL = 200, /*The Request has Succeeded*/
+	FUMO_SUCCESSFUL_VENDOR_SPEC = 250, /*250 -299 Vendor Specified Successful Operation
+										with Vendor Specified ResultCode*/
+	FUMO_MNGMT_CLIENT_ERR = 400, /*Management Client error .
+									based on User or Device behavior*/
+	FUMO_USER_CANCELLED = 401, /*User chose not to accept the operation when prompted*/
+	FUMO_CORRUPTED_FW_UPDATE = 402, /*Corrupted firmware update package,
+									did not store correctly.*/
+	FUMO_DEVICE_MISMATCH = 403, /*Firmware Update Package. Device Mismatch*/
+	FUMO_PKG_VALIDATION_ERR = 404, /*Package Validation Failure to positively validate
+									digital signature of firmware update package*/
+	FUMO_PKG_NOT_ACCEPTABLE_FW = 405, /*Firmware Update Package is Not Acceptable*/
+	FUMO_ALTERNATE_DL_AUTH_ERR = 406, /*Authentication was Required but Authentication
+						Failure was encountered when downloading Firmware Update Package*/
+	FUMO_ALTERNATE_DL_REQ_TIMEOUT = 407, /*Client has encountered a time-out
+										when downloading Firmware Update Package*/
+	FUMO_NOT_IMPLEMENTED = 408, /*The device does not support the requested operation.*/
+	FUMO_UNDEFINED_ERR = 409, /*Indicates failure not defined by any other error code*/
+	FUMO_FW_UPDATE_FAILED = 410, /*Firmware Update operation failed in device*/
+	FUMO_MALFORMED_OR_BAD_URL = 411, /*The URL provided for alternate download is bad*/
+	FUMO_ALT_DL_SERV_UNAVAILABLE = 412, /*The Alternate Download Server is 
+										Unavailable or Does not Respond*/
+	FUMO_CLIENT_ERR = 450, /*450-499: Client Error encountered for Operation with 
+							Vendor Specified ResultCode*/
+	FUMO_ALT_DL_SERV_ERR = 500, /*Alternate Download Server Error Encountered*/
+	FUMO_DL_OUT_OF_MEM = 501, /*Download fails due to device is out of memory
+								The download fails due insufficient memory in the device
+								to save the firmware update package.*/
+	FUMO_UPDATE_OUT_OF_MEM = 502, /*Firmware update fails due to device out of memory
+				The update fails because there isn¡¯t sufficient memory to update the device.*/
+	FUMO_DL_NETWORK_ERR = 503, /*Download fails due to network issues
+								The download fails due to network/transport level errors*/
+	FUMO_ALT_DL_SERV_ERR_VENDOR_SPEC = 550, /*550-599: Alternate Download Server Error.
+								Vendor Specified
+								Alternate Download Server Error encountered for Operation
+								with Vendor Specified ResultCode*/
+
+	FUMO_RESULT_END
+} FUMO_RESULT;
+
+#define GAPI_LOG_LEVEL_IS_FILE(level)		((level)>4)
+#define GAPI_LOG_FLUSH_LEVEL		10
+
+typedef void (*GIndRcvHCIPacket) (GDEV_ID_P pID, char *szBuf, int nBufSize);
+typedef void (*GIndPowerModeChange) (GDEV_ID_P pID, GCT_API_POWER_MODE nPowerMode);
+typedef void (*GIndDeviceStatusUpdate)(GDEV_ID_P pID,
+				WIMAX_API_DEVICE_STATUS deviceStatus,
+				WIMAX_API_STATUS_REASON statusReason,
+				WIMAX_API_CONNECTION_PROGRESS_INFO connectionProgressInfo);
+typedef void (*GIndDeviceInsertRemove)(GDEV_ID_P pID, BOOL cardPresence);
+typedef void (*GIndControlPowerManagement)(GDEV_ID_P pID, WIMAX_API_RF_STATE powerState);
+typedef void (*GIndConnectToNetwork) (GDEV_ID_P pID,
+				WIMAX_API_NETWORK_CONNECTION_RESP networkConnectionResponse);
+typedef void (*GIndDisconnectFromNetwork) (GDEV_ID_P pID,
+				WIMAX_API_NETWORK_CONNECTION_RESP networkDisconnectResponse);
+typedef void (*GIndNetworkSearchWideScan) (GDEV_ID_P pID, WIMAX_API_NSP_INFO_P pNspList,
+				UINT32 listSize);
+typedef void (*GIndProvisioningOperation) (GDEV_ID_P pID, 
+				WIMAX_API_PROV_OPERATION provisioningOperation,
+				WIMAX_API_CONTACT_TYPE contactType);
+typedef void (*GIndPackageUpdate) (GDEV_ID_P pID, WIMAX_API_PACK_UPDATE packageUpdate);
+typedef void (*GIndNotification) (GDEV_ID_P pID, GCT_API_NOTI_CATEGORY nCategory,
+				GCT_API_NOTI_TYPE nType, int nBufSize, char *szBuf);
+
+#if defined(CONFIG_ENABLE_SERVICE_FLOW)
+typedef void (*GIndNotiServiceFlow)(GDEV_ID_P pID, WIMAX_SF_EVENT_P pSfEvent);
+#endif // CONFIG_ENABLE_SERVICE_FLOW
+#endif
diff --git a/sdk/global.h b/sdk/global.h
new file mode 100644
index 0000000..46fb52c
--- /dev/null
+++ b/sdk/global.h
@@ -0,0 +1,125 @@
+// 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.
+
+#if !defined(GLOBAL_H_20080709)
+#define GLOBAL_H_20080709
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
+#include <linux/types.h>
+#endif
+#include <linux/if_packet.h>
+#include <assert.h>
+#include <pthread.h>
+#include <netinet/in.h>
+
+#include "list.h"
+
+#if !defined(TRUE)
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#if !defined(TRUE)
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#if !defined(SDK_TYPEDEF)
+#define SDK_TYPEDEF
+typedef char 				bool;
+typedef unsigned char		u8;
+typedef unsigned short		u16;
+typedef unsigned int		u32;
+typedef unsigned long long	u64;
+typedef	signed char			s8;
+typedef signed short		s16;
+typedef int				s32;
+typedef long long			s64;
+#if 1
+typedef wchar_t				uchar;
+#else
+typedef unsigned short		uchar;
+#endif
+#endif
+
+typedef struct buf_s {
+	void	*buf;
+	int		size;
+
+} buf_t;
+
+inline static void bufset(buf_t *dst, buf_t *src)
+{
+	if (src) {
+		dst->buf = src->buf;
+		dst->size = src->size;
+	}
+	else {
+		dst->buf = NULL;
+		dst->size = 0;
+	}
+}
+
+typedef void (*void_func_t) (void);
+
+#define STR(s)		#s
+
+#define B2H(x)		ntohs(x)
+#define H2B(x)		htons(x)
+#define DB2H(x)		ntohl(x)
+#define DH2B(x)		htonl(x)
+
+#define U82U16(b)	((((u16)((u8*)b)[0])<<8)|((u16)((u8*)b)[1]))
+#define U82U24(b)	((((u32)((u8*)b)[0])<<16)|(((u32)((u8*)b)[1])<<8)|((u32)((u8*)b)[2]))
+#define U82U32(b)	(((u32)U82U16(b)<<16)|(u32)U82U16((u8*)(b)+2))
+#define U162U8(b,v)	((((u8*)b)[0])=((u16)(v)>>8),(((u8*)b)[1])=(u8)((u16)(v)))
+#define U242U8(b,v)	((((u8*)b)[0])=(u8)((u32)(v)>>16),(((u8*)b)[1])=(u8)((u32)(v)>>8),\
+						(((u8*)b)[2])=(u8)((u32)(v)))
+#define U322U8(b,v)	(U162U8((u8*)(b)+2, v), U162U8(b, (u32)v>>16))
+
+#define set_msb(x32, x8)	(x32 = ((u32)x32 & 0x00ffffff) | ((u32)x8<<24))
+#define get_msb(x32)		((u8)((u32)x32>>24))
+
+#define IS_BIG_ENDIAN()	(B2H(0x1122)==0x1122)
+
+
+#define MAC_FORMAT_STR		"%02X%02X%02X%02X%02X%02X"
+#define MAC_INPUT_STR(m)		((u8*)m)[0],((u8*)m)[1],((u8*)m)[2]\
+								,((u8*)m)[3],((u8*)m)[4],((u8*)m)[5]
+
+#define sdk_malloc(s)	malloc(s)
+#define sdk_free(b)		free(b)
+
+#ifndef offsetof
+#define	offsetof(type, field)	((int)(&((type*)0)->field))
+#endif
+
+#define rangeof(type, start, end)	(offsetof(type, end)-offsetof(type, start)\
+									+sizeof(((type*)0)->end))
+
+#define numof_array(arr)	(sizeof(arr)/sizeof(arr[0]))
+
+#define THREAD_EXIT_MSG	((void *) -1)
+
+//#define SDK_TEST
+#endif
diff --git a/sdk/handle.c b/sdk/handle.c
new file mode 100644
index 0000000..c3a1086
--- /dev/null
+++ b/sdk/handle.c
@@ -0,0 +1,111 @@
+// 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 <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include "error.h"
+#include "handle.h"
+#include "sdk.h"
+#include "wimax.h"
+#include "device.h"
+#include "log.h"
+
+
+pthread_mutex_t		api_handle_lock;
+struct list_head	api_handle_list;
+
+void hand_init(void)
+{
+	INIT_LIST_HEAD(&api_handle_list);
+	pthread_mutex_init(&api_handle_lock, NULL);
+}
+
+void hand_deinit(void)
+{
+	struct list_head *head = &api_handle_list;
+	api_hand_t *handle, *tmp;
+
+	pthread_mutex_lock(&api_handle_lock);
+	list_for_each_entry_safe(handle, tmp, head, list) {
+		list_del(&handle->list);
+		if (handle->api)
+			sdk_free(handle->api);
+		sdk_free(handle);
+	}
+	pthread_mutex_unlock(&api_handle_lock);
+	pthread_mutex_destroy(&api_handle_lock);
+}
+
+api_hand_t *hand_alloc_api(void)
+{
+	struct list_head *head = hand_get_api_handle_list();
+	api_hand_t *handle;
+
+	handle = (api_hand_t *) sdk_malloc(sizeof(api_hand_t));
+	assert(handle != NULL);
+	memset(handle, 0, sizeof(api_hand_t));
+
+	handle->struct_size = sizeof(api_hand_t);
+	pthread_mutex_lock(&api_handle_lock);
+	list_add(&handle->list, head);
+	pthread_mutex_unlock(&api_handle_lock);
+
+	return handle;
+}
+
+int hand_free_api(api_hand_t *handle)
+{
+	pthread_mutex_lock(&api_handle_lock);
+	list_del(&handle->list);
+	pthread_mutex_unlock(&api_handle_lock);
+	sdk_free(handle);
+
+	return 0;
+}
+
+dev_hand_t *hand_alloc_dev(int dev_idx)
+{
+	device_t *dev;
+	dev_hand_t *handle;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return NULL;
+
+	handle = (dev_hand_t *) sdk_malloc(sizeof(dev_hand_t));
+	assert(handle != NULL);
+	memset(handle, 0, sizeof(dev_hand_t));
+	handle->dev_idx = dev_idx;
+	handle->struct_size = sizeof(dev_hand_t);
+
+	dm_put_dev(dev_idx);
+	return handle;
+}
+
+int hand_free_dev(dev_hand_t *handle)
+{
+	if (handle == NULL) {
+		xprintf(SDK_ERR, "handle is NULL\n");
+		return sdk_set_errno(ERR_INVALID);
+	}
+
+	if (handle->struct_size != sizeof(dev_hand_t)) {
+		xprintf(SDK_ERR, "handle->struct_size(0x%08X!=0x%08X) is invalid\n", 
+			handle->struct_size, sizeof(dev_hand_t));
+		return sdk_set_errno(ERR_INVALID);
+	}
+
+	sdk_free(handle);
+	return 0;
+}
+
diff --git a/sdk/handle.h b/sdk/handle.h
new file mode 100644
index 0000000..c29eb06
--- /dev/null
+++ b/sdk/handle.h
@@ -0,0 +1,46 @@
+// 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.
+
+#if !defined(HANDLE_H_20080715)
+#define HANDLE_H_20080715
+#include "global.h"
+#include <pthread.h>
+
+#if !defined(MAX_DEVICE)
+#define MAX_DEVICE 256
+#endif
+
+typedef struct dev_hand_s {
+	u32 struct_size;
+	struct api_hand_s *api;
+	int dev_idx;
+
+} dev_hand_t;
+
+typedef struct api_hand_s {
+	u32 struct_size;
+	struct list_head list;
+	struct sdk_internal_s *sdk;
+
+	void *api;
+
+} api_hand_t;
+
+extern pthread_mutex_t		api_handle_lock;
+extern struct list_head		api_handle_list;
+
+static __inline struct list_head *hand_get_api_handle_list(void)
+{
+	return &api_handle_list;
+}
+
+void hand_init(void);
+void hand_deinit(void);
+
+api_hand_t *hand_alloc_api(void);
+int hand_free_api(api_hand_t *handle);
+
+dev_hand_t *hand_alloc_dev(int dev_idx);
+int hand_free_dev(dev_hand_t *handle);
+#endif
diff --git a/sdk/hci.c b/sdk/hci.c
new file mode 100644
index 0000000..283ae27
--- /dev/null
+++ b/sdk/hci.c
@@ -0,0 +1,952 @@
+// 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 <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <net/if_arp.h>
+#include <unistd.h>
+#include <net/if.h>
+#include <assert.h>
+
+#include "error.h"
+#include "sdk.h"
+#include "device.h"
+#include "io.h"
+#include "hci.h"
+#include "wimax.h"
+#include "nds.h"
+#include "log.h"
+
+#if defined(TRANSPORT_TEST)
+static int dl_transport_handler(int dev_idx, char *buf, int len);
+static int start_transport_test(int dev_idx, char *buf, int len);
+#endif
+
+int hci_get_tlv(u8 *buf, u8 *T, u16 *L, u8 **V)
+{
+	int next_pos;
+
+	*T = buf[0];
+	if (buf[1] == 0x82) {
+		*L = U82U16(&buf[2]);
+		next_pos = 1/*type*/+3/*len*/;
+	}
+	else {
+		*L = buf[1];
+		next_pos = 1/*type*/+1/*len*/;
+	}
+	*V = &buf[next_pos];
+
+	next_pos += *L/*length of val*/;
+	return next_pos;
+}
+
+int hci_set_tlv(u8 *buf, u8 T, u16 L, u8 *V)
+{
+	int pos = 0;
+
+	buf[pos++] = T;
+
+	if (L < 0x80) {
+		buf[pos++] = L;
+	}
+	else {
+		buf[pos++] = 0x82;
+		U162U8(&buf[pos], L);
+		pos+=2;
+	}
+
+	memcpy(&buf[pos], V, L);
+	pos += L;
+
+	return pos;
+}
+
+int hci_send(int dev_idx, u16 cmd, u8 *data, int len)
+{
+	u16 buf[HCI_MAX_PACKET / sizeof(u16)];
+	u8 *data_buf = (u8 *)&buf[0] + HCI_HEADER_SIZE;
+	int ret;
+
+	xfunc_in("cmd=0x%04x, len=%d", cmd, len);
+
+	buf[0] = H2B(cmd);
+	buf[1] = H2B(len);
+
+	memcpy(data_buf, data, len);
+
+	ret = io_send(dev_idx, buf, len+HCI_HEADER_SIZE);
+	if (ret == len+HCI_HEADER_SIZE)
+		ret = len;
+	else if (ret >= 0) {
+		xprintf(SDK_ERR, "Wrong sent size=%d\n", ret);
+		ret = -1;
+	}
+
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+#define DESTROYED_HCI		-2
+
+int hci_send_wait(int dev_idx, u16 s_cmd, u8 *data, int plen, 
+	u16 w_cmd, void *buf, int buf_len, int chk_len, u32 flag, int timeout)
+{
+	#define timeval2timespec(tv,ts)	\
+		((ts)->tv_sec = (tv)->tv_sec, (ts)->tv_nsec = (tv)->tv_usec * 1000)
+	device_t *dev;
+	hci_req_t hcir;
+	struct list_head *head;
+	struct timeval tv;
+	struct timespec ts;
+	int ret;
+
+	xfunc_in("cmd=0x%04x", s_cmd);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	pthread_mutex_lock(&dev->hci_wait_signal);
+
+	if ((ret = hci_send(dev_idx, s_cmd, data, plen)) < 0)
+		goto out;
+
+	INIT_LIST_HEAD(&hcir.list);
+	hcir.cmd_evt = w_cmd;
+	hcir.buf = buf;
+	hcir.len = buf_len;
+	hcir.chk_len = chk_len;
+	hcir.flag = flag;
+
+	pthread_cond_init(&hcir.cond, NULL);
+
+	if (timeout) {
+		gettimeofday(&tv, NULL);
+		timeval2timespec(&tv, &ts);
+		ts.tv_sec += timeout;
+	}
+
+	head = &dev->hci_wait_list;
+	list_add_tail(&hcir.list, head);
+
+	xprintf(SDK_DBG, "Wait cmd(0x%04x)\n", hcir.cmd_evt);
+	ret = pthread_cond_timedwait(&hcir.cond, &dev->hci_wait_signal, &ts);
+	if (ret == ETIMEDOUT) {
+		list_del(&hcir.list);
+		if (w_cmd != WIMAX_ARM_CAPABILITY_RESULT)
+			xprintf(SDK_ERR, "hci_send_wait(0x%04X TIMEOUT(%d)\n", w_cmd, timeout);
+		ret = - ETIMEDOUT;
+	}
+	else {
+		ret = hcir.len;
+		if (ret == DESTROYED_HCI)
+			xprintf(SDK_NOTICE, "HCI(%04x) has been destroyed\n", w_cmd);
+	}
+
+out:
+	pthread_mutex_unlock(&dev->hci_wait_signal);
+	xfunc_out("ret=%d", ret);
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+int hci_wait(int dev_idx, u16 cmd_evt,
+			void *buf, int len, int chk_len, u32 flag, int timeout)
+{
+	#define timeval2timespec(tv,ts)	\
+		((ts)->tv_sec = (tv)->tv_sec, (ts)->tv_nsec = (tv)->tv_usec * 1000)
+	device_t *dev;
+	hci_req_t hcir;
+	struct list_head *head;
+	struct timeval tv;
+	struct timespec ts;
+	int ret;
+
+	xfunc_in("cmd=0x%04x", cmd_evt);
+	
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	INIT_LIST_HEAD(&hcir.list);
+	hcir.cmd_evt = cmd_evt;
+	hcir.buf = buf;
+	hcir.len = len;
+	hcir.chk_len = chk_len;
+	hcir.flag = flag;
+
+	pthread_cond_init(&hcir.cond, NULL);
+
+	if (timeout) {
+		gettimeofday(&tv, NULL);
+		timeval2timespec(&tv, &ts);
+		ts.tv_sec += timeout;
+	}
+
+	pthread_mutex_lock(&dev->hci_wait_signal);
+	head = &dev->hci_wait_list;
+	list_add_tail(&hcir.list, head);
+
+	ret = pthread_cond_timedwait(&hcir.cond, &dev->hci_wait_signal, &ts);
+	if (ret == ETIMEDOUT) {
+		list_del(&hcir.list);
+		xprintf(SDK_ERR, "hci_wait(0x%04X TIMEOUT(%d)\n", cmd_evt, timeout);
+		ret = - 1;
+	}
+	else {
+		ret = hcir.len;
+		if (ret == DESTROYED_HCI)
+			xprintf(SDK_NOTICE, "HCI(%04x) has been destroyed\n", cmd_evt);
+	}
+
+	pthread_mutex_unlock(&dev->hci_wait_signal);
+	xfunc_out("ret=%d", ret);
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+int hci_destroy_resp(int dev_idx)
+{
+	device_t *dev;
+	struct list_head *head;
+	hci_req_t *hcir, *tmp;
+	int ret = 0;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	head = &dev->hci_wait_list;
+
+	pthread_mutex_lock(&dev->hci_wait_signal);
+	list_for_each_entry_safe(hcir, tmp, head, list) {
+		hcir->len = DESTROYED_HCI;
+		pthread_cond_signal(&hcir->cond);
+		ret++;
+	}
+	pthread_mutex_unlock(&dev->hci_wait_signal);
+
+	xfunc_out("ret=%d", ret);
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+static int hci_unsolicited_getinfo_result(int dev_idx, u8 *buf, int len)
+{
+	device_t *dev;
+	u8 T, *V;
+	u16 L;
+	int pos = 0, ret = 0;
+
+	xfunc_in();
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+	while (pos < len) {
+		pos += hci_get_tlv(&buf[pos], &T, &L, &V);
+		switch (T) {
+			case TLV_T(T_REALM):
+				memcpy(dev->wimax->dev_info.eapp.visited_realm, V, L);
+				dev->wimax->dev_info.eapp.visited_realm[L] = 0;
+				xprintf(SDK_NOTICE, "Network Realm=%s\n",
+					dev->wimax->dev_info.eapp.visited_realm);
+				break;
+			case TLV_T(T_BSID):
+				xprintf(SDK_INFO, "BSID=%06X:%06X\n", U82U24(&V[0]), U82U24(&V[3]));
+				break;
+			case TLV_T(T_RSSI):
+				xprintf(SDK_INFO, "T_RSSI(%d)\n", wm_convert_rssi(*V));
+				break;
+			default:
+				xprintf(SDK_DBG, "Unknown Type=0x%02x\n", T);
+				ret = -1;
+				goto out;
+		}
+	}
+out:
+	dm_put_dev(dev_idx);
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+static bool hci_receive_resp(int dev_idx, u16 cmd_evt, u8 *buf, int len)
+{
+	device_t *dev;
+	struct list_head *head;
+	hci_req_t *hcir, *tmp;
+	int handled_cnt = 0;
+
+	xfunc_in("cmd=0x%04x", cmd_evt);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	head = &dev->hci_wait_list;
+
+	pthread_mutex_lock(&dev->hci_wait_signal);
+	list_for_each_entry_safe(hcir, tmp, head, list) {
+		if (cmd_evt == hcir->cmd_evt) {
+			if (hcir->chk_len) {
+				if (memcmp(hcir->buf, buf, hcir->chk_len)) {
+					xprintf_hex(SDK_DBG, "data to check is not matched: 1",
+						buf, hcir->chk_len);
+					xprintf_hex(SDK_DBG, "data to check is not matched: 2",
+						hcir->buf, hcir->chk_len);
+					continue;
+				}
+			}
+			if (hcir->buf && hcir->len) {
+				assert(hcir->len >= len);
+				memcpy(hcir->buf, buf, len);
+				hcir->len = len;
+			}
+			else
+				hcir->len = 0;
+
+			list_del(&hcir->list);
+			xprintf(SDK_DBG, "Send signal(0x%04x(%d): %02x, %02x)\n",
+				hcir->cmd_evt, hcir->len, buf[0], buf[1]);
+			pthread_cond_signal(&hcir->cond);
+			if (hcir->flag & HCI_INDICATION)
+				handled_cnt = -1;
+			if (handled_cnt >=0)
+				handled_cnt++;
+		}
+	}
+	pthread_mutex_unlock(&dev->hci_wait_signal);
+
+	xfunc_out("handled_cnt=%d", handled_cnt);
+	dm_put_dev(dev_idx);
+	return handled_cnt <= 0 ? FALSE : TRUE;
+}
+
+static int hci_receive_ind(int dev_idx, void *buf, int len)
+{
+	device_t *dev;
+	struct hci *hci = (struct hci *) buf;
+	u16 cmd_evt, cmd_len, category;
+	u8 *data_buf = (u8 *) hci->data;
+	bool should_bypass = FALSE;
+	int ret = -1;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+	
+	cmd_evt = B2H(hci->cmd_evt);
+	cmd_len = B2H(hci->length);
+	category = (cmd_evt >> 8) & 0xf;
+
+	xfunc_in("0x%04x, %d, %02x, %02x, %02x, %02x", cmd_evt, cmd_len,
+		hci->data[0], hci->data[1], hci->data[2], hci->data[3]);
+
+	if (len > HCI_MAX_PACKET || (len-HCI_HEADER_SIZE) < cmd_len) {
+		xprintf(SDK_ERR, "[%d] Invalid packet length(%d) (%d,%d)\n",
+			dev_idx, len, (len-HCI_HEADER_SIZE), cmd_len);
+		goto out;
+	}
+
+	if (hci_receive_resp(dev_idx, cmd_evt, hci->data, cmd_len))
+		goto out;
+
+	if (category == 3)
+		should_bypass = TRUE;
+
+	if (!dev->wimax) {
+		xprintf(SDK_NOTICE, "Device has been closed!\n");
+		goto out;
+	}
+
+	/*The following is a indication.*/
+	switch (cmd_evt) {
+		case WIMAX_FSM_UPDATE:
+			ret = sdk_ind_status_update(dev_idx, data_buf, cmd_len);
+			break;
+		case WIMAX_IF_UPDOWN:
+			ret = sdk_ind_if_updown(dev_idx, data_buf, cmd_len);
+			break;
+		case WIMAX_RADIO_STATE_IND:
+			ret = sdk_ind_rf_state(dev_idx, data_buf, cmd_len);
+			break;
+		case WIMAX_SCAN_RESULT:
+			ret = nds_update_scan_result(dev_idx, data_buf, cmd_len);
+			break;
+		case WIMAX_SCAN_COMPLETE:
+			ret = sdk_ind_event(dev_idx, NM_ScanComplete);
+			break;
+		case WIMAX_CONNECT_START:
+			ret = sdk_ind_event(dev_idx, NC_ConnectStart);
+			break;
+		case WIMAX_CONNECT_COMPLETE:
+			ret = nds_connect_complete(dev_idx, data_buf, cmd_len);
+			break;
+		case WIMAX_ASSOC_START:
+			ret = nds_associate_start(dev_idx, data_buf, cmd_len);
+			break;
+		case WIMAX_ASSOC_COMPLETE:
+			ret = nds_associate_complete(dev_idx, data_buf, cmd_len);
+			break;
+		case WIMAX_DISCONN_IND:
+			ret = nds_disconnect_ind(dev_idx, data_buf, cmd_len);
+			ret |= sdk_ind_recv_hci_pkt(dev_idx, buf, len);
+			break;
+		case WIMAX_ENTRY_IND:
+			ret = nds_connection_stage(dev_idx, data_buf, cmd_len);
+			break;
+		case WIMAX_HO_START:
+			ret = nds_ho_start(dev_idx, data_buf, cmd_len);
+			break;
+		case WIMAX_HO_COMPLETE:
+			ret = nds_ho_complete(dev_idx, data_buf, cmd_len);
+			break;
+		case WIMAX_IP_RENEW_IND:
+			should_bypass = TRUE;
+			break;
+		case WIMAX_RX_EAP:
+				xprintf(SDK_ERR, "WIMAX_RX_EAP is NOT supported.\n", cmd_evt);
+			break;
+		case WIMAX_NOTIFICATION:
+			ret = wm_notification(dev_idx, (char *) data_buf, cmd_len);
+			should_bypass = FALSE;
+			break;
+		#if defined(TRANSPORT_TEST)
+		case WIMAX_START_TRANSPORT_TEST:
+			start_transport_test(dev_idx, (char *) data_buf, cmd_len);
+			should_bypass = FALSE;
+			break;
+		case WIMAX_DL_TRANSPORT_TEST:
+			dl_transport_handler(dev_idx, (char *) data_buf, cmd_len);
+			should_bypass = FALSE;
+			break;
+		#endif
+		case WIMAX_ARM_CAPABILITY_RESULT:
+			wm_report_capability(dev_idx, data_buf, cmd_len);
+			should_bypass = FALSE;
+			break;
+		case WIMAX_MODE_CHANGE:
+			ret = sdk_ind_power_mode_change(dev_idx, data_buf, cmd_len);
+			break;
+		case WIMAX_SF_IND:
+			ret = wm_ind_sf_mode(dev_idx, data_buf, cmd_len);
+			break;
+		case WIMAX_GET_INFO_RESULT:
+			ret = hci_unsolicited_getinfo_result(dev_idx, data_buf, cmd_len);
+			if (!ret)
+				break;
+		case WIMAX_FULL_REENTRY:
+			ret = wm_report_full_reentry(dev_idx, data_buf, cmd_len);
+			break;
+#if defined(CONFIG_ENABLE_SERVICE_FLOW)
+		case WIMAX_DSX_COMPLETE:
+			// Using original data
+			ret = sdk_sf_recv_dsx_complete(dev_idx, buf, len);
+			break;
+#endif // CONFIG_ENABLE_SERVICE_FLOW
+		default:
+			if (!should_bypass)
+				xprintf(SDK_INFO, "Unhandled HCI(0x%04x)\n", cmd_evt);
+			break;
+	}
+
+	if (should_bypass) {
+		xprintf(SDK_DBG, "Bypass HCI(0x%04x)\n", cmd_evt);
+		ret = sdk_ind_recv_hci_pkt(dev_idx, buf, len);
+	}
+out:
+	xfunc_out("ret=%d", ret);
+	dm_put_dev(dev_idx);
+
+	return ret;
+}
+
+bool hci_parse_lv(u8 *buf, u16 event, u8 T, u8 *L, u8 **V)
+{
+	u8 type;
+	u16 cmd_evt;
+
+	cmd_evt = B2H(*(u16 *)&buf[0]);
+
+	if (cmd_evt == event) {
+		type = buf[HCI_HEADER_SIZE];
+
+		if (T == type) {
+			*L = buf[HCI_HEADER_SIZE+1];
+			*V = &buf[HCI_HEADER_SIZE+2];
+			return TRUE;
+		}
+		else
+			xprintf(SDK_DBG, "receive another type(0x%02X!=0x%02X)\n", type, T);
+	}
+	else
+		xprintf(SDK_DBG, "receive another event(0x%04X!=0x%04X)\n", cmd_evt, event);
+
+	return FALSE;
+}
+
+int hci_req_getinfo(int dev_idx, u8 *buf, tlv_t *tlv, int cnt)
+{
+	u8 param[HCI_MAX_TLV];
+	int pos = 0, i;
+	int chk_len;
+	u8 T;
+	int ret = -1;
+
+	xfunc_in("dev=%d, cnt=%d", dev_idx, cnt);
+	assert(HCI_MAX_TLV >= cnt);
+
+	for (i = 0; i < cnt; i++)
+		param[i] = tlv[i].T;
+
+	buf[0] = tlv[0].T;
+	chk_len = 1;
+	ret = hci_send_wait(dev_idx, WIMAX_GET_INFO, param, cnt,
+		WIMAX_GET_INFO_RESULT, buf, HCI_MAX_PACKET, chk_len, 0, IO_TIMEOUT_SEC);
+	if (ret > cnt/*min. size*/) {
+		for (i = 0; i < cnt; i++) {
+			pos += hci_get_tlv(&buf[pos], &T, &tlv[i].L, &tlv[i].V);
+			if (T != tlv[i].T) {
+				xprintf_hex(SDK_ERR, "GET_INFO", buf, ret);
+				xprintf(SDK_ERR, "hci_get_tlv mismatch 0x%02X!=0x%02X\n", T, tlv[i].T);
+				ret = -1;
+				goto out;
+			}
+		}
+		ret = 0;
+	}
+	else if (ret >= 0){
+		xprintf(SDK_ERR, "hci_send_wait mismatch: %d<=%d\n", ret, cnt);
+		ret = -1;
+	}
+out:
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int hci_req_getinfo32(int dev_idx, u8 type, u32 *val)
+{
+	u8 buf[HCI_MAX_PACKET];
+	tlv_t tlv;
+	int ret;
+
+	xfunc_in();
+	
+	tlv.T = type;
+	ret = hci_req_getinfo(dev_idx, buf, &tlv, 1);
+	if (!ret) {
+		if (tlv.L == sizeof(u32)) {
+			memcpy(val, tlv.V, sizeof(u32));
+			*val = DB2H(*val);
+		}
+		else {
+			xprintf(SDK_ERR, "length mismatch(%d!=%d)\n", tlv.L, sizeof(u32));
+			ret = -1;
+		}
+	}
+
+	xfunc_out("ret=%d, *val=0x%08X", ret, *val);
+	return ret;
+}
+
+int hci_req_setinfo32(int dev_idx, u8 type, u32 val)
+{
+	u8 buf[HCI_MAX_PARAM];
+	u8 *pos = buf;
+	u8 T, *V;
+	u16 L;
+	int len, ret;
+
+	xfunc_in("val=%d", val);
+
+	val = DH2B(val);
+	T = type;
+	L = (u16) sizeof(u32);
+	V = (u8 *) &val;
+	pos += hci_set_tlv(pos, T, L, V);
+
+	len = pos - buf;
+	ret = hci_send(dev_idx, WIMAX_SET_INFO, buf, len);
+	if (len == ret)
+		ret = 0;
+	else {
+		xprintf(SDK_STD_ERR, "[%d] hci_send(%d!=%d)\n", dev_idx, len, ret);
+		ret = sdk_set_errno(ERR_STD);
+	}
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int hci_send_msg(int dev_idx, hci_msg_t *msg)
+{
+	msg_thr_t *hci_recvr = &sdk_mng.hci_recvr;
+
+	xfunc_in("%02x%02x", (u8)msg->buf[0], (u8)msg->buf[1]);
+
+	msg_send(&hci_recvr->msg_cb, dev_idx, msg);
+
+	xfunc_out();
+	return 0;
+}
+
+static void *hci_receiver_thread(void *data)
+{
+	msg_thr_t *hci_recvr = (msg_thr_t *) data;
+	hci_msg_t *msg;
+	int dev_idx;
+	char *buf;
+	int len;
+
+	xfunc_in();
+
+	while (1) {
+		xprintf(SDK_DBG, "[%d] In hci_receiver\n", dev_idx);
+		if (msg_recv(&hci_recvr->msg_cb, &dev_idx, (void **)&msg) < 0) {
+			xprintf(SDK_ERR, "hci msg_recv error\n");
+			break;
+		}
+
+		if (msg == THREAD_EXIT_MSG) {
+			xprintf(SDK_INFO, "%s thread exit...\n", __FUNCTION__);
+			break;
+		}
+
+		buf = msg->buf;
+		len = msg->len;
+		hci_receive_ind(dev_idx, buf, len);
+		sdk_free(msg);
+	}
+
+	msg_deinit(&hci_recvr->msg_cb);
+	xfunc_out();
+	return NULL;
+}
+
+int hci_receiver_create(msg_thr_t *hci_recvr)
+{	
+	xfunc_in();
+
+	msg_init(&hci_recvr->msg_cb);
+
+	pthread_create(&hci_recvr->thread, NULL, hci_receiver_thread, (void *)hci_recvr);
+
+	xfunc_out();
+	return 0;
+}
+
+int hci_receiver_delete(msg_thr_t *hci_recvr)
+{
+	pthread_t thread;
+
+	xfunc_in("thread=0x%08X", (int) hci_recvr->thread);
+
+	if ((thread = hci_recvr->thread)) {
+		hci_recvr->thread = (pthread_t) NULL;
+		msg_send(&hci_recvr->msg_cb, 0, THREAD_EXIT_MSG);
+		pthread_join(thread, NULL);
+	}
+
+	xfunc_out();
+	return 0;
+}
+
+#if defined(TRANSPORT_TEST)
+#define TYPE_NONE		0
+#define TYPE_DL			1
+#define TYPE_UL			2
+#define TYPE_LOOPBACK	3
+#define TYPE_BI_DIR		4
+#define TYPE_MAX		4
+
+#define PATTERN_ZERO_FILLED	0
+#define PATTERN_INCREMENTAL	1
+#define PATTERN_RANDOM		2
+#define PATTERN_MAX			2
+
+#define PACKETSIZE_MAX		1400
+
+
+typedef struct trans_test_s {
+	unsigned char type;
+	unsigned char pattern;
+	unsigned short outer_loop;
+	unsigned short inner_loop;
+	unsigned short packet_size;
+
+} __attribute__((packed)) trans_test_t;
+
+typedef struct trans_mng_s {
+	trans_test_t tt;
+
+	int mismatches;
+
+} trans_mng_t;
+
+typedef struct trans_packet_s {
+	unsigned short seq_nr;
+	unsigned char packet[0];	
+	
+} __attribute__((packed)) trans_packet_t;
+
+typedef struct trans_phase_s {
+	int outer_loop;
+	int inner_loop;
+
+} trans_phase_t;
+
+static trans_mng_t trans_mng;
+static trans_phase_t ul_phase;
+static trans_phase_t dl_phase;
+
+static char send_hci[HCI_MAX_PACKET] __attribute__((aligned(1024)));
+static unsigned char packet_data[HCI_MAX_PACKET];
+
+static void fill_incremental_buf(void *buf, int len, unsigned char start)
+{
+	unsigned char *p = buf;
+	int i;
+
+	for (i = 0; i < len; i++)
+		*p++ = start++;
+}
+
+static void fill_random_buf(void *buf, int len)
+{
+	unsigned short *p = (unsigned short *) buf;
+	unsigned char *bp = (unsigned char *) buf;
+	int slen = len / 2;
+	int i;
+
+	for (i = 0; i < slen; i++)
+		*p++ = rand();
+
+	if (len & 1)
+		bp[len-1] = rand();
+}
+
+static void init_send_hci(trans_mng_t *ptm)
+{
+	struct hci *hci;
+	trans_packet_t *data;
+	int len = ptm->tt.packet_size;
+	unsigned short length = sizeof(data->seq_nr) + len;
+
+	if (ptm->tt.type == TYPE_UL || ptm->tt.type == TYPE_LOOPBACK) {
+		hci = (struct hci *) send_hci;
+		data = (trans_packet_t *) hci->data;
+
+		hci->cmd_evt = H2B(WIMAX_UL_TRANSPORT_TEST);
+		hci->length = H2B(length);
+		if (ptm->tt.pattern == PATTERN_ZERO_FILLED)
+			memset(data->packet, 0, len);
+		else if (ptm->tt.pattern == PATTERN_INCREMENTAL)
+			fill_incremental_buf(packet_data, sizeof(packet_data), 0);
+		else if (ptm->tt.pattern == PATTERN_RANDOM)
+			fill_random_buf(packet_data, sizeof(packet_data));
+	}
+}
+
+static struct hci *get_hci_buf(trans_mng_t *ptm, unsigned char seq_nr)
+{
+	struct hci *hci = (struct hci *) send_hci;
+	trans_packet_t *data = (trans_packet_t *) hci->data;
+
+	if (ptm->tt.pattern == PATTERN_INCREMENTAL || ptm->tt.pattern == PATTERN_RANDOM)
+		memcpy(data->packet, &packet_data[seq_nr], ptm->tt.packet_size);
+
+	return hci;
+}
+
+static unsigned int elapsed_time_us(struct timeval *start)
+{
+	struct timeval tv, now;
+	unsigned int us;
+
+	gettimeofday(&now, NULL);
+
+	timersub(&now, start, &tv);
+
+	us = tv.tv_sec * 1000000 + tv.tv_usec;
+	return us;
+}
+
+static unsigned int get_throughput(trans_mng_t *ptm, unsigned int us)
+{
+	int loop = ptm->tt.inner_loop;
+	int packet_size = ptm->tt.packet_size;
+	unsigned int sent;
+	unsigned int bps;
+	double sec;
+
+	if (ptm->tt.type == TYPE_DL)
+		loop--;
+
+	sent = (HCI_HEADER_SIZE + sizeof(trans_packet_t) + packet_size)
+			* 8/*bits*/ *loop;
+
+	sec = (double)us / 1000000;
+	bps = sent / sec;
+	return bps;
+}
+
+static void print_throughput(const char *title, trans_mng_t *ptm, double bps)
+{
+	char str[1024], *p = str;
+	#define Kbits		(1024)
+	#define Mbits		(1024*Kbits)
+
+	if (bps > Mbits)
+		p += sprintf(p, "%s: %.2f Mbits", title, bps/Mbits);
+	else if (bps > Kbits)
+		p += sprintf(p, "%s: %.2f Kbits", title, bps/Kbits);
+	else
+		p += sprintf(p, "%s: %.2f bits", title, bps);
+
+	if (ptm->mismatches)
+		p += sprintf(p, ", mismatches=%d", ptm->mismatches);
+
+	xprintf(SDK_NOTICE, "%s\n", str);
+}
+
+static void report_throughput(trans_mng_t *ptm, char *name,
+								struct timeval *start, int index)
+{
+	char title[128];
+	unsigned int elapsed_us;
+	double bps;
+
+	elapsed_us = elapsed_time_us(start);
+	sprintf(title, "%d. %s(bps)", index, name);
+
+	bps = get_throughput(ptm, elapsed_us);
+
+	print_throughput(title, ptm, bps);
+}
+
+static void ul_transport_send(int dev_idx, trans_mng_t *ptm, int seq_nr)
+{
+	struct hci *hci;
+	trans_packet_t *data;
+	int len;
+
+	hci = get_hci_buf(ptm, seq_nr);
+	data = (trans_packet_t *) hci->data;
+	data->seq_nr = H2B(seq_nr);
+
+	len = B2H(hci->length);
+
+	io_send(dev_idx, hci, len+HCI_HEADER_SIZE);
+}
+
+static void ul_transport_test(int dev_idx, trans_mng_t *ptm)
+{
+	struct timeval start;
+	int i, j;
+
+	assert(ptm->tt.type == TYPE_UL);
+
+	for (i = 0; i < ptm->tt.outer_loop; i++) {
+		gettimeofday(&start, NULL);
+		for (j = 0; j < ptm->tt.inner_loop; j++)
+			ul_transport_send(dev_idx, ptm, j);
+		report_throughput(ptm, "UL", &start, i);
+		sleep(1);
+	}
+}
+
+static void loopback_test(int dev_idx, trans_mng_t *ptm)
+{
+	assert(ptm->tt.type == TYPE_LOOPBACK);
+
+	ul_transport_send(dev_idx, ptm, ul_phase.inner_loop);
+
+	if (++ul_phase.inner_loop == ptm->tt.inner_loop) {
+		ul_phase.inner_loop = 0;
+		ul_phase.outer_loop++;
+	}
+}
+
+static int dl_transport_handler(int dev_idx, char *buf, int len)
+{
+	trans_mng_t *ptm = &trans_mng;
+	trans_packet_t *data = (trans_packet_t *) buf;
+	static struct timeval start;
+	unsigned short seq_nr = B2H(data->seq_nr);
+
+	if (!dl_phase.inner_loop)
+		gettimeofday(&start, NULL);
+
+	if (ptm->tt.type == TYPE_LOOPBACK)
+		loopback_test(dev_idx, ptm);
+
+	if (seq_nr != dl_phase.inner_loop)
+		ptm->mismatches++;
+
+	if (++dl_phase.inner_loop == ptm->tt.inner_loop) {
+		if (ptm->tt.type == TYPE_LOOPBACK)
+			report_throughput(ptm, "Loopback", &start, dl_phase.outer_loop++);
+		else
+			report_throughput(ptm, "DL", &start, dl_phase.outer_loop++);
+		dl_phase.inner_loop = 0;
+	}
+	
+	return 0;
+}
+
+static int chk_trans_test_param(trans_mng_t *ptm)
+{
+	if (ptm->tt.type > TYPE_MAX)
+		return 0;
+	if (ptm->tt.pattern > PATTERN_MAX)
+		return 0;
+	if (!ptm->tt.inner_loop)
+		return 0;
+	if (ptm->tt.packet_size > PACKETSIZE_MAX)
+		return 0;
+
+	return 1;
+}
+
+static int start_transport_test(int dev_idx, char *buf, int len)
+{
+	trans_test_t *data = (trans_test_t *) buf;
+	trans_mng_t *ptm = &trans_mng;
+
+	memset(ptm, 0, sizeof(trans_mng_t));
+
+	ptm->tt.type = data->type;
+	ptm->tt.pattern = data->pattern;
+	ptm->tt.outer_loop = B2H(data->outer_loop);
+	ptm->tt.inner_loop = B2H(data->inner_loop);
+	ptm->tt.packet_size = B2H(data->packet_size);
+
+	xprintf(SDK_NOTICE, "transt %d %d %d %d %d\n",
+		ptm->tt.type, ptm->tt.pattern, ptm->tt.outer_loop, ptm->tt.inner_loop, ptm->tt.packet_size);
+
+	if (!chk_trans_test_param(ptm)) {
+		xprintf(SDK_ERR, "transport test param is invalid\n");
+		return -1;
+	}
+
+	memset(&dl_phase, 0, sizeof(dl_phase));
+	memset(&ul_phase, 0, sizeof(ul_phase));
+	init_send_hci(ptm);
+
+	switch (ptm->tt.type) {
+		case TYPE_UL:
+			ul_transport_test(dev_idx, ptm);
+			break;
+		case TYPE_LOOPBACK:
+			loopback_test(dev_idx, ptm);
+			break;
+	}
+	return 0;
+}
+#endif
diff --git a/sdk/hci.h b/sdk/hci.h
new file mode 100644
index 0000000..74f17ec
--- /dev/null
+++ b/sdk/hci.h
@@ -0,0 +1,520 @@
+// 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.
+
+#ifndef HCI_H_20080718
+#define HCI_H_20080718
+#include "global.h"
+#include "wimax.h"
+#include "msg.h"
+#include "msg_thread.h"
+
+
+#define HCI_HEADER_SIZE		4
+#define HCI_VALUE_OFFS		(HCI_HEADER_SIZE)
+#define HCI_MAX_PACKET		2048
+#define HCI_MAX_PARAM		(HCI_MAX_PACKET-HCI_HEADER_SIZE)
+#define HCI_MAX_TLV			32
+
+#define W_ERR_NOTI_CATE_EAP			0
+#define W_ERR_NOTI_TYPE_CODE		0
+#define W_ERR_NOTI_TYPE_TEXT		1
+
+/* CMD-EVT */
+
+/* Category 0 */
+#define WIMAX_RESET					0x0000
+#define WIMAX_SET_INFO				0x0001
+#define WIMAX_GET_INFO				0x0002
+#define WIMAX_GET_INFO_RESULT		0x8003
+#define WIMAX_RADIO_OFF				0x0004
+#define WIMAX_RADIO_ON				0x0006
+#define WIMAX_WIMAX_RESET			0x0007	/* Is this still here */
+
+/* Category 1 */
+#define WIMAX_NET_ENTRY				0x0100
+#define WIMAX_NET_DISCONN			0x0102
+#define WIMAX_ENTER_SLEEP			0x0103
+#define WIMAX_EXIT_SLEEP			0x0104
+#define WIMAX_ENTER_IDLE			0x0105
+#define WIMAX_EXIT_IDLE				0x0106
+#define WIMAX_MODE_CHANGE			0x8108
+	#define MODE_W_NULL				0x00
+	#define MODE_W_STANDBY			0x01
+	#define MODE_W_OUT_OF_ZONE		0x02
+	#define MODE_W_AWAKE			0x03
+	#define MODE_W_IDLE				0x04
+	#define MODE_W_SLEEP			0x05
+	#define MODE_W_WAIT				0x06
+#define WIMAX_HANDOVER				0x8109	/* obsolete */
+
+#define WIMAX_SCAN					0x010d
+#define WIMAX_SCAN_COMPLETE			0x810e
+#define WIMAX_SCAN_RESULT			0x810f
+
+#define WIMAX_CONNECT				0x0110
+#define WIMAX_CONNECT_START			0x8111
+#define WIMAX_CONNECT_COMPLETE		0x8112
+#define WIMAX_ASSOC_START			0x8113
+#define WIMAX_ASSOC_COMPLETE		0x8114
+#define WIMAX_DISCONN_IND			0x8115
+#define WIMAX_ENTRY_IND				0x8116
+#define WIMAX_HO_START				0x8117
+#define WIMAX_HO_COMPLETE			0x8118
+#define WIMAX_RADIO_STATE_IND		0x8119
+#define WIMAX_IP_RENEW_IND			0x811a
+
+#define WIMAX_DISCOVER_NSP			0x011d
+#define WIMAX_DISCOVER_NSP_RESULT	0x811e
+
+#define WIMAX_SCAN_CANCEL		0x0122
+#define WIMAX_AIRPLANE_MODE_IND	0x8123
+#define WIMAX_GET_AIRPLANE_MODE	0x0124
+#define WIMAX_FULL_REENTRY		0x8126
+
+/* Category 2 */
+#define WIMAX_TX_EAP				0x0200
+#define WIMAX_RX_EAP				0x8201
+#define WIMAX_TX_SDU				0x0202
+#define WIMAX_RX_SDU				0x8203
+
+/* Category 3 */
+#define WIMAX_DM_CMD				0x030a
+#define WIMAX_DM_RSP				0x830b
+
+#define WIMAX_CLI_CMD				0x030c
+#define WIMAX_CLI_RSP				0x830d
+
+#define WIMAX_DL_IMAGE				0x0310
+#define WIMAX_DL_IMAGE_STATUS		0x8311
+#define WIMAX_UL_IMAGE				0x0312
+#define WIMAX_UL_IMAGE_RESULT		0x8313
+#define WIMAX_UL_IMAGE_STATUS		0x0314
+
+#define WIMAX_NIC_CMD				0x0315
+#define WIMAX_IMAGE_CMD				0x0316
+#define WIMAX_IMAGE_CMD_STATUS		0x8317
+
+#define WIMAX_UICC_STATUS_IND		0x8318
+#define WIMAX_UICC_EAP_IND			0x8319
+#define WIMAX_UICC_CMD				0x031A
+	#define UICC_CMD_PIN_ENABLE		0x00
+	#define UICC_CMD_PIN_DISABLE	0x01
+	#define UICC_CMD_PIN_CHANGE		0x02
+	#define UICC_CMD_PIN_VERIFY		0x03
+	#define UICC_CMD_PUK_INPUT		0x04
+	#define UICC_CMD_UICC_STATUS	0x05
+	#define UICC_CMD_SUBSCRIBERID	0x06
+	#define UICC_CMD_ICCID			0x07
+	#define UICC_CMD_POWER_DOWN		0x08
+	#define UICC_CMD_POWER_UP		0x09
+#define WIMAX_UICC_CMD_RESULT		0x831B
+	#define UICC_CMD_RESULT_SUCCESS	0x00
+	#define UICC_CMD_RESULT_FAIL	0x01
+
+#define WIMAX_NOTIFICATION			0x831F
+#define WIMAX_ARM_CAPABILITY		0x0320
+#define WIMAX_ARM_CAPABILITY_RESULT	0x8321
+	#define W_CAPABILITY_ENC_XML	(1<<0)
+	#define W_CAPABILITY_E_EAP_TLS	(1<<1)
+	#define W_CAPABILITY_ODM		(1<<2)
+	#define W_CAPABILITY_E_EAP_AKA	(1<<3)
+	#define W_CAPABILITY_CAPL_INFO	(1<<4)
+
+#define WIMAX_DSX_REQUEST			0x0322
+#define WIMAX_DSX_COMPLETE			0x8323
+
+#define WIMAX_MODEM_REQUEST			0x0324
+	#define MODE_MODEM_REPORT		0
+	#define MODE_MODEM_REQUEST		1
+	#define W_PDU_STATISTIC			0x50
+	#define W_PHY_MAC_BASIC			0x51
+	#define W_POWER_CONTROL			0x52
+	#define W_PHY_BURST				0x53
+	#define W_PHY_MSC				0x54
+	#define W_PHY_ZONE				0x55
+	#define W_PHY_CINR_RSSI			0x56
+	#define W_TEMP_ADC				0x57
+	#define W_PHY_CTRL_CHANNEL		0x58
+	#define W_DL_SF_STATISTICS		0x59
+	#define W_UL_SF_STATISTICS		0x5a
+	#define W_HANDOVER				0x5b
+	#define W_NEIGHBOR_LIST			0x5c
+	#define W_HARQ_STATISTICS		0x5d
+	#define W_NETENTRY_STATISTICS	0x5e
+#define WIMAX_MODEM_REPORT			0x8325
+
+#define WIMAX_START_TRANSPORT_TEST	0x8330
+#define WIMAX_DL_TRANSPORT_TEST		0x8331
+#define WIMAX_UL_TRANSPORT_TEST		0x0332
+
+#define WIMAX_NOTIFICATION			0x831F
+
+#define WIMAX_MANAGER_MSG			0x8333
+#define WIMAX_SF_IND				0x8334
+	#define WIMAX_SF_ENABLE			1
+	#define WIMAX_SF_DISABLE		0
+
+#define WIMAX_SET_EAP_INFO			0x0340
+	#define W_NO_EAP				0
+	#define W_EAP_TLS				1
+	#define W_EAP_TTLS_MD5			2
+	#define W_EAP_TTLS_MSCHAPV2		3
+	#define W_EAP_TTLS_CHAP			4
+	#define W_EAP_AKA				5
+	#define IS_EAP_TLS(type)		((type)>=W_EAP_TLS && (type)<=W_EAP_TTLS_CHAP)
+	#define T_USER_ID				(1	| ( 1 << 16 ))
+	#define T_USER_PASSWD			(2	| ( 1 << 16 ))
+	#define T_ANONYMOUS_ID			(3	| ( 1 << 16 ))
+	#define T_PRIV_KEY_PASSWD		(4	| ( 1 << 16 ))
+	#define T_EAP_FORCE(x)			((x)+100)
+	#define T_CR801_MODE			(5	| ( 1 << 16 ))
+	#define T_DEV_CERT_NULL			(6	| ( 1 << 16 ))
+	#define T_CA_CERT_NULL			(7	| ( 1 << 16 ))
+	#define T_EAP_PARAM				(8	| ( 1 << 16 ))
+		#define V_PARAM_NV			0
+		#define V_PARAM_XML			1
+		#define V_PARAM_USER		2
+	#define T_EAP_DEBUG_ON			(9	| ( 1 << 16 ))
+	#define T_EAP_RESUMPTION_OFF	(10	| ( 1 << 16 ))
+	#define T_EAP_CW_DEV_CATEGORY	(11	| ( 1 << 16 ))
+	#define T_EAP_DECORATION		(12	| ( 0 << 16 ))
+	#define T_EAP_RAND_SEED			(13	| ( 4 << 16 ))
+	#define T_EAP_SESSIONTICKET_OFF	(14	| ( 1 << 16 ))
+#define WIMAX_SET_EAP_INFO_RESULT	0x8341
+#define WIMAX_GET_CERT_INFO			0x0342
+#define WIMAX_GET_CERT_INFO_RESULT	0x8343
+	#define LEVEL_CA_CERT			(1<<0)
+	#define LEVEL_CLIENT_CERT		(1<<1)
+	#define LEVEL_SERVER_CERT		(1<<2)
+	#define T_SUBJECT_CN			1
+	#define T_ISSUER_CN				2
+	#define T_EXPIRE_DATE			3
+#define WIMAX_DELETE_CERT			0x0344
+#define WIMAX_DELETE_CERT_RESULT	0x8345
+
+#define WIMAX_READ_FILE				0x0350
+#define WIMAX_WRITE_FILE			0x0351
+#define WIMAX_DELETE_FILE			0x0352
+#define WIMAX_FILE_RESULT			0x8354
+
+/* Download image type */
+#define DLIMG_KERNEL		0
+#define DLIMG_FS			1
+#define DLIMG_CFG			2
+#define DLIMG_CFG_RAM		3
+#define DLIMG_FS2			4
+#define DLIMG_CLR_CFG		5
+#define DLIMG_EAP_PARM		6
+#define DLIMG_BL_EEPROM		7
+#define DLIMG_BL_FLASH		8
+
+#define DLIMG_OMA_XML		0x100
+#define DLIMG_DEV_CERT		0x101
+#define DLIMG_CERT1_U		0x102
+#define DLIMG_CERT1_L		0x103
+#define DLIMG_CERT2_U		0x104
+#define DLIMG_EAP_PARAM		0x105
+#define DLIMG_CERT_BIG		0x106
+
+#define DLIMG_TLS_PCAP		0x200
+#define DLIMG_TLS_DEC		0x201
+#define DLIMG_TLS_DEV_CERT	0x202
+#define DLIMG_TLS_CA_CERT	0x203
+
+/* Category 0xF */
+#define WIMAX_FSM_UPDATE			0x8F01
+#define WIMAX_IF_UPDOWN				0x8F02
+	#define WIMAX_IF_UP				1
+	#define WIMAX_IF_DOWN			2
+
+/* WIMAX mode */
+#define W_NULL				0
+#define W_STANDBY			1
+#define W_OOZ				2
+#define W_AWAKE				3
+#define W_IDLE				4
+#define W_SLEEP				5
+#define W_WAIT				6
+
+#define W_NET_ENTRY_RNG		0x80
+#define W_NET_ENTRY_SBC		0x81
+#define W_NET_ENTRY_PKM		0x82
+#define W_NET_ENTRY_REG		0x83
+#define W_NET_ENTRY_DSX		0x84
+
+#define W_NET_ENTRY_RNG_FAIL	0x1100100
+#define W_NET_ENTRY_SBC_FAIL	0x1100200
+#define W_NET_ENTRY_PKM_FAIL	0x1102000
+#define W_NET_ENTRY_REG_FAIL	0x1103000
+#define W_NET_ENTRY_DSX_FAIL	0x1104000
+
+/* Scan Type */
+#define W_SCAN_ALL_CHANNEL				0
+#define W_SCAN_ALL_SUBSCRIPTION			1
+#define W_SCAN_SPECIFIED_SUBSCRIPTION	2
+
+/*
+ * TLV
+ *
+ * [31:31] indicates the type is composite.
+ * [30:16] is the length of the type. 0 length means length is variable.
+ * [15:0] is the actual type.
+ * 
+ */
+#define TLV_L(x)		(((x) >> 16) & 0xff)
+#define TLV_T(x)			((x) & 0xff)
+#define TLV_COMPOSITE(x)	((x) >> 31)
+
+/* GENERAL */
+#define T_MAC_ADDRESS			(0x00	| ( 6 << 16 ))
+#define T_BSID					(0x01 	| ( 6 << 16 ))
+#define T_MSK					(0x02	| ( 64 << 16 ))
+#define T_RSSI_THRSHLD			(0x03	| ( 1 << 16 ))
+#define T_FREQUENCY				(0x04	| ( 4 << 16 ))
+#define T_CONN_CS_TYPE			(0x05	| ( 1 << 16 ))
+#define T_HOST_IP_VER			(0x06	| ( 1 << 16 ))
+#define T_STBY_SCAN_INTERVAL	(0x07	| ( 4  << 16 ))
+#define T_OOZ_SCAN_INTERVAL		(0x08	| ( 4 << 16 ))
+#define T_IMEI					(0x09	| ( 8 << 16 ))
+#define T_PID					(0x0a	| ( 12 << 16 ))
+
+#define T_BOOTLOAD_VER			(0x19	| ( 4 << 16 ))
+#define T_CAPABILITY			(0x1a	| ( 4 << 16 ))
+#define T_RELEASE_NUMBER		(0x1b	| ( 4 << 16 ))
+#define T_DRIVER_REVISION		(0x1c	| ( 4 << 16 ))
+#define T_FW_REVISION			(0x1d	| ( 4 << 16 ))
+#define T_MAC_HW_REVISION		(0x1e	| ( 4 << 16 ))
+#define T_PHY_HW_REVISION		(0x1f	| ( 4 << 16 ))
+
+/* HANDOVER */
+#define T_SCAN_INTERVAL			(0x20	| ( 1 << 16 ))
+
+#define T_RSC_RETAIN_TIME		(0x2f	| ( 2 << 16 ))
+
+/* SLEEP */
+#define T_TYPE1_ISW				(0x40	| ( 1 << 16 ))
+
+#define T_SLP_START_TO			(0x4a 	| ( 2 << 16 ))
+
+/* IDLE */
+#define T_IDLE_MODE_TO			(0x50	| ( 2 << 16 ))
+
+#define T_IDLE_START_TO			(0x54	| ( 2 << 16 ))
+
+/* MONITOR */
+#define T_RSSI						(0x60	| ( 1 << 16 ))
+#define T_CINR						(0x61	| ( 1 << 16 ))
+#define T_TX_POWER          	    (0x6a   | ( 1 << 16 ))
+#define T_PER						(0x6b   | ( 1 << 16 ))
+#define T_UL_PERM_BASE				(0x6c   | ( 1 << 16 ))
+#define T_DL_PERM_BASE				(0x6d   | ( 1 << 16 ))
+#define T_CURR_PREAMBLE_IDX			(0x6e   | ( 1 << 16 ))
+#define T_PREV_PREAMBLE_IDX			(0x6f   | ( 1 << 16 ))
+#define T_HO_SIGNAL_LATENCY			(0x70   | ( 2 << 16 ))
+#define T_RSSI_2					(0x71   | ( 1 << 16 ))
+#define T_CINR_2					(0x72   | ( 1 << 16 ))
+#define T_POWER_CONTROL_MODE		(0x73   | ( 1 << 16 ))
+#define T_PER_RECEIVE_COUNT			(0x74   | ( 4 << 16 ))
+#define T_PER_ERROR_COUNT			(0x75   | ( 4 << 16 ))
+#define T_UL_BURST_DATA_FEC_SCHEME	(0x76   | ( 1 << 16 ))
+#define T_DL_BURST_DATA_FEC_SCHEME	(0x77   | ( 1 << 16 ))
+#define T_UL_BURST_DATA_UIUC		(0x78   | ( 1 << 16 ))
+#define T_DL_BURST_DATA_UIUC		(0x79   | ( 1 << 16 ))
+#define T_TX_POWER_MAX				(0x7a   | ( 1 << 16 ))
+#define T_HO_CNT					(0x7c   | ( 2 << 16 ))
+#define T_HO_FAIL_CNT				(0x7d   | ( 2 << 16 ))
+#define T_RESYNC_CNT				(0x7e   | ( 2 << 16 ))
+#define T_CUR_FREQ					(0x7f	| ( 4 << 16 ))
+
+
+/* WIMAX */
+#define T_MAX_SUBSCRIPTION		(0xa1	| ( 1 << 16 ))
+#define T_MAX_SF				(0xa2	| ( 1 << 16 ))
+#define T_PHY_TYPE				(0xa3	| ( 1 << 16 ))
+#define T_PKM					(0xa4	| ( 1 << 16 ))
+#define T_AUTH_POLICY			(0xa5	| ( 1 << 16 ))
+#define T_CS_TYPE				(0xa6	| ( 2 << 16 ))
+#define T_VENDOR_NAME			(0xa7	| ( 0 << 16 ))
+#define T_MOD_NAME				(0xa8	| ( 0 << 16 ))
+#define T_PACKET_FILTER			(0xa9	| ( 1 << 16 ))
+#define T_NSP_CHANGE_COUNT		(0xaa	| ( 4 << 16 ))
+#define T_RADIO_STATE			(0xab	| ( 1 << 16 ))
+#define T_URI_CONTACT_TYPE		(0xac	| ( 1 << 16 ))
+#define T_URI_TEXT				(0xad	| ( 0 << 16 ))
+#define T_URI					(0xae 	| ( 0 << 16 ))
+#define T_ENABLE_AUTH			(0xaf	| ( 1 << 16 ))
+#define T_TIMEOUT               (0xb0   | ( 2 << 16 ))
+#define T_RUN_MODE				(0xb1	| ( 1 << 16 ))
+			#define T_NORMAL_MODE			0
+			#define T_ENGINEERING_MODE		1
+#define T_OMADMT_VER			(0xb2	| ( 4 << 16 ))
+#define T_RTC_TIME				(0xb3	| ( 4 << 16 ))	/*This is measured in seconds from 00:00:00 GMT January 1, 1970.*/
+#define T_CERT_STATUS			(0xb4	| ( 4 << 16 ))
+#define T_CERT_MASK				(0xb5	| ( 4 << 16 ))
+#define T_EMSK					(0xb6	| ( 64 << 16 ))
+
+/* Subscription TLV */
+#define T_SUBSCRIPTION_LIST		(0xd1	| ( 0 << 16 ) | (1 << 31))
+#define T_H_NSPID				(0xd2	| ( 3 << 16 ))
+#define T_NSP_NAME				(0xd3	| ( 0 << 16 ))
+#define T_SUBSCRIPTION_NAME		(0xd4	| ( 0 << 16 ))
+#define T_SUBSCRIPTION_FLAG		(0xd5	| ( 2 << 16 ))
+#define T_V_NSPID				(0xd6	| ( 3 << 16 ))
+#define T_NAP_ID				(0xd7	| ( 3 << 16 ))
+#define T_PREAMBLES				(0xd8	| ( 15 << 16 ))
+#define T_BW					(0xd9	| ( 4 << 16 ))
+#define T_FFTSIZE				(0xda	| ( 4 << 16 ))
+#define T_DUPLEX_MODE			(0xdb	| ( 4 << 16 ))
+#define T_REALM					(0xdc	| ( 0 << 16 ))
+#define T_MO_REALM				(0xdd	| ( 0 << 16 ))
+
+typedef struct hci {
+	u16		cmd_evt;
+	u16		length;
+	u8		data[0];	
+} __attribute__((packed)) hci_t;
+
+typedef struct hci_image_payload {
+	u16		type;
+	u32		offset;
+	u8		data[0];
+} __attribute__((packed)) hci_image_payload_t;
+
+typedef struct hci_image_response {
+	u16		type;
+	u32		offset;
+	s32		result;
+} __attribute__((packed)) hci_image_response_t;
+
+typedef struct hci_file_write {
+	u32		offset;
+	u16		path_len;	/*Include null char*/
+	u8		path[0];
+	u8		data[0];
+} __attribute__((packed)) hci_file_write_t;
+#define hci_file_data(p)	(p->path+p->path_len)
+
+typedef struct hci_file_delete {
+	u8		path[0];
+	u8		data[0];
+} __attribute__((packed)) hci_file_delete_t;
+
+typedef struct hci_file_read {
+	u32		offset;
+	u8	 	path[0];
+	u8		data[0];
+} __attribute__((packed)) hci_file_read_t;
+
+typedef struct hci_file_response {
+	s32		result;
+	u16		path_len;
+	u8		path[0];
+	u8		data[0];
+} __attribute__((packed)) hci_file_response_t;
+#define file_response_data(r)	\
+	(((hci_file_response_t*)(r))->path+B2H(((hci_file_response_t*)(r))->path_len))
+
+typedef struct hci_notification {
+	u8		category;
+	u8		type;
+	u8		value[0];
+} __attribute__((packed)) hci_notification_t;
+
+typedef struct hci_set_eap_info
+{
+	u8		type;
+	u16		frag_size;
+	u8		use_delimiter;
+	u8		tlv[0];
+} __attribute__((packed)) hci_set_eap_info_t;
+
+typedef struct hci_set_eap_info_result
+{
+	u32 		code;
+} __attribute__((packed)) hci_set_eap_info_result_t;
+
+typedef struct hci_get_cert_info
+{
+	u8		index;
+} __attribute__((packed)) hci_get_cert_info_t;
+
+typedef struct hci_get_cert_info_result
+{
+	s32		result;
+	u16		source;
+	u8		level;
+	u8		tlv[0];
+} __attribute__((packed)) hci_get_cert_info_result_t;
+
+typedef struct hci_delete_cert
+{
+	u8		index;
+} __attribute__((packed)) hci_delete_cert_t;
+
+typedef struct hci_delete_cert_result
+{
+	u32		 result;
+} __attribute__((packed)) hci_delete_cert_result_t;
+
+typedef struct hci_set_arm_capability_s
+{
+	u32		capability;
+} __attribute__((packed)) hci_set_arm_capability_t;
+
+typedef struct hci_set_arm_capability_result_s
+{
+	u32		capability;
+} __attribute__((packed)) hci_set_arm_capability_result_t;
+
+typedef struct hci_mode_change_s
+{
+	u8		status[3];
+	u8		power_state;
+} __attribute__((packed)) hci_mode_change_t;
+
+typedef struct tlv_s {
+	u8 T;
+	u16 L;
+	u8 *V;
+
+} tlv_t;
+
+#define HCI_INDICATION			(1<<0)
+
+typedef struct hci_req_s {
+	struct list_head list;
+	u16 cmd_evt;
+	
+	void *buf;		/*this buffer is shared with data to check.*/
+	int len;
+	int chk_len;	/*length of data to check*/
+	u32 flag;
+	pthread_cond_t cond;
+
+} hci_req_t;
+
+typedef struct hci_msg_s {
+	char buf[HCI_MAX_PACKET];
+	int len;
+
+} hci_msg_t;
+
+int hci_get_tlv(u8 *buf, u8 *T, u16 *L, u8 **V);
+int hci_set_tlv(u8 *buf, u8 T, u16 L, u8 *V);
+
+int hci_send(int dev_idx, u16 cmd, u8 *data, int len);
+int hci_send_wait(int dev_idx, u16 s_cmd, u8 *data, int plen, 
+	u16 w_cmd, void *buf, int len, int chk_len, u32 flag, int timeout);
+int hci_wait(int dev_idx, u16 cmd_evt,
+	void *buf, int len, int chk_len, u32 flag, int timeout);
+int hci_destroy_resp(int dev_idx);
+int hci_req_getinfo(int dev_idx, u8 *buf, tlv_t *tlv, int cnt);
+int hci_req_getinfo32(int dev_idx, u8 type, u32 *val);
+int hci_req_setinfo32(int dev_idx, u8 type, u32 val);
+int hci_send_msg(int dev_idx, hci_msg_t *msg);
+int hci_receiver_create(msg_thr_t *hci_recvr);
+int hci_receiver_delete(msg_thr_t *hci_recvr);
+
+#endif /* __HCI_H__ */
+
diff --git a/sdk/io.c b/sdk/io.c
new file mode 100644
index 0000000..2203aea
--- /dev/null
+++ b/sdk/io.c
@@ -0,0 +1,472 @@
+// 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 "global.h"
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "error.h"
+#include "wimax.h"
+#include "wm_ioctl.h"
+#include "io.h"
+#include "device.h"
+#include "hci.h"
+#include "log.h"
+
+int get_iface_index(int fd, const char *device)
+{
+	struct ifreq ifr;  
+
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, device, IFNAMSIZ);
+ 	ifr.ifr_name[strlen(ifr.ifr_name)] = '\0';
+
+    	if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
+		xprintf(SDK_STD_ERR, "SIOCGIFINDEX(%d)\n", fd);
+        	return sdk_set_errno(ERR_STD);
+	}
+	
+	return ifr.ifr_ifindex;
+}
+
+static int net_open(device_t *dev)
+{
+	int fd;
+	char *ifname = dev->name;
+	int ifindex;
+
+	fd = socket(PF_PACKET, SOCK_DGRAM, IPPROTO_IP);
+	if (fd < 0) {
+		xprintf(SDK_STD_ERR, "socket\n");
+		return sdk_set_errno(ERR_STD);
+	}
+
+	ifindex = get_iface_index(fd, ifname);
+
+	if (ifindex < 0) {
+		xprintf(SDK_ERR, "Cannot find the interface\n");
+		return sdk_set_errno(ERR_ENV);
+	}
+
+	xprintf(SDK_DBG, "net open, fd=%d, ifindex=%d, name=%s\n", fd, ifindex, ifname);
+	dev->ifindex = ifindex;
+	dev->net_fd = fd;
+	return 0;
+}
+
+int net_updown(int dev_idx, bool up)
+{
+	device_t *dev;
+	struct ifreq ifr;
+	int fd;
+	int ret = 0;
+
+	xfunc_in();
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+	
+	if (!dev->inserted) {
+		xprintf(SDK_DBG, "device(%s) has been removed\n", dev->name);
+		goto out;
+	}
+
+	fd = dev->net_fd;
+
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, dev->name, IFNAMSIZ);
+	if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
+		xprintf(SDK_STD_ERR, "ioctl SIOCGIFFLAGS(%d) %s\n", fd, up ? "Up" : "Down");
+		ret = sdk_set_errno(ERR_STD);
+		goto out;
+	}
+
+	if (up)
+		ifr.ifr_flags |= (IFF_UP|IFF_RUNNING);
+	else
+		ifr.ifr_flags &= ~IFF_UP;
+	
+	if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
+		xprintf(SDK_STD_ERR, "ioctl SIOCSIFFLAGS(%d) %s\n", fd, up ? "Up" : "Down");
+		ret = sdk_set_errno(ERR_STD);
+	}
+out:
+	dm_put_dev(dev_idx);
+	xfunc_out();
+	return ret;
+}
+
+#define RESOLV_CONF_PATH    "/etc/resolv.conf"
+
+unsigned int net_get_dns_info_mtime(void)
+{
+	const char *file = RESOLV_CONF_PATH;
+	struct stat stat_buf;
+
+	if (stat(RESOLV_CONF_PATH, &stat_buf) < 0) {
+		if (errno == ENOENT)
+			xprintf(SDK_DBG, "%s has been removed!\n", RESOLV_CONF_PATH);
+		else {
+			xprintf(SDK_STD_ERR, "stat(%s)\n", file);
+			return 0;
+		}
+	}
+	xprintf(SDK_DBG, "%s: st_mtime=0x%08X\n", file, (int)stat_buf.st_mtime);
+	return stat_buf.st_mtime;
+}
+
+int net_get_dns_info(dns_info_t *dns_info)
+{
+	FILE *file;
+	int ret, i, svr_cnt, df;
+	char name[16], domain[128];
+
+	xfunc_in();
+
+	file = fopen(RESOLV_CONF_PATH, "r");
+	if (!file) {
+		xprintf(SDK_ERR, "fopen fail = %s(%d)\n", strerror(errno), errno);
+		return -errno;
+	}
+
+	i = svr_cnt = df = 0;
+	while ((ret = fscanf(file, "%s %s", name, domain)) != EOF) {
+		if (ret < 2) {
+			xprintf(SDK_STD_ERR, "fscanf ret=%d\n", ret);
+			ret = -1;
+			break;
+		}
+
+		if (svr_cnt < MAX_DNS_SERVERS && !strcmp(name, "nameserver")) {
+			strcpy(dns_info->dns_svr[svr_cnt++], domain);
+			xprintf(SDK_INFO, "dns_svr=%s\n", domain);
+		}
+		else if (!strcmp(name, "search")) {
+			strcpy(dns_info->domain, domain);
+			xprintf(SDK_INFO, "domain=%s\n", domain);
+			df++;
+		}
+	}
+
+	fclose(file);
+
+	xprintf(SDK_INFO, "svr_cnt=%d, df=%d\n", svr_cnt, df);
+
+	if (svr_cnt && df)
+		ret = 0;
+	else
+		ret = -1;
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int net_get_dhcp_info(int dev_idx, dhcp_info_t *dhcp_info)
+{
+#define sizeof_sa_sin_port	2
+#define p_inaddrr(x) (&ifr.x[sizeof_sa_sin_port])
+	device_t *dev;
+	struct ifreq ifr;
+	struct in_addr inaddr;
+	char *dev_name;
+	int fd;
+	int ret = 0;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	dev_name = dev->name;
+	
+	if (!dev->inserted) {
+		xprintf(SDK_ERR, "device(%s) has been removed\n", dev_name);
+		goto out;
+	}
+
+	fd = dev->net_fd;
+
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, dev_name, IFNAMSIZ);
+	if (ioctl(fd, SIOCGIFADDR, &ifr) < 0) {
+		xprintf(SDK_DBG, "ioctl SIOCGIFFLAGS(%d)\n", fd);
+		ret = sdk_set_errno(ERR_STD);
+		goto out;
+	}
+	memcpy(&inaddr, p_inaddrr(ifr_addr.sa_data), sizeof(inaddr));
+	strcpy(dhcp_info->ip, inet_ntoa(inaddr));
+	xprintf(SDK_INFO, "ip: %s\n", dhcp_info->ip);
+
+
+	ret = ioctl(fd, SIOCGIFNETMASK, &ifr);
+	memcpy(&inaddr, p_inaddrr(ifr_addr.sa_data), sizeof(inaddr));
+
+	if (ret < 0) {
+		xprintf(SDK_STD_ERR, "ioctl SIOCGIFNETMASK(%d): netmask(%s)\n",
+			fd, inet_ntoa(inaddr));
+		ret = sdk_set_errno(ERR_STD);
+		goto out;
+	}
+
+	strcpy(dhcp_info->netmask, inet_ntoa(inaddr));
+	xprintf(SDK_INFO, "netmask: %s\n", dhcp_info->netmask);
+
+out:
+	xprintf(SDK_DBG, "net_get_dhcp_info: ret=%d\n", ret);
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+int net_ioctl(int dev_idx, wm_req_t *wmr, int cmd)
+{
+	device_t *dev;
+	int ret = 0;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	wmr->cmd = cmd;
+	xfunc_in("cmd=0x%X", wmr->cmd);
+
+	if (dev->inserted && ioctl(dev->net_fd, SIOCWMIOCTL, wmr) < 0) {
+		xprintf(SDK_STD_ERR, "[%d] cmd=%d\n", dev_idx, wmr->cmd);
+		ret = sdk_set_errno(ERR_STD);
+	}
+
+	xfunc_out("ret=%d", ret);
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+int net_ioctl_data(int dev_idx, bool get, u16 data_id, void *buf, int size)
+{
+	device_t *dev;
+	wm_req_t wmr;
+	int ret = -1, cmd;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	if (data_id >= SIOC_DATA_MAX) {
+		xprintf(SDK_ERR, "invalid data_id=%d\n", data_id);
+		goto out;
+	}
+	if (!buf) {
+		xprintf(SDK_ERR, "buffer is null\n");
+		goto out;
+	}
+	if (size <= 0) {
+		xprintf(SDK_ERR, "invalid size=%d\n", size);
+		goto out;
+	}
+
+	cmd = get ? SIOCG_DATA : SIOCS_DATA;
+	strncpy(wmr.ifr_name, dev->name, sizeof(wmr.ifr_name)-1);
+	wmr.data_id = data_id;
+	wmr.data.buf = buf;
+	wmr.data.size = size;
+
+	xprintf(SDK_INFO, "net ioctl: cmd=%s, id=%d\n", get ? "Get" : "Set", data_id);
+	if ((ret = net_ioctl(dev_idx, &wmr, cmd)) < 0) {
+		xprintf(SDK_STD_ERR, "[%d] cmd(0x%04x) data id=%d\n", dev_idx, cmd, data_id);
+		sdk_set_errno(ERR_STD);
+	}
+out:
+	dm_put_dev(dev_idx);
+	xfunc_out("ret=%d", ret);
+	return ret < 0 ? -1 : wmr.data.size;
+}
+
+static void net_close(device_t *dev)
+{
+	xfunc_in();
+	if (dev->net_fd > 0) {
+		xprintf(SDK_DBG, "close(%d)\n", dev->net_fd);
+		close(dev->net_fd);
+		dev->net_fd = 0;
+	}
+	xfunc_out();
+}
+
+static int io_open(device_t *dev)
+{
+	int idx, ret;
+
+	sscanf(dev->name, "wm%d", &idx);
+	ret = nl_open(&dev->io_nl, NETLINK_WIMAX, dev->ifindex, idx);
+
+	if (ret < 0) {
+		xprintf(SDK_ERR, "Open net-link failure\n");
+		return sdk_set_errno(ERR_ENV);
+	}
+
+	xprintf(SDK_DBG, "io open\n");
+	return ret;
+}
+
+static void io_close(device_t *dev)
+{
+	int ret;
+
+	xfunc_in("dev=%s", dev->name);
+	ret = nl_close(&dev->io_nl);
+	xfunc_out("ret=%d", ret);
+}
+
+int io_send(int dev_idx, void *buf, int len)
+{
+	device_t *dev;
+	int ret;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	ret = nl_send(&dev->io_nl, 0, buf, len);
+
+	if (ret < 0) {
+		if (!dev->inserted)
+			xprintf(SDK_DBG, "device[%d] has been removed\n", dev_idx);
+		else {
+			xprintf(SDK_STD_ERR, "[%d] nl_send\n", dev_idx);
+			sdk_set_errno(ERR_STD);
+		}
+	}
+	else if (!ret) {
+		xprintf(SDK_ERR, "nl_send length is 0.\n");
+		ret = -1;
+	}
+	else
+		ret = len;
+
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+static int io_recv(device_t *dev, char *buf, int len, int flags)
+{
+	hnetlink_t *hnl = &dev->io_nl;
+	int ret;
+
+	ret = nl_recv(hnl, buf, len, flags);
+
+	if (ret < 0) {
+		if (!dev->inserted) {
+			xprintf(SDK_DBG, "device(%s) has been removed\n", dev->name);
+			return -1;
+		}
+		xprintf(SDK_STD_ERR, "nl_recv\n");
+		sdk_set_errno(ERR_STD);
+	}
+	else if (!ret) {
+		xprintf(SDK_ERR, "Received length is 0.\n");
+		ret = -1;
+	}
+
+	return ret;
+}
+
+void *io_receiver_thread(void *data)
+{
+	int dev_idx = (int) data;
+	device_t *dev;
+	hci_msg_t *msg;
+	int fd, len = 0;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		goto end;
+
+	xfunc_in("name=%s", dev->name);
+
+	if ((fd = net_open(dev)) < 0)
+		goto out;
+
+	if ((fd = io_open(dev)) < 0)
+		goto out;
+
+	pthread_sem_signal(&dev->sync_lock);
+
+	while (1) {
+		msg = (hci_msg_t *) sdk_malloc(sizeof(hci_msg_t));
+
+		len = io_recv(dev, msg->buf, sizeof(msg->buf), 0);
+		xprintf(SDK_DBG, "io_recv: %02x%02x %02x%02x\n",
+			(u8)msg->buf[0], (u8)msg->buf[1], (u8)msg->buf[2], (u8)msg->buf[3]);
+		if (len < 0) {
+			if (errno == ENOBUFS) {
+				/*
+					If rx-netlink is full, ENOBUFS is returned,
+					thus, we will try to receive non-overflowed data,
+					but overflowed data cannot be received.
+				*/
+				xprintf(SDK_NOTICE, "ENOBUFS has been returned and try to receive again!");
+				continue;
+			}
+			sdk_free(msg);
+			break;
+		}
+
+		msg->len = len;
+		hci_send_msg(dev_idx, msg);
+		xprintf(SDK_DBG, "[%d] msg sent, len=%d\n", dev_idx, len);
+	}
+
+out:
+	io_close(dev);
+	net_close(dev);
+	xfunc_out("name=%s", dev->name);
+	dm_put_dev(dev_idx);
+end:
+	#if 0
+	if (!len)
+		pthread_sem_signal(&dev->sync_lock);
+	#endif
+	return NULL;
+}
+
+int io_receiver_create(int dev_idx)
+{
+	device_t *dev;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+	
+	xfunc_in("dev=%d", dev_idx);
+
+	pthread_create(&dev->ind_thr, NULL, io_receiver_thread, (void *)dev_idx);
+
+	pthread_sem_wait(&dev->sync_lock);
+
+	xfunc_out();
+	dm_put_dev(dev_idx);
+	return dev->io_nl.fd ? 0 : -1;
+}
+
+int io_receiver_delete(int dev_idx)
+{
+	device_t *dev;
+	pthread_t thread;
+	int ret;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	xfunc_in("name=%s", dev->name);
+
+	if ((thread = dev->ind_thr)) {
+		dev->ind_thr = (pthread_t) NULL;
+		pthread_cancel(thread);
+		xprintf(SDK_DBG, "+IO(%d) pthread_join\n", dev_idx);
+		ret = pthread_join(thread, NULL);
+		xprintf(SDK_DBG, "+IO(%d) pthread_join, ret=%d\n", dev_idx, ret);
+		net_close(dev);
+		io_close(dev);
+	}
+
+	xfunc_out("name=%s, thread=0x%08X", dev->name, (int) thread);
+	dm_put_dev(dev_idx);
+	return 0;
+}
+
diff --git a/sdk/io.h b/sdk/io.h
new file mode 100644
index 0000000..365a183
--- /dev/null
+++ b/sdk/io.h
@@ -0,0 +1,42 @@
+// 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.
+
+#if !defined(IO_H_20080709)
+#define IO_H_20080709
+#include "global.h"
+#include "wm_ioctl.h"
+
+#define IO_TIMEOUT_SEC		10
+
+#define MAX_DNS_SERVERS		2
+#define MAX_NET_STR_LEN		256
+
+typedef struct dns_info_s {
+	char dns_svr[MAX_DNS_SERVERS][MAX_NET_STR_LEN];
+	char domain[MAX_NET_STR_LEN];
+
+} dns_info_t;
+
+typedef struct dhcp_info_s {
+	char ip[MAX_NET_STR_LEN];
+	char netmask[MAX_NET_STR_LEN];
+
+} dhcp_info_t;
+
+int io_send(int dev_idx, void *buf, int len);
+int net_updown(int dev_idx, bool up);
+unsigned int net_get_dns_info_mtime(void);
+int net_get_dns_info(dns_info_t *dns_info);
+int net_get_dhcp_info(int dev_idx, dhcp_info_t *dhcp_info);
+int net_ioctl(int dev_idx, wm_req_t *wmr, int cmd);
+int net_ioctl_data(int dev_idx, bool get, u16 data_id, void *buf, int size);
+#define net_ioctl_get_data(dev_idx, data_id, buf, size)	\
+	net_ioctl_data(dev_idx, TRUE, data_id, buf, size)
+#define net_ioctl_set_data(dev_idx, data_id, buf, size)	\
+	net_ioctl_data(dev_idx, FALSE, data_id, buf, size)
+
+int io_receiver_create(int dev_idx);
+int io_receiver_delete(int dev_idx);
+
+#endif
diff --git a/sdk/list.h b/sdk/list.h
new file mode 100644
index 0000000..8493304
--- /dev/null
+++ b/sdk/list.h
@@ -0,0 +1,328 @@
+// 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.
+
+#ifndef LINUX_LIST_H_07142008
+#define LINUX_LIST_H_07142008
+#include <pthread.h>
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized list entries.
+ */
+#define LIST_POISON1  ((void *) 0x00100100)
+#define LIST_POISON2  ((void *) 0x00200200)
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+struct list2_head {
+	struct list_head head;
+	pthread_mutex_t lock;
+	int cnt;
+
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+	struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+	(ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+#define INIT_LIST2(ptr) do { \
+	INIT_LIST_HEAD(&(ptr)->head);\
+	pthread_mutex_init(&(ptr)->lock, NULL);\
+	(ptr)->cnt = 0;\
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+			      struct list_head *prev,
+			      struct list_head *next)
+{
+	next->prev = new;
+	new->next = next;
+	new->prev = prev;
+	prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return TRUE after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	entry->next = LIST_POISON1;
+	entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+        __list_del(list->prev, list->next);
+        list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+				  struct list_head *head)
+{
+        __list_del(list->prev, list->next);
+        list_add_tail(list, head);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+	return head->next == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is
+ * empty _and_ checks that no other CPU might be
+ * in the process of still modifying either member
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ *
+ * @head: the list to test.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+	struct list_head *next = head->next;
+	return (next == head) && (next == head->prev);
+}
+
+static inline void __list_splice(struct list_head *list,
+				 struct list_head *head)
+{
+	struct list_head *first = list->next;
+	struct list_head *last = list->prev;
+	struct list_head *at = head->next;
+
+	first->prev = head;
+	head->next = first;
+
+	last->next = at;
+	at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+	if (!list_empty(list))
+		__list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+				    struct list_head *head)
+{
+	if (!list_empty(list)) {
+		__list_splice(list, head);
+		INIT_LIST_HEAD(list);
+	}
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:	the &struct list_head pointer.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+   ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+/**
+ * list_for_each	-	iterate over a list
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @head:	the head for your list.
+ */
+#define list_for_each(pos, head) \
+	for (pos = (head)->next; pos != (head); \
+        	pos = pos->next)
+
+/**
+ * __list_for_each	-	iterate over a list
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @head:	the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+	for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev	-	iterate over a list backwards
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @head:	the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+	for (pos = (head)->prev; pos != (head); \
+        	pos = pos->prev)
+
+/**
+ * list_for_each_safe	-	iterate over a list safe against removal of list entry
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @n:		another &struct list_head to use as temporary storage
+ * @head:	the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+	for (pos = (head)->next, n = pos->next; pos != (head); \
+		pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry	-	iterate over list of given type
+ * @pos:	the type * to use as a loop counter.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member)				\
+	for (pos = list_entry((head)->next, typeof(*pos), member);	\
+	     &pos->member != (head); 	\
+	     pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos:	the type * to use as a loop counter.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member)			\
+	for (pos = list_entry((head)->prev, typeof(*pos), member);	\
+	     &pos->member != (head); 	\
+	     pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use as a start point in
+ *			list_for_each_entry_continue
+ * @pos:	the type * to use as a start point
+ * @head:	the head of the list
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_prepare_entry(pos, head, member) \
+	((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue -	iterate over list of given type
+ *			continuing after existing point
+ * @pos:	the type * to use as a loop counter.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_continue(pos, head, member) 		\
+	for (pos = list_entry(pos->member.next, typeof(*pos), member);	\
+	     &pos->member != (head);	\
+	     pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos:	the type * to use as a loop counter.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member)			\
+	for (pos = list_entry((head)->next, typeof(*pos), member),	\
+		n = list_entry(pos->member.next, typeof(*pos), member);	\
+	     &pos->member != (head); 					\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+#endif
diff --git a/sdk/log.c b/sdk/log.c
new file mode 100644
index 0000000..94d03b6
--- /dev/null
+++ b/sdk/log.c
@@ -0,0 +1,386 @@
+// 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 "global.h"
+#include "log.h"
+#include <time.h>
+
+#define FILE_LOG_TIME_INFO
+//#define STDOUT_LOG_TIME_INFO
+#define FORCE_ENABLE_STDOUT_API_LOG
+
+bool log_print_all;
+
+#if defined(FORCE_ENABLE_STDOUT_API_LOG)
+#define FORCE_ENABLED_STDOUT_MASK	\
+	(SDK_FORCE|SDK_ERR|SDK_STD_ERR|SDK_NOTICE|SDK_API_LOG)
+#else
+#define FORCE_ENABLED_STDOUT_MASK	\
+	(SDK_FORCE|SDK_ERR|SDK_STD_ERR|SDK_NOTICE)
+#endif
+
+#if (CONFIG_LOG_FILE_BUF_SIZE > 0)
+#define LOG_FILE_BUF_SIZE			(CONFIG_LOG_FILE_BUF_SIZE)
+#endif
+
+#define MAX_LOG_BUF	4096
+static char log_file[256];
+static int log_mask_idx = 0;
+#if !defined(LOG_FILE_BUF_SIZE)
+static int log_fd = 0;
+#endif
+
+static const unsigned log_mask[] = {
+	/*STDOUT*/
+	SDK_LOG_LEVEL_0,
+	SDK_LOG_LEVEL_1,
+	SDK_LOG_LEVEL_2,
+	SDK_LOG_LEVEL_3,
+	SDK_LOG_LEVEL_4,
+	/*FILE*/
+	SDK_LOG_LEVEL_5,
+	SDK_LOG_LEVEL_6,
+	SDK_LOG_LEVEL_7,
+	SDK_LOG_LEVEL_8,
+	SDK_LOG_LEVEL_9,
+
+	/*Flush log buffer to file*/
+	SDK_LOG_LEVEL_10,
+};
+
+#define cur_log_mask()			(log_mask[log_mask_idx])
+#define get_log_mask(level)		(log_mask[level])
+
+#if defined(LOG_FILE_BUF_SIZE)
+typedef struct log_buf_mng_s {
+	char		*buffer;
+	unsigned	put_idx,
+				count;
+
+	pthread_mutex_t	log_lock;
+
+} log_buf_mng_t;
+
+static log_buf_mng_t log_buf_mnger;
+
+static void log_buffer_init(void)
+{
+	log_buf_mng_t *mnger = &log_buf_mnger;
+
+	mnger->put_idx = mnger->count = 0;
+	pthread_mutex_init(&mnger->log_lock, NULL);
+	mnger->buffer = sdk_malloc(LOG_FILE_BUF_SIZE);
+}
+
+static int log_buffer_write(const char *str)
+{
+	log_buf_mng_t *mnger = &log_buf_mnger;
+	int len, put_idx, available;
+
+	len = strlen(str);
+
+	pthread_mutex_lock(&mnger->log_lock);
+	put_idx = mnger->put_idx % LOG_FILE_BUF_SIZE;
+	available = LOG_FILE_BUF_SIZE - put_idx;
+
+	if (available >= len)
+		memcpy(&mnger->buffer[put_idx], str, len);
+	else {
+		memcpy(&mnger->buffer[put_idx], str, available);
+		memcpy(&mnger->buffer[0], &str[available], len-available);
+	}
+
+	mnger->put_idx += len;
+	if (mnger->count <= LOG_FILE_BUF_SIZE)
+		mnger->count += len;
+	pthread_mutex_unlock(&mnger->log_lock);
+	return len;
+}
+#define log_fprintf		log_buffer_write
+
+static void log_buffer_flush(void)
+{
+	log_buf_mng_t *mnger = &log_buf_mnger;
+	int fd, ret, put_idx, to_write;
+
+	if (!strlen(log_file)) {
+		fprintf(stderr, "Log file was not set up!\n");
+		return;
+	}
+
+	if ((fd = open(log_file, O_CREAT|O_WRONLY|O_TRUNC, 0644)) < 0) {
+		fprintf(stderr, "open(%s) file failed(%s)\n", log_file, strerror(errno));
+		return;
+	}
+
+	pthread_mutex_lock(&mnger->log_lock);
+	if (mnger->count < LOG_FILE_BUF_SIZE) {
+		to_write = mnger->count;
+		ret = write(fd, mnger->buffer, to_write);
+	}
+	else {
+		put_idx = mnger->put_idx % LOG_FILE_BUF_SIZE;
+		to_write = LOG_FILE_BUF_SIZE - put_idx;
+		ret = write(fd, &mnger->buffer[put_idx], to_write);
+		if (ret == to_write) {
+			to_write = LOG_FILE_BUF_SIZE - to_write;
+			ret = write(fd, &mnger->buffer[0], to_write);
+		}
+	}
+	pthread_mutex_unlock(&mnger->log_lock);
+
+	if (ret != to_write) {
+		fprintf(stderr, "ERROR write: %d!=%d, %s(%d)\n",
+			to_write, ret, strerror(errno), errno);
+	}
+	else
+		printf("log buffer has been flushed to %s(%d)!\n", log_file, ret);
+	close(fd);
+}
+
+static void log_buffer_deinit(void)
+{
+	log_buf_mng_t *mnger = &log_buf_mnger;
+
+	if (mnger->buffer) {
+		//log_buffer_flush();
+		sdk_free(mnger->buffer);
+		mnger->buffer = NULL;
+		pthread_mutex_destroy(&mnger->log_lock);
+	}
+}
+#endif
+
+int log_set_level(int level)
+{
+	int prev_level = log_mask_idx;
+	#if !defined(LOG_FILE_BUF_SIZE)
+	int fd;
+	#endif
+
+	if (level >= numof_array(log_mask))
+		return log_mask_idx;
+	
+	#if defined(LOG_FILE_BUF_SIZE)
+	if (cur_log_mask() & SDK_LOG_FILE) {
+		if (get_log_mask(level) & SDK_LOG_FILE_FLUSH) {
+			log_buffer_flush();
+			return log_mask_idx;
+		}
+		if (!(get_log_mask(level) & SDK_LOG_FILE))
+			log_buffer_deinit();
+	}
+	else if ((get_log_mask(level) & SDK_LOG_FILE))
+		log_buffer_init();
+	#else
+	if ((get_log_mask(level) & SDK_LOG_FILE) && log_fd <= 0) {
+		if (!strlen(log_file)) {
+			fprintf(stderr, "Log file was not set up!\n");
+			return -1;
+		}
+		if ((fd = open(log_file, O_RDWR|O_APPEND)) < 0 && errno == ENOENT) {
+			if ((fd = open(log_file, O_CREAT|O_RDWR|O_APPEND, 0644)) < 0) {
+				fprintf(stderr, "open(%s) file failed\n", log_file);
+				return -1;
+			}
+		}
+		log_fd = fd;
+	}
+	#endif
+	
+	log_mask_idx = level;
+	return prev_level;
+}
+
+void log_init(const char *logfile, int log_level)
+{
+	#if !defined(LOG_FILE_BUF_SIZE)
+	if (log_fd) {
+		fprintf(stderr, "log_fd(%d) is already opened\n", log_fd);
+		return;
+	}
+	#endif
+
+	if (logfile)
+		strcpy(log_file, logfile);
+
+	log_set_level(log_level);
+
+	xprintf(SDK_NOTICE, "SDK Log Level:%d\n", log_mask_idx);
+}
+
+void log_deinit(void)
+{
+	#if defined(LOG_FILE_BUF_SIZE)
+	log_set_level(0);
+	#else
+	if (log_fd > 0) {
+		close(log_fd);
+		log_fd = 0;
+	}
+	#endif
+}
+
+#if !defined(LOG_FILE_BUF_SIZE)
+static int log_fprintf(const char *str)
+{
+	int fd = log_fd;
+	int ret = 0;
+
+	if (fd > 0)
+		ret = write(fd, str, strlen(str));
+	return ret;
+}
+#endif
+
+static int log_add_time_info(char *buf, const char *title)
+{
+	char *pos = buf;
+	time_t t;
+	struct tm *tm;
+	struct timeval tv;
+
+	time(&t);
+	tm = localtime(&t);
+	gettimeofday(&tv, NULL);
+
+	if (title)
+		pos += sprintf(pos, "[%02d:%02d:%02d:%03d %s] ",
+			tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(tv.tv_usec/1000), title);
+	else
+		pos += sprintf(pos, "[%02d:%02d:%02d:%03d] ",
+			tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(tv.tv_usec/1000));
+
+	return pos - buf;
+}
+
+static inline int log_add_decoration(char *buf, bool file, const char *title)
+{
+	char *pos = buf;
+
+	if (file) {
+		#if defined(FILE_LOG_TIME_INFO)
+		pos += log_add_time_info(pos, title);
+		#else
+		if (title)
+			pos += sprintf(pos, "[%s] ", title);
+		#endif
+	}
+	else {
+		#if defined(STDOUT_LOG_TIME_INFO)
+		pos += log_add_time_info(pos, title);
+		#else
+		if (title)
+			pos += sprintf(pos, "[%s] ", title);
+		#endif
+	}
+
+	return pos - buf;
+}
+
+static int log_vfprintf(const char *title, const char *fmt, va_list args)
+{
+	char buf[MAX_LOG_BUF+256];
+	char *pos = buf;
+	int ret;
+
+	pos += log_add_decoration(pos, TRUE, title);
+
+	vsprintf(pos, fmt, args);
+	ret = log_fprintf(buf);
+
+	return ret;
+}
+
+static int log_vprintf(const char *title, const char *fmt, va_list args)
+{
+	char buf[MAX_LOG_BUF];
+	char *pos = buf;
+	int ret;
+
+	pos += log_add_decoration(pos, FALSE, title);
+
+	vsprintf(pos, fmt, args);
+	#if 1
+	ret = printf("%s", buf);
+	fflush(stdout);
+	#else
+	ret = fprintf(stderr, buf);
+	#endif
+
+	return ret;
+}
+
+int log_printf(unsigned mask, const char *title, const char *fmt, ...)
+{
+	va_list args;
+	int ret = 0;
+
+	if ((cur_log_mask() & mask) || log_print_all) {
+		va_start(args, fmt);
+		if (cur_log_mask() & SDK_LOG_FILE)
+			ret = log_vfprintf(title, fmt, args);
+		if ((cur_log_mask() & SDK_LOG_STDOUT) || (mask & FORCE_ENABLED_STDOUT_MASK)
+			|| log_print_all)
+			ret = log_vprintf(title, fmt, args);
+		va_end(args);
+	}
+
+	return ret;
+}
+
+int log_printf_string(unsigned mask, int flag, const char *title, const char *str)
+{
+	char buf[MAX_LOG_BUF+256];
+	char *pos = buf;
+	int ret = 0;
+
+	if ((cur_log_mask() & mask) || log_print_all) {
+		if (cur_log_mask() & SDK_LOG_FILE) {
+			pos += log_add_decoration(pos, TRUE, title);
+			strcpy(pos, str);
+			ret = log_fprintf(buf);
+			if (flag & SDK_LOG_FLAG_NO_STDOUT_IN_LOGFILE)
+				goto out;
+		}
+		if ((cur_log_mask() & SDK_LOG_STDOUT) || (mask & FORCE_ENABLED_STDOUT_MASK)
+			|| log_print_all) {
+			pos = buf;
+			#if 1
+			pos += log_add_decoration(pos, FALSE, NULL);
+			#else
+			pos += log_add_decoration(pos, FALSE, title);
+			#endif
+			strcpy(pos, str);
+			ret = printf("%s", buf);
+			fflush(stdout);
+		}
+	}
+out:
+	return ret;
+}
+
+void log_printf_hex(unsigned mask, const char *title, void *buf, int len)
+{
+	char *mbuf, *pos;
+	u8 *p = buf;
+	int i;
+
+	if ((cur_log_mask() & mask) || log_print_all) {
+		if (len > MAX_LOG_BUF/4)
+			len = MAX_LOG_BUF/4;
+
+		mbuf = pos = sdk_malloc(len * 7);
+
+		for (i = 0; i < len; i++) {
+			if (i && (i % 16 == 0))
+				pos += sprintf(pos, "\n");
+			pos += sprintf(pos, "%02x ", *p++);
+		};
+
+		log_printf(mask, title, "\n%s\n", mbuf);
+		sdk_free(mbuf);
+	}
+}
+
diff --git a/sdk/log.h b/sdk/log.h
new file mode 100644
index 0000000..67c5064
--- /dev/null
+++ b/sdk/log.h
@@ -0,0 +1,82 @@
+// 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.
+
+#if !defined(LOG_H_07092008)
+#define LOG_H_07092008
+#include "global.h"
+
+#define SDK_LOG_TITLE	"SDK"
+
+#define SDK_NOW				SDK_FORCE
+#define SDK_FORCE			(1<<0)
+#define SDK_ERR				(1<<1)
+#define SDK_STD_ERR			(1<<2)
+#define SDK_NOTICE			(1<<3)
+#define SDK_INFO			(1<<4)
+#define SDK_DBG				(1<<5)
+#define SDK_FUNC			(1<<6)
+#define SDK_API_LOG			(1<<7)
+
+#define SDK_LOG_STDOUT		(1<<31)
+#define SDK_LOG_FILE		(1<<30)
+#define SDK_LOG_FILE_FLUSH	(1<<28)	/*Flush log buffer to file*/
+
+#define _LOG_LEVEL_0		(SDK_FORCE|SDK_ERR|SDK_STD_ERR|SDK_API_LOG)
+#define _LOG_LEVEL_1		(_LOG_LEVEL_0|SDK_NOTICE|SDK_API_LOG)
+#define _LOG_LEVEL_2		(_LOG_LEVEL_1|SDK_INFO|SDK_API_LOG)
+#define _LOG_LEVEL_3		(_LOG_LEVEL_2|SDK_DBG|SDK_API_LOG)
+#define _LOG_LEVEL_4		(_LOG_LEVEL_3|SDK_FUNC|SDK_API_LOG)
+
+#define SDK_LOG_LEVEL_0		(_LOG_LEVEL_0|SDK_LOG_STDOUT)
+#define SDK_LOG_LEVEL_1		(_LOG_LEVEL_1|SDK_LOG_STDOUT)
+#define SDK_LOG_LEVEL_2		(_LOG_LEVEL_2|SDK_LOG_STDOUT)
+#define SDK_LOG_LEVEL_3		(_LOG_LEVEL_3|SDK_LOG_STDOUT)
+#define SDK_LOG_LEVEL_4		(_LOG_LEVEL_4|SDK_LOG_STDOUT)
+#define SDK_LOG_LEVEL_5		(_LOG_LEVEL_0|SDK_LOG_FILE)
+#define SDK_LOG_LEVEL_6		(_LOG_LEVEL_1|SDK_LOG_FILE)
+#define SDK_LOG_LEVEL_7		(_LOG_LEVEL_2|SDK_LOG_FILE)
+#define SDK_LOG_LEVEL_8		(_LOG_LEVEL_3|SDK_LOG_FILE)
+#define SDK_LOG_LEVEL_9		(_LOG_LEVEL_4|SDK_LOG_FILE)
+#define SDK_LOG_LEVEL_10	(SDK_LOG_FILE_FLUSH)
+
+#define LOG_FILE_FLUSH_LEVEL	10
+
+#define SDK_LOG_FLAG_NO_STDOUT_IN_LOGFILE	(1<<0)
+
+#define xfunc_in(fmt, args...)\
+	log_printf(SDK_FUNC, SDK_LOG_TITLE, "+%s[lr:%x] " fmt "\n",\
+		__FUNCTION__, __builtin_return_address(0), ## args)
+#define xfunc_out(fmt, args...)\
+	log_printf(SDK_FUNC, SDK_LOG_TITLE, "-%s " fmt "\n",\
+		__FUNCTION__, ## args)
+
+#define xprintf(mask, fmt, args...)	do {\
+			if ((mask) & SDK_ERR)\
+				log_printf(mask, SDK_LOG_TITLE, "#ERROR: in %s [lr:%x]\n\t:" fmt,\
+				__FUNCTION__, __builtin_return_address(0), ## args);\
+			else if ((mask) & SDK_STD_ERR)\
+				log_printf(mask, SDK_LOG_TITLE, "#ERROR: in %s [lr:%x] err=%s(%d)\n\t:" fmt,\
+				__FUNCTION__, __builtin_return_address(0), strerror(errno), errno, ## args);\
+			else\
+				log_printf(mask, SDK_LOG_TITLE, fmt, ## args);\
+		} while (0)
+
+#define xprintf_hex(mask, title, buf, len)	log_printf_hex(mask, title, buf, len)
+#define xprintf_mac(mask, msg, buf)\
+	log_printf(mask, SDK_LOG_TITLE, "%s=%02x:%02x:%02x:%02x:%02x:%02x\n",\
+		msg, (u8)(buf)[0], (u8)(buf)[1], (u8)(buf)[2],\
+		(u8)(buf)[3], (u8)(buf)[4], (u8)(buf)[5])
+
+extern bool log_print_all;
+#define log_dbg_start()		(log_print_all=TRUE)
+#define log_dbg_end()		(log_print_all=FALSE)
+
+void log_init(const char *logfile, int log_level);
+void log_deinit(void);
+int log_set_level(int level);
+int log_printf(unsigned mask, const char *title, const char *fmt, ...);
+int log_printf_string(unsigned mask, int flag, const char *title, const char *str);
+void log_printf_hex(unsigned mask, const char *title, void *buf, int len);
+
+#endif
diff --git a/sdk/msg.c b/sdk/msg.c
new file mode 100644
index 0000000..ae84f40
--- /dev/null
+++ b/sdk/msg.c
@@ -0,0 +1,132 @@
+// 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 <stdlib.h>
+#include <assert.h>
+#include "msg.h"
+
+#include "global.h"
+#define msg_malloc(s)	sdk_malloc(s)
+#define msg_free(b)		sdk_free(b)
+
+#define MAX_MSG_POOL		10
+
+void msg_init(msg_cb_t *msg_cb)
+{
+	msg_cb->mc_msg_pool = NULL;
+	msg_cb->mc_head = NULL;
+	msg_cb->mc_tail = NULL;
+	msg_cb->mc_pool_cnt = 0;
+
+	pthread_mutex_init(&msg_cb->mc_lock, NULL);
+	pthread_cond_init(&msg_cb->mc_cond, NULL);
+}
+
+void msg_deinit(msg_cb_t *msg_cb)
+{
+	int free_cnt = 0;
+	msg_t *msg;
+
+	pthread_mutex_lock(&msg_cb->mc_lock);
+	while (msg_cb->mc_msg_pool) {
+		msg = msg_cb->mc_msg_pool;
+		msg_cb->mc_msg_pool = msg_cb->mc_msg_pool->ms_next;
+		msg_free(msg);
+		free_cnt++;
+	}
+	msg_cb->mc_pool_cnt = 0;
+	pthread_mutex_unlock(&msg_cb->mc_lock);
+
+	pthread_mutex_destroy(&msg_cb->mc_lock);
+	pthread_cond_destroy(&msg_cb->mc_cond);
+	assert(free_cnt <= MAX_MSG_POOL);
+}
+
+static void put_msg_pool(msg_cb_t *msg_cb, msg_t *msg)
+{
+	if (!msg_cb->mc_msg_pool) {
+		msg->ms_next = NULL;
+		msg_cb->mc_msg_pool = msg;
+		assert(msg_cb->mc_pool_cnt == 0);
+	}
+	else {
+		msg->ms_next = msg_cb->mc_msg_pool;
+		msg_cb->mc_msg_pool = msg;
+		assert(msg_cb->mc_pool_cnt > 0);
+	}
+	msg_cb->mc_pool_cnt++;
+}
+
+static msg_t *get_msg_pool(msg_cb_t *msg_cb)
+{
+	msg_t *msg;
+
+	msg = msg_cb->mc_msg_pool;
+	msg_cb->mc_msg_pool = msg->ms_next;
+	msg_cb->mc_pool_cnt--;
+	assert(msg_cb->mc_pool_cnt >= 0);
+
+	return msg;
+}
+
+void msg_send(msg_cb_t *msg_cb, int prim, void *data)
+{
+	msg_t *msg;
+
+	pthread_mutex_lock(&msg_cb->mc_lock);
+	if (!msg_cb->mc_msg_pool) {
+		pthread_mutex_unlock(&msg_cb->mc_lock);
+		msg = (msg_t *) msg_malloc(sizeof(msg_t));
+		assert(msg);
+		pthread_mutex_lock(&msg_cb->mc_lock);
+	}
+	else
+		msg = get_msg_pool(msg_cb);
+
+	msg->ms_prim = prim;
+	msg->ms_data = data;
+	msg->ms_next = NULL;
+
+	if (!msg_cb->mc_head)
+		msg_cb->mc_head = msg_cb->mc_tail = msg;
+	else {
+		msg_cb->mc_tail->ms_next = msg;
+		msg_cb->mc_tail = msg;
+	}
+	pthread_cond_signal(&msg_cb->mc_cond);
+	pthread_mutex_unlock(&msg_cb->mc_lock);
+}
+
+int msg_recv(msg_cb_t *msg_cb, int *prim, void **data)
+{
+	msg_t *msg;
+	int ret = 0;
+
+	pthread_mutex_lock(&msg_cb->mc_lock);
+	if (!msg_cb->mc_head) {
+		ret = pthread_cond_wait(&msg_cb->mc_cond, &msg_cb->mc_lock);
+		assert(msg_cb->mc_head);
+	}
+
+	msg = msg_cb->mc_head;
+	msg_cb->mc_head = msg_cb->mc_head->ms_next;
+
+	if (prim)
+		*prim = msg->ms_prim;
+	if (data)
+		*data = msg->ms_data;
+
+	if (msg_cb->mc_pool_cnt < MAX_MSG_POOL) {
+		put_msg_pool(msg_cb, msg);
+		pthread_mutex_unlock(&msg_cb->mc_lock);
+	}
+	else {
+		pthread_mutex_unlock(&msg_cb->mc_lock);
+		msg_free(msg);
+	}
+
+	return ret;
+}
+
diff --git a/sdk/msg.h b/sdk/msg.h
new file mode 100644
index 0000000..b5e1f22
--- /dev/null
+++ b/sdk/msg.h
@@ -0,0 +1,34 @@
+// 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.
+
+#if !defined(MSG_H_20080815)
+#define MSG_H_20080815
+#include <pthread.h>
+
+typedef struct msg_s {
+	struct msg_s	*ms_next;
+	int				ms_prim;
+	void			*ms_data;
+
+} msg_t;
+
+typedef struct msg_cb_s {
+	struct msg_s	*mc_msg_pool;
+	int				mc_pool_cnt;
+
+	struct msg_s	*mc_head, 
+					*mc_tail;
+
+	pthread_mutex_t	mc_lock;
+	pthread_cond_t	mc_cond;
+
+} msg_cb_t;
+
+void msg_init(msg_cb_t *msg_cb);
+void msg_deinit(msg_cb_t *msg_cb);
+void msg_send(msg_cb_t *msg_cb, int prim, void *data);
+int msg_recv(msg_cb_t *msg_cb, int *prim, void **data);
+
+#endif
+
diff --git a/sdk/msg_thread.h b/sdk/msg_thread.h
new file mode 100644
index 0000000..d326876
--- /dev/null
+++ b/sdk/msg_thread.h
@@ -0,0 +1,25 @@
+// 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.
+
+#if !defined(MSG_THREAD_H_20100407)
+#define MSG_THREAD_H_20100407
+#include <pthread.h>
+#include "msg.h"
+
+#define USE_PTHREAD_SEM
+#if defined(USE_PTHREAD_SEM)
+#include "pthread_sem.h"
+#endif
+
+typedef struct msg_thr_s {
+	pthread_t			thread;
+	msg_cb_t			msg_cb;
+	#if defined(USE_PTHREAD_SEM)
+	pthread_sem_t		sync_lock;
+	#endif
+
+} msg_thr_t;
+
+#endif
+
diff --git a/sdk/nds.c b/sdk/nds.c
new file mode 100644
index 0000000..27a1390
--- /dev/null
+++ b/sdk/nds.c
@@ -0,0 +1,668 @@
+// 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 "global.h"
+#include "error.h"
+#include "device.h"
+#include "io.h"
+#include "sdk.h"
+#include "nds.h"
+#include "hci.h"
+#include "log.h"
+
+#if defined(CONFIG_ENABLE_BW_SWITCHING_FOR_KT)
+#define FILE_BW_PATH	"/etc/gct/bw"
+
+static u32 nds_get_switching_bw(void)
+{
+	char *file = FILE_BW_PATH;
+	u32 bw = BW_8750KHz;
+	int ret;
+
+	ret = sdk_read_file(file, &bw, sizeof(bw));
+	xprintf(SDK_DBG, "get switching_bw=%d, ret=%d\n", bw, ret);
+	return bw;
+}
+
+static int nds_set_switching_bw(int bw)
+{
+	char *file = FILE_BW_PATH;
+	int ret;
+
+	ret = sdk_write_file(file, &bw, sizeof(bw), O_WRONLY);
+	xprintf(SDK_DBG, "set switching_bw=%d, ret=%d\n", bw, ret);
+	return ret;
+}
+
+void nds_update_switching_bw(int dev_idx)
+{
+	device_t *dev;
+	wimax_t *wm;
+	bool scaned;
+
+	xfunc_in();
+	if (!(dev = dm_get_dev(dev_idx)))
+		return;
+	wm = dev->wimax;
+	scaned = wm->scan_list.cnt;
+	
+	if (scaned) {
+		wm->scan.nr_no_scaned = 0;
+		wm->scan.scan_interval_sec = WM_DEFAULT_SCAN_INTERVAL_SEC;
+		nds_set_switching_bw(wm->scan.scan_bw);
+	}
+	else {
+		wm->scan.nr_no_scaned++;
+		/*Toggle BW*/
+		if (wm->scan.scan_bw == BW_8750KHz)
+			wm->scan.scan_bw = BW_10MHz;
+		else
+			wm->scan.scan_bw = BW_8750KHz;
+		if (wm->scan.nr_no_scaned == 1)
+			wm_req_scan(dev_idx);
+	}
+
+	if (wm->scan.nr_no_scaned >= 2) {
+		if (wm->scan.scan_interval_sec < SWITCHING_BW_MAX_SCAN_INTERVAL_SEC)
+			wm->scan.scan_interval_sec *= 2;
+		wm->scan.nr_no_scaned = 0;
+	}
+	xprintf(SDK_DBG, "nr_no_scaned=%d, scan_bw=%d, interval_sec=%d\n",
+		wm->scan.nr_no_scaned, wm->scan.scan_bw, wm->scan.scan_interval_sec);
+	dm_put_dev(dev_idx);
+	xfunc_out();
+}
+
+static void nds_init_switching_bw(int dev_idx)
+{
+	device_t *dev;
+	wimax_t *wm;
+	char *file = FILE_BW_PATH;
+	u32 bw = BW_8750KHz;
+
+	xfunc_in();
+	if (!(dev = dm_get_dev(dev_idx)))
+		return;
+	wm = dev->wimax;
+
+	if (access(file, 0) < 0)
+		sdk_creat_file(file, &bw, sizeof(bw));
+	else
+		bw = nds_get_switching_bw();
+
+	if (bw == BW_10MHz)
+		wm->scan.scan_bw = BW_10MHz;
+	else
+		wm->scan.scan_bw = BW_8750KHz;
+	dm_put_dev(dev_idx);
+	xfunc_out();
+}
+#endif
+
+void nds_init(int dev_idx)
+{
+	device_t *dev;
+	wimax_t *wm;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return;
+	wm = dev->wimax;
+
+	xfunc_in();
+
+	pthread_mutex_init(&wm->scan_list.lock, NULL);
+	INIT_LIST2(&wm->scan_list);
+
+	pthread_mutex_init(&wm->subs_list.lock, NULL);
+	INIT_LIST2(&wm->subs_list);
+
+	assert(wm->subs_list.head.prev && wm->subs_list.head.next);
+	#if defined(CONFIG_ENABLE_BW_SWITCHING_FOR_KT)
+	nds_init_switching_bw(dev_idx);
+	#endif
+	dm_put_dev(dev_idx);
+	xfunc_out();
+}
+
+void nds_deinit(int dev_idx)
+{
+	device_t *dev;
+	wimax_t *wm;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return;
+	wm = dev->wimax;
+
+	nds_clean_scan_list(wm);
+	dm_put_dev(dev_idx);
+}
+
+int nds_req_scan(int dev_idx, u8 scan_type, u8 *hnspid, u8 *usr_hnai)
+{
+	u8 param[HCI_MAX_PARAM];
+	int len = 0, str_len;
+	int ret;
+	#if defined(CONFIG_ENABLE_BW_SWITCHING_FOR_KT)
+	device_t *dev;
+	wimax_t *wm;
+	u32 bw;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	wm = dev->wimax;
+	#endif
+
+	xfunc_in("dev=%d, type=%d", dev_idx, scan_type);
+	assert(scan_type <= W_SCAN_SPECIFIED_SUBSCRIPTION);
+
+	param[len++] = scan_type;
+	if (scan_type == W_SCAN_SPECIFIED_SUBSCRIPTION) {
+		len += hci_set_tlv(&param[len], TLV_T(T_H_NSPID), TLV_L(T_H_NSPID), hnspid);
+		str_len = strlen((char *)usr_hnai) + 1/*null*/;
+		len += hci_set_tlv(&param[len], TLV_T(T_SUBSCRIPTION_NAME), str_len, usr_hnai);
+		xprintf(SDK_INFO, "Scan hnspid=%06X, user_hnai=%s\n", U82U24(hnspid), usr_hnai);
+	}
+	#if defined(CONFIG_ENABLE_BW_SWITCHING_FOR_KT)
+	xprintf(SDK_NOTICE, "Scan BW=%d\n", wm->scan.scan_bw);
+	bw = DH2B(wm->scan.scan_bw);
+	len += hci_set_tlv(&param[len], TLV_T(T_BW), TLV_L(T_BW), (u8*)&bw);
+	#endif
+
+	if ((ret = hci_send(dev_idx, WIMAX_SCAN, param, len)) == len)
+		ret = 0;
+	else
+		ret = -1;
+	#if defined(CONFIG_ENABLE_BW_SWITCHING_FOR_KT)
+	dm_put_dev(dev_idx);
+	#endif
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int nds_parse_scan_list(int dev_idx, struct wimax_s *wm, u8 *buf, int len)
+{
+	struct list2_head *scan_list = &wm->scan_list;
+	struct wm_nsp_s *nsp = NULL;
+	struct wm_nap_s *nap;
+	u8 T, diff_T, *V;
+	u16 L;
+	int pos = 0, nr_nap, getn;
+
+	xfunc_in();
+	pthread_mutex_lock(&wm->scan_list.lock);
+
+	while (pos < len) {
+		pos += hci_get_tlv(&buf[pos], &T, &L, &V);
+		if (T == TLV_T(T_H_NSPID)) {
+			xprintf(SDK_INFO, "[%d] SCAN H_NSPID=0x%08X\n", dev_idx, U82U24(V));
+			pos += hci_get_tlv(&buf[pos], &T, &L, &V);
+		}
+		if (T != (diff_T=TLV_T(T_V_NSPID))) goto diff_type;
+
+		nsp = (struct wm_nsp_s *) sdk_malloc(sizeof(struct wm_nsp_s));
+		INIT_LIST_HEAD(&nsp->list);
+		nsp->id = U82U24(V);
+
+		nsp->type = wm_get_network_type(wm, V);
+
+		pos += hci_get_tlv(&buf[pos], &T, &L, &V);
+		if (T != (diff_T=TLV_T(T_NSP_NAME))) goto diff_type;
+		memcpy(nsp->name, V, L);
+		nsp->name[L] = 0;
+
+		pos += hci_get_tlv(&buf[pos], &T, &L, &V);
+		if (T != (diff_T=TLV_T(T_CINR))) goto diff_type;
+		nsp->cinr = wm_convert_cinr(*V);
+
+		pos += hci_get_tlv(&buf[pos], &T, &L, &V);
+		if (T != (diff_T=TLV_T(T_RSSI))) goto diff_type;
+		nsp->rssi = wm_convert_rssi(*V);
+
+		xprintf(SDK_INFO, "[%d] V_NSPID=0x%08X, V_NSPNAME=%s, cinr=%d, rssi=%d\n", 
+			dev_idx, nsp->id, nsp->name, nsp->cinr, nsp->rssi);
+
+		nr_nap = 0;
+		do {
+			getn = hci_get_tlv(&buf[pos], &T, &L, &V);
+			if (T == TLV_T(T_BSID)) {
+				assert(WM_MAX_NAP > nr_nap);
+				pos += getn;
+				nap = (struct wm_nap_s *) sdk_malloc(sizeof(struct wm_nap_s));
+				nsp->nap_array[nr_nap] = nap;
+				memcpy(&nap->bsid, V, TLV_L(T_BSID));
+
+				pos += hci_get_tlv(&buf[pos], &T, &L, &V);
+				if (T != (diff_T=TLV_T(T_CINR))) {
+					sdk_free(nsp->nap_array[nr_nap]);
+					nsp->nap_array[nr_nap] = NULL;
+					goto diff_type;
+				}
+				nap->cinr = wm_convert_cinr(*V);
+
+				pos += hci_get_tlv(&buf[pos], &T, &L, &V);
+				if (T != (diff_T=TLV_T(T_RSSI))) {
+					sdk_free(nsp->nap_array[nr_nap]);
+					nsp->nap_array[nr_nap] = NULL;
+					goto diff_type;
+				}
+				nap->rssi = wm_convert_rssi(*V);
+
+				xprintf(SDK_INFO, "[%d] BS(%d): cinr=%d, rssi=%d\n",
+					dev_idx, nr_nap, nap->cinr, nap->rssi);
+				nr_nap++;
+			}
+			else
+				break;
+		} while(pos < len);
+		nsp->nr_nap = nr_nap;
+
+		list_add_tail(&nsp->list, &scan_list->head);
+		scan_list->cnt++;
+	}
+
+	pthread_mutex_unlock(&wm->scan_list.lock);
+	xfunc_out();
+	return 0;
+
+diff_type:
+	pthread_mutex_unlock(&wm->scan_list.lock);
+	if (nsp) {
+		list_del(&nsp->list);
+		sdk_free(nsp);
+	}
+	xprintf(SDK_ERR, "Diff type(0x%02X != 0x%02X)\n", T, diff_T);
+	return -1;
+}
+
+void nds_clean_scan_list(struct wimax_s *wm)
+{
+	struct list_head *head = &wm->scan_list.head;
+	struct wm_nsp_s *nsp, *tmp;
+	int i;
+
+	pthread_mutex_lock(&wm->scan_list.lock);
+	list_for_each_entry_safe(nsp, tmp, head, list) {
+		list_del(&nsp->list);
+		for (i = 0; i < nsp->nr_nap; i++) {
+			sdk_free(nsp->nap_array[i]);
+			nsp->nap_array[i] = NULL;
+		}
+		sdk_free(nsp);
+	}
+	INIT_LIST2(&wm->scan_list);
+	pthread_mutex_unlock(&wm->scan_list.lock);
+}
+
+int nds_update_scan_result(int dev_idx, u8 *buf, int len)
+{
+	device_t *dev;
+	wimax_t *wm;
+	int ret;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	wm = dev->wimax;
+	
+	xfunc_in("dev=%d, len=%d", dev_idx, len);
+
+	nds_clean_scan_list(wm);
+
+	ret = nds_parse_scan_list(dev_idx, wm, buf, len);
+	if (ret < 0)
+		nds_clean_scan_list(wm);
+
+	xfunc_out();
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+static void nds_print_bs_info(int dev_idx, struct bs_info_s *bsinfo, const char *title)
+{
+	xprintf(SDK_INFO, "[%d] %s\n", dev_idx, title);
+	xprintf(SDK_INFO, "H_NSPID[0x%08X], V_NSPID[0x%08X], NAPID[0x%08X]\n",
+		U82U24(bsinfo->hnspid), U82U24(bsinfo->nspid), U82U24(bsinfo->napid));
+		
+	xprintf(SDK_INFO, "id[%02X:%02X:%02X:%02X:%02X:%02X]\n",
+		bsinfo->bsid[0], bsinfo->bsid[1], bsinfo->bsid[2],
+		bsinfo->bsid[3], bsinfo->bsid[4], bsinfo->bsid[5]);
+}
+
+int nds_get_bs_info(int dev_idx, u8 *buf, int len, struct bs_info_s *bsinfo)
+{
+	u8 T, *V;
+	u16 L;
+	int pos = 0;
+	int ret = 0;
+
+	xfunc_in("dev=%d, len=%d", dev_idx, len);
+
+	while (pos < len) {
+		pos += hci_get_tlv(&buf[pos], &T, &L, &V);
+		switch (T) {
+			case TLV_T(T_H_NSPID):
+				ret = (TLV_L(T_H_NSPID) == L) ? 0 : sdk_set_errno(ERR_UNEXPECTED_TLV);
+				memcpy(bsinfo->hnspid, V, TLV_L(T_H_NSPID));
+				break;
+			case TLV_T(T_V_NSPID):
+				ret = (TLV_L(T_V_NSPID) == L) ? 0 : sdk_set_errno(ERR_UNEXPECTED_TLV);
+				memcpy(bsinfo->nspid, V, TLV_L(T_V_NSPID));
+				break;
+			case TLV_T(T_BSID):
+				ret = (TLV_L(T_BSID) == L) ? 0 : sdk_set_errno(ERR_UNEXPECTED_TLV);
+				memcpy(bsinfo->bsid, V, TLV_L(T_BSID));
+				memcpy(bsinfo->napid, V, NAP_ID_SIZE);
+				break;
+			case TLV_T(T_CUR_FREQ):
+				xprintf(SDK_NOTICE, "Current Frequency is %d\n", U82U32(V));
+				break;
+			case TLV_T(T_BW):
+				xprintf(SDK_NOTICE, "Current Bandwidth is %d\n", U82U32(V));
+				break;
+			default:
+				xprintf(SDK_NOTICE, "Type(0x%02X) is unexpected\n", T);
+				break;
+		}
+	}
+
+	xfunc_out();
+	return ret;
+}
+
+int nds_connect_complete(int dev_idx, u8 *buf, int len)
+{
+	device_t *dev;
+	wimax_t *wm;
+	wm_subscription_info_t *subs;
+	bs_info_t bsinfo;
+	wm_nsp_t *nsp;
+	int pos = 0;
+	fsm_event_t event = NC_ConnectComplete;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	wm = dev->wimax;
+	xfunc_in("dev=%d, len=%d", dev_idx, len);
+
+	wm->conn_comp.status = buf[pos++];
+	if (wm->conn_comp.status != wm_connect_success) {
+		event = NC_ConnectFail;
+		xprintf(SDK_INFO, "NC_ConnectFail: status=%d\n", wm->conn_comp.status);
+		goto out;
+	}
+
+	if (nds_get_bs_info(dev_idx, &buf[pos], len-pos, &bsinfo) < 0)
+		goto out;
+	nds_print_bs_info(dev_idx, &bsinfo, "Connect complete");
+	memcpy(wm->conn_comp.subscription.hnspid.id, bsinfo.hnspid, TLV_L(T_H_NSPID));
+	memcpy(wm->conn_comp.net_id.nsp.id, bsinfo.nspid, TLV_L(T_V_NSPID));
+	memcpy(wm->conn_comp.net_id.nap.id, bsinfo.napid, TLV_L(T_NAP_ID));
+	memcpy(wm->conn_comp.net_id.bs.id, bsinfo.bsid, TLV_L(T_BSID));
+
+	if ((subs = wm->scan.selected_subs)) {
+		if (memcmp(bsinfo.hnspid, subs->subscription_id.hnspid.id, NSP_ID_SIZE)) {
+			xprintf(SDK_ERR, "Mismatch H_NSPID(0x%08X!=0x%08X)\n",
+				U82U24(bsinfo.hnspid), U82U24(subs->subscription_id.hnspid.id));
+			goto out;
+		}
+
+		memcpy(&wm->conn_comp.subscription,
+			&subs->subscription_id,
+			sizeof(wm_subscription_identifier_t));
+	}
+	else if (wm->scan.type != wm_scan_all_channels) {
+			xprintf(SDK_ERR, "Selected subscription was not set up\n");
+			goto out;
+	}
+
+	if (memcmp(bsinfo.hnspid, bsinfo.nspid, NSP_ID_SIZE)) {
+		nsp = wm_lookup_nsp_by_id(wm, bsinfo.nspid);
+		if (nsp)
+			strcpy((char *)wm->conn_comp.net_id.nsp.name, (char *)nsp->name);
+		else {
+			memset(wm->conn_comp.net_id.nsp.name, 0, WM_MAX_NSP_NAME_LEN);
+			xprintf(SDK_ERR, "T_V_NSPID(0x%08X)'s NSP list is not found\n",
+				U82U24(wm->conn_comp.net_id.nsp.id));
+			event = NC_ConnectFail;
+			goto out;
+		}
+	}
+out:
+	sdk_ind_event(dev_idx, event);
+
+	xfunc_out();
+	dm_put_dev(dev_idx);
+	return (event==NC_ConnectComplete) ? 0 : -1;
+}
+
+int nds_associate_start(int dev_idx, u8 *buf, int len)
+{
+	device_t *dev;
+	struct wimax_s *wm;
+	struct bs_info_s bsinfo;
+	struct wm_nsp_s *nsp;
+	int pos = 0;
+	fsm_event_t event = NC_AssocStart;
+	int ret = -1;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	wm = dev->wimax;
+
+	xfunc_in("dev=%d, len=%d", dev_idx, len);
+
+	if (nds_get_bs_info(dev_idx, &buf[pos], len-pos, &bsinfo) < 0)
+		goto out;
+
+	memcpy(wm->asso_start.net_id.nsp.id, bsinfo.nspid, TLV_L(T_V_NSPID));
+	memcpy(wm->asso_start.net_id.nap.id, bsinfo.napid, TLV_L(T_NAP_ID));
+	memcpy(wm->asso_start.net_id.bs.id, bsinfo.bsid, TLV_L(T_BSID));
+
+	nsp = wm_lookup_nsp_by_id(wm, bsinfo.nspid);
+	if (nsp) {
+		strcpy((char *)wm->asso_start.net_id.nsp.name, (char *)nsp->name);
+		ret = 0;
+	}
+	else {
+		memset(wm->asso_start.net_id.nsp.name, 0, WM_MAX_NSP_NAME_LEN);
+		xprintf(SDK_ERR, "T_V_NSPID(0x%08X)'s NSP list is not found\n",
+			U82U24(bsinfo.nspid));
+	}
+out:
+	sdk_ind_event(dev_idx, event);
+
+	xfunc_out();
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+int nds_associate_complete(int dev_idx, u8 *buf, int len)
+{
+	device_t *dev;
+	struct wimax_s *wm;
+	struct bs_info_s bsinfo;
+	struct wm_nsp_s *nsp;
+	int pos = 0;
+	fsm_event_t event = NC_AssocSuccess;
+	int ret = -1;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	wm = dev->wimax;
+
+	xfunc_in("dev=%d, len=%d", dev_idx, len);
+
+	wm->asso_comp.status = buf[pos++];
+	if (wm->asso_comp.status != wm_connect_success) {
+		event = NC_AssocFail;
+		xprintf(SDK_INFO, "NC_AssocFail: status=%d\n", wm->asso_comp.status);
+		goto out;
+	}
+
+	if (nds_get_bs_info(dev_idx, &buf[pos], len-pos, &bsinfo) < 0)
+		goto out;
+	memcpy(wm->asso_comp.net_id.nsp.id, bsinfo.nspid, TLV_L(T_V_NSPID));
+	memcpy(wm->asso_comp.net_id.nap.id, bsinfo.napid, TLV_L(T_NAP_ID));
+	memcpy(wm->asso_comp.net_id.bs.id, bsinfo.bsid, TLV_L(T_BSID));
+
+	nsp = wm_lookup_nsp_by_id(wm, bsinfo.nspid);
+	if (nsp) {
+		strcpy((char *)wm->asso_comp.net_id.nsp.name, (char *)nsp->name);
+		ret = 0;
+	}
+	else {
+		wm->asso_comp.status = wm_assoc_req_other_failure;
+		memset(wm->asso_comp.net_id.nsp.name, 0, WM_MAX_NSP_NAME_LEN);
+		xprintf(SDK_ERR, "T_V_NSPID(0x%08X)'s NSP list is not found\n",
+			U82U24(bsinfo.nspid));
+	}
+out:
+	sdk_ind_event(dev_idx, event);
+
+	xfunc_out();
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+int nds_disconnect_ind(int dev_idx, u8 *buf, int len)
+{
+	device_t *dev;
+	struct wimax_s *wm;
+	fsm_event_t event = NC_Disconnect;
+	int ret;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	wm = dev->wimax;
+	
+	xfunc_in("dev=%d, len=%d", dev_idx, len);
+
+	wm->disconn_ind.reason = buf[0];
+	ret = sdk_ind_event(dev_idx, event);
+
+	xfunc_out();
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+int nds_ho_start(int dev_idx, u8 *buf, int len)
+{
+	device_t *dev;
+	wimax_t *wm;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	wm = dev->wimax;
+
+	xfunc_in("dev=%d, len=%d", dev_idx, len);
+
+	wm->ho_start.reason = buf[0];
+
+	xfunc_out();
+	dm_put_dev(dev_idx);
+	return 0;
+}
+
+int nds_ho_complete(int dev_idx, u8 *buf, int len)
+{
+	device_t *dev;
+	wimax_t *wm;
+	bs_info_t bsinfo;
+	int pos = 0;
+	int ret = -1;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	wm = dev->wimax;
+
+	xfunc_in("dev=%d, len=%d", dev_idx, len);
+
+	wm->ho_comp.status = buf[pos++];
+	if (wm->ho_comp.status > wm_connect_success_provisioning)
+		goto out;
+
+	if (nds_get_bs_info(dev_idx, &buf[pos], len-pos, &bsinfo) < 0)
+		goto out;
+	nds_print_bs_info(dev_idx, &bsinfo, "Handover complete");
+	memcpy(wm->ho_comp.net_id.nsp.id, bsinfo.nspid, TLV_L(T_V_NSPID));
+	memcpy(wm->ho_comp.net_id.nap.id, bsinfo.napid, TLV_L(T_NAP_ID));
+	memcpy(wm->ho_comp.net_id.bs.id, bsinfo.bsid, TLV_L(T_BSID));
+
+	if (wm->ho_comp.status == wm_connect_success) {
+		wm->conn_comp.status = wm_connect_success;
+		memcpy(wm->conn_comp.net_id.nsp.id, bsinfo.nspid, TLV_L(T_V_NSPID));
+		memcpy(wm->conn_comp.net_id.nap.id, bsinfo.napid, TLV_L(T_NAP_ID));
+		memcpy(wm->conn_comp.net_id.bs.id, bsinfo.bsid, TLV_L(T_BSID));
+	}
+
+out:
+	xfunc_out();
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+int nds_connection_stage(int dev_idx, u8 *buf, int len)
+{
+	char *stage_str = "Unknown";
+	u8 stage = buf[0];
+	u8 start_complete = buf[1];
+	fsm_event_t event = 0;
+	int ret = 0;
+
+	switch (stage) {
+		case S_RNG:
+			stage_str = STR(S_RNG);
+			if (start_complete == S_START)
+				event = NC_RangingStart;
+			else
+				event = NC_RangingComplete;
+			break;
+		case S_SBC:
+			stage_str = STR(S_SBC);
+			#if 1
+			if (start_complete == S_START)
+				event = NC_SbcStart;
+			else
+				event = NC_SbcComplete;
+			#endif
+			break;
+		case S_PKM:
+			stage_str = STR(S_PKM);
+			if (start_complete == S_START)
+				event = NC_AuthStart;
+			else
+				event = NC_AuthComplete;
+			break;
+		case S_REG:
+			stage_str = STR(S_REG);
+			if (start_complete == S_START)
+				event = NC_RegStart;
+			else
+				event = NC_RegComplete;
+			break;
+		case S_DSX:
+			#if 1
+			stage_str = STR(S_DSX);
+			if (start_complete == S_START)
+				event = NC_DsxStart;
+			else
+				event = NC_DsxComplete;
+			#endif
+			break;
+	}
+
+	xprintf(SDK_DBG, "Connecting %s(%s)\n",
+		stage_str, start_complete==S_START ? "Start" : "Complete");
+
+	if (event)
+		sdk_ind_event(dev_idx, event);
+	return ret;
+}
diff --git a/sdk/nds.h b/sdk/nds.h
new file mode 100644
index 0000000..74d8f9b
--- /dev/null
+++ b/sdk/nds.h
@@ -0,0 +1,24 @@
+// 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.
+
+#if !defined(NDS_H_20080710)
+#define NDS_H_20080710
+#include "global.h"
+
+void nds_init(int dev_idx);
+void nds_deinit(int dev_idx);
+int nds_req_scan(int dev_idx, u8 scan_type, u8 *home_nsp_id, u8 *usr_home_nai);
+void nds_clean_scan_list(struct wimax_s *wm);
+int nds_update_scan_result(int dev_idx, u8 *buf, int len);
+int nds_connect_complete(int dev_idx, u8 *buf, int len);
+int nds_associate_start(int dev_idx, u8 *buf, int len);
+int nds_associate_complete(int dev_idx, u8 *buf, int len);
+int nds_disconnect_ind(int dev_idx, u8 *buf, int len);
+int nds_ho_start(int dev_idx, u8 *buf, int len);
+int nds_ho_complete(int dev_idx, u8 *buf, int len);
+int nds_connection_stage(int dev_idx, u8 *buf, int len);
+#if defined(CONFIG_ENABLE_BW_SWITCHING_FOR_KT)
+void nds_update_switching_bw(int dev_idx);
+#endif
+#endif
diff --git a/sdk/netlink_u.c b/sdk/netlink_u.c
new file mode 100644
index 0000000..d5e019a
--- /dev/null
+++ b/sdk/netlink_u.c
@@ -0,0 +1,162 @@
+// 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 <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
+#include <linux/types.h>
+#endif
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include "netlink_u.h"
+
+#if !defined(NLMSG_HDRLEN)
+#define NLMSG_HDRLEN	 ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#endif
+
+#define ND_MAX_GROUP			30
+#define ND_IFINDEX_LEN			sizeof(int)
+#define ND_NLMSG_SPACE(len)		(NLMSG_SPACE(len) + ND_IFINDEX_LEN)
+#define ND_NLMSG_DATA(nlh)		((void *)((char *)NLMSG_DATA(nlh) + ND_IFINDEX_LEN))
+#define ND_NLMSG_S_LEN(len)		(len+ND_IFINDEX_LEN)
+#define ND_NLMSG_R_LEN(nlh)		(nlh->nlmsg_len-ND_IFINDEX_LEN)
+#define ND_NLMSG_IFIDX(nlh)		NLMSG_DATA(nlh)
+#define ND_MAX_MSG_LEN			8096
+
+int nl_open(hnetlink_t *hnl, int unit, int ifindex, unsigned int group)
+{
+	struct sockaddr_nl nladdr;
+	int fd;
+
+	if (group > ND_MAX_GROUP) {
+		fprintf(stderr, "ERROR: Group %d is invalied.\n", group);
+		fprintf(stderr, "ERROR: Valid group is 0 ~ %d.\n", ND_MAX_GROUP);
+		return -1;
+	}
+
+	fd = socket(AF_NETLINK, SOCK_RAW, unit);
+	if (fd < 0) {
+		fprintf(stderr, "ERROR: Cannot open netlink socket(%d). %s(%d)\n",
+			unit, strerror(errno), errno);
+		return -1;
+	}
+
+	memset(&nladdr, 0, sizeof(nladdr));
+	nladdr.nl_family = AF_NETLINK;
+	nladdr.nl_pid = 0;   /* For Linux Kernel */
+	nladdr.nl_groups = 1;	/*For Multicase*/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
+	nladdr.nl_groups = group+1;
+#else
+	nladdr.nl_groups = 1 << group;
+#endif
+
+	if (bind(fd, (struct sockaddr *)&nladdr, sizeof(nladdr)) < 0) {
+		fprintf(stderr, "ERROR: Cannot bind netlink socket. %s(%d)\n", strerror(errno), errno);
+		close(fd);
+		return -1;
+	}
+
+	hnl->fd = fd;
+	hnl->ifindex = ifindex;
+	return 0;
+}
+
+int nl_close(hnetlink_t *hnl)
+{
+	if (!hnl) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	close(hnl->fd);
+	memset(hnl, 0, sizeof(hnetlink_t));
+	return 0;
+}
+
+int nl_send(hnetlink_t *hnl, unsigned short type, void *buf, int len)
+{
+	struct nlmsghdr *nlh;
+	struct sockaddr_nl nladdr;
+	struct iovec iov;
+	struct msghdr msg = {(void *)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0};
+	int fd, ret = -1;
+
+	if (!hnl || !buf || !len) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	fd = hnl->fd;
+
+	if (ND_NLMSG_SPACE(len) > ND_MAX_MSG_LEN) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	nlh = (struct nlmsghdr *) malloc(ND_NLMSG_SPACE(len));
+ 	nlh->nlmsg_len = ND_NLMSG_S_LEN(len);
+	nlh->nlmsg_flags = 0;
+	nlh->nlmsg_type = type;
+	nlh->nlmsg_pid = 0;
+	memcpy(ND_NLMSG_IFIDX(nlh), &hnl->ifindex, ND_IFINDEX_LEN);
+	memcpy(ND_NLMSG_DATA(nlh), buf, len);
+
+ 	iov.iov_base = (void *) nlh;
+	iov.iov_len = ND_NLMSG_SPACE(len);
+
+	memset(&nladdr, 0, sizeof(nladdr));
+	nladdr.nl_family = AF_NETLINK;
+
+	ret = sendmsg(fd, &msg, 0);
+
+	free(nlh);
+
+	if (ret <= 0)
+		return -1;
+
+	return len;
+}
+
+int nl_recv(hnetlink_t *hnl, char *buf, int len, int flags)
+{
+	struct nlmsghdr *nlh;
+	struct sockaddr_nl nladdr;
+	struct iovec iov;
+	struct msghdr msg = {(void *)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0};
+	int fd, ret;
+
+	if (!hnl || !buf || !len) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	fd = hnl->fd;
+
+	nlh = (struct nlmsghdr *) malloc(NLMSG_SPACE(len));
+	memset(nlh, 0, NLMSG_SPACE(len));
+
+	iov.iov_base = (void *)nlh;
+	iov.iov_len = NLMSG_SPACE(len);
+
+	memset(&nladdr, 0, sizeof(nladdr));
+	nladdr.nl_family = AF_NETLINK;
+
+	ret = recvmsg(fd, &msg, flags);
+
+	if (ret > 0) {
+		ret = nlh->nlmsg_len - NLMSG_HDRLEN;
+		memcpy(buf, NLMSG_DATA(nlh), ret);
+	}
+
+	free(nlh);
+	return ret;
+}
diff --git a/sdk/netlink_u.h b/sdk/netlink_u.h
new file mode 100644
index 0000000..7cdd443
--- /dev/null
+++ b/sdk/netlink_u.h
@@ -0,0 +1,19 @@
+// 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.
+
+#if !defined(NETLINK_U_H_20081203)
+#define NETLINK_U_H_20081203
+
+typedef struct hnetlink_s {
+	int fd;
+	int ifindex;
+
+} hnetlink_t;
+
+int nl_open(hnetlink_t *hnl, int unit, int ifindex, unsigned int group);
+int nl_close(hnetlink_t *hnl);
+int nl_send(hnetlink_t *hnl, unsigned short type, void *buf, int len);
+int nl_recv(hnetlink_t *hnl, char *buf, int len, int flags);
+
+#endif
diff --git a/sdk/pthread_sem.c b/sdk/pthread_sem.c
new file mode 100644
index 0000000..3e8de9e
--- /dev/null
+++ b/sdk/pthread_sem.c
@@ -0,0 +1,94 @@
+// 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 "pthread_sem.h"
+#include <sys/time.h>
+
+static struct timespec *get_timespec(struct timespec *ts, int timeout_sec)
+{
+	#define ps_timeval2timespec(tv,ts)	\
+		((ts)->tv_sec = (tv)->tv_sec, (ts)->tv_nsec = (tv)->tv_usec * 1000)
+	struct timeval tv;
+
+	gettimeofday(&tv, NULL);
+	ps_timeval2timespec(&tv, ts);
+	ts->tv_sec += timeout_sec;
+	return ts;
+}
+
+int pthread_sem_init(pthread_sem_t *psem, int count)
+{
+	int ret = 0;
+
+	psem->ps_count = count;
+
+	ret = pthread_mutex_init(&psem->ps_lock, NULL);
+	ret |= pthread_cond_init(&psem->ps_cond, NULL);
+
+	return ret;
+}
+
+int pthread_sem_destroy(pthread_sem_t *psem)
+{
+	int ret = 0;
+
+	psem->ps_count = 0;
+
+	ret = pthread_mutex_destroy(&psem->ps_lock);
+	ret |= pthread_cond_destroy(&psem->ps_cond);
+
+	return ret;
+}
+
+int pthread_sem_wait(pthread_sem_t *psem)
+{
+	int ret = 0;
+
+	pthread_mutex_lock(&psem->ps_lock);
+
+	if (--psem->ps_count < 0)
+		ret = pthread_cond_wait(&psem->ps_cond, &psem->ps_lock);
+
+	pthread_mutex_unlock(&psem->ps_lock);
+
+	return ret;
+}
+
+int pthread_sem_timedwait(pthread_sem_t *psem, int timeout_sec)
+{
+	struct timespec ts;
+	int ret = 0;
+
+	pthread_mutex_lock(&psem->ps_lock);
+
+	if (--psem->ps_count < 0) {
+		if (timeout_sec) {
+			get_timespec(&ts, timeout_sec);
+			ret = pthread_cond_timedwait(&psem->ps_cond, &psem->ps_lock, &ts);
+		}
+		else
+			ret = pthread_cond_wait(&psem->ps_cond, &psem->ps_lock);
+	}
+
+	pthread_mutex_unlock(&psem->ps_lock);
+
+	return ret;
+}
+
+int pthread_sem_signal(pthread_sem_t *psem)
+{
+	int ret = 0;
+
+	pthread_mutex_lock(&psem->ps_lock);
+
+	if (psem->ps_count++ < 0) {
+		pthread_mutex_unlock(&psem->ps_lock);
+		ret = pthread_cond_signal(&psem->ps_cond);
+	}
+	else
+		pthread_mutex_unlock(&psem->ps_lock);
+
+	return ret;
+}
+
diff --git a/sdk/pthread_sem.h b/sdk/pthread_sem.h
new file mode 100644
index 0000000..2e416aa
--- /dev/null
+++ b/sdk/pthread_sem.h
@@ -0,0 +1,23 @@
+// 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.
+
+#if !defined(PTHREAD_SEM_H_20081208)
+#define PTHREAD_SEM_H_20081208
+
+#include <pthread.h>
+
+typedef struct pthread_sem_s {
+	int ps_count;
+	pthread_mutex_t	ps_lock;
+	pthread_cond_t	ps_cond;
+
+} pthread_sem_t;
+
+int pthread_sem_init(pthread_sem_t *psem, int count);
+int pthread_sem_destroy(pthread_sem_t *psem);
+int pthread_sem_wait(pthread_sem_t *psem);
+int pthread_sem_timedwait(pthread_sem_t *psem, int timeout_sec);
+int pthread_sem_signal(pthread_sem_t *psem);
+
+#endif
diff --git a/sdk/sdk.c b/sdk/sdk.c
new file mode 100644
index 0000000..4c6f1b4
--- /dev/null
+++ b/sdk/sdk.c
@@ -0,0 +1,2902 @@
+// 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 "global.h"
+#include "wm_ioctl.h"
+#include "error.h"
+#include "handle.h"
+#include "sdk.h"
+#include "wimax.h"
+#include "nds.h"
+#include "device.h"
+#include "io.h"
+#include "fload.h"
+#include "hci.h"
+#include "log.h"
+#if defined(CONFIG_ENABLE_SERVICE_FLOW)
+#include "sf.h"
+extern void dev_update_service_flow(int dev_idx, struct hci *pkt);
+#endif // CONFIG_ENABLE_SERVICE_FLOW
+#include "eap.h"
+
+#define LOG_FILE_PREFIX		"sdk"
+#define LOG_FILE_EXT		"log"
+#define LOG_FILE			"sdk.log"
+#define LOCK_PATH			"/var/lock/gct/"
+#define LOCK_FILE			LOCK_PATH "gct_sdk.lock"
+
+sdk_mng_t sdk_mng;
+
+extern void array_DB2H(u32 *arr, int n);
+extern void array_B2H(u16 *arr, int n);
+
+int sdk_on_ind_event(sdk_internal_t *sdk, int dev_idx, fsm_event_t event);
+int sdk_on_app_event(sdk_internal_t *sdk, int dev_idx, fsm_event_t event);
+static int sdk_set_ioctl_profile_id(int dev_idx, u32 profile_id);
+
+const char *sdk_version(void)
+{
+	return SDK_VERSION;
+}
+
+static int sdk_check_lock_file(void)
+{
+	int fd;
+
+	if (access(LOCK_PATH, F_OK))
+		mkdir(LOCK_PATH, 0755);
+	if (access(LOCK_FILE, F_OK) < 0) {
+		if ((fd = open(LOCK_FILE, O_CREAT|O_WRONLY|O_TRUNC, 0755)) < 0) {
+			xprintf(SDK_STD_ERR, "Creating fail(%s)\n", LOCK_FILE);
+			return -1;
+		}
+		close(fd);
+		return 0;
+	}
+	xprintf(SDK_STD_ERR, "API is locked.(%s)\n", LOCK_FILE);
+	return -1;
+}
+
+static int sdk_delete_lock_file(void)
+{
+	xprintf(SDK_DBG, "unlink %s\n", LOCK_FILE);
+	return unlink(LOCK_FILE);
+}
+
+static void sdk_init_seed(void)
+{
+	struct timeval now;
+
+	gettimeofday(&now, NULL);
+	srand(now.tv_sec+now.tv_usec);
+}
+
+sdk_internal_t *sdk_get_rw_handle(void)
+{
+	struct list_head *head = hand_get_api_handle_list();
+	api_hand_t *handle;
+	sdk_internal_t *ret = NULL;
+
+	pthread_mutex_lock(&api_handle_lock);
+	list_for_each_entry(handle, head, list) {
+		if (!handle->sdk->ro) {
+			ret = handle->sdk;
+			break;
+		}
+	}
+	pthread_mutex_unlock(&api_handle_lock);
+	return ret;
+}
+
+static void sdk_set_logpath(char *buf, const char *dir)
+{
+	time_t t;
+	struct tm *tms;
+	char time_buf[256];
+
+	time(&t);
+	tms = localtime(&t);
+
+	sprintf(time_buf, "%04d%02d%02d-%02d.%02d.%02d", 
+		tms->tm_year+1900, tms->tm_mon+1, tms->tm_mday,
+		tms->tm_hour, tms->tm_min, tms->tm_sec);
+	
+	sprintf(buf, "%s/%s_%s.%s", dir, LOG_FILE_PREFIX, time_buf, LOG_FILE_EXT);
+}
+
+static void path_trim(char *path)
+{
+	int len;
+	len = strlen(path) - 1/*move to last char*/;
+	while (path[len] == '/' || path[len] == '\\')
+		path[len--] = 0;
+}
+
+int sdk_init(GCT_WIMAX_SDK_MODE mode, GCT_WIMAX_API_PARAM *sdk_param)
+{
+	int log_level;
+	char log_file[512];
+	int ret;
+
+	assert(sizeof(struct wm_req_s) <= sizeof(struct ifreq));
+	assert(SIOC_DATA_END <= SIOC_DATA_MAX);
+
+	if (sdk_param) {
+		strcpy(sdk_mng.nonvolatile_dir, sdk_param->nonvolatile_dir);
+		strcpy(sdk_mng.log_path, sdk_param->log_path);
+		path_trim(sdk_mng.nonvolatile_dir);
+		path_trim(sdk_mng.log_path);
+		log_level = sdk_param->log_level;
+	}
+	else {
+		strcpy(sdk_mng.nonvolatile_dir, "./");
+		strcpy(sdk_mng.log_path, "./sdklog");
+		log_level = 1;
+	}
+
+	if (mode & GCT_WIMAX_SDK_EMBEDDED_EAP_ENABLED)
+		sdk_mng.eeap_enabled = TRUE;
+	if (mode & GCT_WIMAX_SDK_OMA_DM_ENABLED)
+		sdk_mng.odm_enabled = TRUE;
+
+	sdk_init_seed();
+
+	if ((ret = mkdir(sdk_mng.log_path, 0644)) < 0 && errno != EEXIST) {
+		fprintf(stderr, "Make directory(%s) failed %s(%d)\n",
+			sdk_mng.log_path, strerror(errno), errno);
+	}
+
+	sdk_set_logpath(log_file, sdk_mng.log_path);
+	
+	#if defined(SDK_TEST)
+	unlink(LOG_FILE);
+	strcpy(log_file, LOG_FILE);
+	printf("####################################################\n");
+	printf("############## NOTE: SDK_TEST Enabled ##############\n");
+	printf("############## LOG FILE PATH: %s ##############\n", log_file);
+	printf("####################################################\n");
+	#endif
+
+	timer_module_init();
+	log_init(log_file, log_level);
+	hand_init();
+
+	ret = dm_init();
+	
+	hci_receiver_create(&sdk_mng.hci_recvr);
+
+	return ret;
+}
+
+int sdk_deinit(void)
+{
+	int ret;
+
+	hci_receiver_delete(&sdk_mng.hci_recvr);
+
+	ret = dm_deinit();
+	log_deinit();
+	hand_deinit();
+ 	timer_module_deinit();
+ 
+ 	if (sdk_get_rw_handle())
+ 		sdk_delete_lock_file();
+
+	return ret;
+}
+
+int sdk_check_handle(api_hand_t *api_hand, int dev_idx)
+{
+	api_hand_t *api = api_hand;
+	sdk_internal_t *sdk = api->sdk;
+	int ret = 0;
+
+	if (api_hand == NULL) {
+		xprintf(SDK_ERR, "API handle is NULL\n", api_hand);
+		ret = sdk_set_errno(ERR_INVALID);
+		goto out;
+	}
+	if (sdk->struct_size != sizeof(sdk_internal_t)) {
+		xprintf(SDK_ERR, "Wrong structure size(%d!=%d)\n", sdk->struct_size, sizeof(api_hand_t));
+		ret = sdk_set_errno(ERR_INVALID);
+		goto out;
+	}
+	if (NO_DEV != dev_idx) {
+		if (dev_idx < DEV_BASE_IDX || dev_idx >= MAX_DEVICE) {
+			xprintf(SDK_ERR, "Device index %d is wrong\n", dev_idx);
+			ret = sdk_set_errno(ERR_INVALID_DEV);
+			goto out;
+		}
+		if (!sdk->dev_open[dev_idx]) {
+			xprintf(SDK_ERR, "Device(%d) was not opened!\n", dev_idx);
+			ret = sdk_set_errno(ERR_INVALID);
+			goto out;
+		}
+		if (!dm_tst_dev(dev_idx)) {
+			xprintf(SDK_ERR, "Device(%d) was not inserted!\n", dev_idx);
+			ret = sdk_set_errno(ERR_INVALID_DEV);
+			goto out;
+		}
+	}
+
+out:
+	return ret;
+}
+
+void *sdk_ind_thread(void *sdk_ptr)
+{
+	sdk_internal_t *sdk = (sdk_internal_t *) sdk_ptr;
+	int prim;
+	ind_msg_t *msg;
+	dev_hand_t dev_hand;
+	bool dev_opened;
+	SDKIndRcvHCIPacket				recv_hci;
+	SDKIndDeviceInsertRemove		insert_remove;
+	SDKIndControlPowerManagement	pow_mng;
+	SDKIndDeviceStatusUpdate		stat_update;
+	SDKIndConnectToNetwork			connect_net;
+	SDKIndDisconnectFromNetwork		disconnect_net;
+	SDKIndNetworkSearchWideScan		net_search_wscan;
+	SDKIndProvisioningOperation		provisioning;
+	SDKIndPackageUpdate				package_update;
+	SDKIndNotification				notification;
+	SDKIndModeChange				power_mode;
+
+	dev_hand.api = sdk->api;
+
+	xfunc_in();
+
+	while (1) {
+		if (msg_recv(&sdk->ind.msg_cb, &prim, (void **)&msg) < 0) {
+			xprintf(SDK_ERR, "msg_recv error\n");
+			break;
+		}
+		if (msg == THREAD_EXIT_MSG) {
+			xprintf(SDK_INFO, "%s thread exit...\n", __FUNCTION__);
+			break;
+		}
+		dev_hand.dev_idx = msg->dev_idx;
+		dev_opened = sdk->dev_open[msg->dev_idx] && dm_tst_dev(msg->dev_idx);
+
+		xprintf(SDK_DBG, "recv ind msg: prim=%d, dev_opened=%d\n", prim, dev_opened);
+
+		switch (prim) {
+			case ind_recv_hci:
+				recv_hci = sdk->ind.recv_hci;
+				if (dev_opened && recv_hci)
+					recv_hci(&dev_hand, msg->u.recv_hci.buf, msg->u.recv_hci.len);
+				sdk_free(msg->u.recv_hci.buf);
+				break;
+			case ind_insert_remove:
+				insert_remove =  sdk->ind.insert_remove;
+				if (insert_remove)
+					insert_remove(&dev_hand, msg->u.insert_remove.presence);
+				break;
+			case ind_pow_mng:
+				pow_mng =  sdk->ind.pow_mng;
+				if (dev_opened && pow_mng)
+					pow_mng(&dev_hand, msg->u.pow_mng.state);
+				break;
+			case ind_stat_update:
+				stat_update = sdk->ind.stat_update;
+				if (dev_opened && stat_update)
+					stat_update(&dev_hand, msg->u.stat_update.device_status,
+						msg->u.stat_update.status_reason, msg->u.stat_update.progress_info);
+				break;
+			case ind_connect_net:
+				connect_net =  sdk->ind.connect_net;
+				if (dev_opened && connect_net)
+					connect_net(&dev_hand, msg->u.connect_net.response);
+				break;
+			case ind_disconnect_net:
+				disconnect_net =  sdk->ind.disconnect_net;
+				if (dev_opened && disconnect_net)
+					disconnect_net(&dev_hand, msg->u.disconnect_net.response);
+				break;
+			case ind_net_search_wscan:
+				net_search_wscan =  sdk->ind.net_search_wscan;
+				if (dev_opened && net_search_wscan)
+					net_search_wscan(&dev_hand,
+						msg->u.net_search_wscan.nsp_list, msg->u.net_search_wscan.list_cnt);
+				break;
+			case ind_provisioning:
+				provisioning =  sdk->ind.provisioning;
+				if (dev_opened && provisioning)
+					provisioning(&dev_hand,
+						msg->u.provisioning.operation, msg->u.provisioning.contact_type);
+				break;
+			case ind_package_update:
+				package_update =  sdk->ind.package_update;
+				if (dev_opened && package_update)
+					package_update(&dev_hand, msg->u.package_update.update);
+				break;
+			case ind_notification:
+				notification =  sdk->ind.notification;
+				if (dev_opened && notification)
+					notification(&dev_hand,
+						msg->u.notification.category, msg->u.notification.type,
+						msg->u.notification.buf_len, msg->u.notification.buf);
+				break;
+			case ind_mode_change:
+				power_mode =  sdk->ind.power_mode;
+				if (dev_opened && power_mode)
+					power_mode(&dev_hand, msg->u.power_mode.power_mode);
+				break;
+			default:
+				break;
+		}
+
+		sdk_free(msg);
+	}
+
+	msg_deinit(&sdk->ind.msg_cb);
+	xprintf(SDK_INFO, "Exit sdk-ind-thread\n");
+
+	xfunc_out();
+	return NULL;
+}
+
+void sdk_init_ind(sdk_internal_t *sdk)
+{
+	msg_init(&sdk->ind.msg_cb);
+	pthread_create(&sdk->ind.thread, NULL, sdk_ind_thread, sdk);
+}
+
+void sdk_deinit_ind(sdk_internal_t *sdk)
+{
+	pthread_t thread;
+
+	xfunc_in("thread=0x%08X", (int) sdk->ind.thread);
+
+	if ((thread = sdk->ind.thread)) {
+		sdk->ind.thread = (pthread_t) NULL;
+		msg_send(&sdk->ind.msg_cb, 0, THREAD_EXIT_MSG);
+		pthread_join(thread, NULL);
+	}
+
+	xfunc_out();
+}
+
+api_hand_t *sdk_api_open(int mode)
+{
+	api_hand_t *api_hand = NULL;;
+	sdk_internal_t *sdk;
+	int ro = mode & sdk_read_only;
+
+	xfunc_in("mode=0x%X", mode);
+
+	if (!ro && (sdk_check_lock_file() < 0)) {
+		sdk_set_errno(ERR_PERM);
+		goto out;
+	}
+
+	api_hand = hand_alloc_api();
+	if (api_hand) {
+		sdk = api_hand->sdk = (sdk_internal_t *) sdk_malloc(sizeof(sdk_internal_t));
+		assert(sdk != NULL);
+		memset(sdk, 0, sizeof(sdk_internal_t));
+		sdk->struct_size = sizeof(sdk_internal_t);
+		sdk->api = api_hand;
+		sdk->ro = ro;
+		sdk->mode = mode;
+		sdk_init_ind(sdk);
+
+	}
+out:
+	xfunc_out("api_hand=0x%08X", api_hand);
+	return api_hand;
+}
+
+int sdk_api_close(api_hand_t *api_hand)
+{
+	sdk_internal_t *sdk = api_hand->sdk;
+	int ret, i;
+
+	xfunc_in();
+
+	if (sdk_check_handle(api_hand, NO_DEV) < 0)
+		return -1;
+
+	for (i = 1; i < MAX_DEVICE; i++) {
+		if (sdk->dev_open[i]) {
+			ret = sdk_device_close(api_hand, i);
+			xprintf(SDK_DBG, "device(%d) has been closed with %d.\n", i, ret);
+		}
+	}
+
+	if (!sdk->ro)
+		sdk_delete_lock_file();
+
+	sdk_deinit_ind(sdk);
+
+	ret = hand_free_api(api_hand);
+	sdk_free(sdk);
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_debug_level(api_hand_t *api_hand, int level)
+{
+	int ret;
+
+	xfunc_in();
+
+	if (sdk_check_handle(api_hand, NO_DEV) < 0)
+		ret = -1;
+	else
+		ret = log_set_level(level);
+
+	xfunc_out();
+	return ret;
+}
+
+int sdk_print_log(api_hand_t *api_hand, int flag, const char *title, const char *str)
+{
+	int ret;
+
+	if (sdk_check_handle(api_hand, NO_DEV) < 0)
+		ret = -1;
+	else
+		ret = log_printf_string(SDK_API_LOG, flag, title, str);
+	return ret;
+}
+
+int sdk_get_device_list(api_hand_t *api_hand, WIMAX_API_HW_DEVICE_ID *dev_list,
+		u32 *list_cnt)
+{
+	dev_mng_t *dm = dm_get_dev_mng();
+	int cnt = 0, i;
+
+	xfunc_in("list_cnt=%d", *list_cnt);
+	
+	if (sdk_check_handle(api_hand, NO_DEV) < 0)
+		return -1;
+
+	pthread_mutex_lock(&dm->detect_lock);
+	for (i = DEV_BASE_IDX; i < MAX_DEVICE; i++) {
+		if (dm->devices[i] && dm->devices[i]->inserted) {
+			if (cnt >= *list_cnt)
+				break;
+			dev_list[cnt].deviceIndex = i;
+			mbstowcs((wchar_t *)dev_list[cnt].deviceName, dm->devices[i]->name,
+				strlen(dm->devices[i]->name)+1);
+			dev_list[cnt].deviceType = WIMAX_API_DEV_TYPE_WIMAX;
+			cnt++;
+		}
+		if (cnt == dm->dev_cnt)
+			break;
+	}
+	*list_cnt = cnt;
+	pthread_mutex_unlock(&dm->detect_lock);
+
+	xfunc_out("list_cnt=%d", *list_cnt);
+	return 0;
+}
+
+int sdk_device_open(api_hand_t *api_hand, int dev_idx)
+{
+	sdk_internal_t *sdk = api_hand->sdk;
+	device_t *dev;
+	int ret;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, NO_DEV) < 0)
+		return -1;
+	if (dev_idx < DEV_BASE_IDX || dev_idx >= MAX_DEVICE)
+		return sdk_set_errno(ERR_INVALID_DEV);
+
+	ret = dm_open_device(dev_idx);
+
+	if (!ret) {
+		if (!(dev = dm_get_dev(dev_idx)))
+			goto out;
+
+		sdk->dev_open[dev_idx] = TRUE;
+
+		if (dev->open_cnt == 1) {
+			if (!sdk->ro) {
+				ret = wm_set_capability(dev_idx, DEFAULT_CAPABILITY);
+				if (ret < 0)
+					goto put;
+			}
+
+			ret = wm_init_device_info(dev_idx);
+			if (ret < 0)
+				goto put;
+
+			if (!sdk->ro) {
+#if defined(CONFIG_ENABLE_SERVICE_FLOW)
+				sf_init(dev_idx);
+#endif // CONFIG_ENABLE_SERVICE_FLOW
+				ret = wm_set_eap(dev_idx, FALSE);
+				if (ret < 0)
+					goto put;
+
+				wm_init_scan(dev_idx);
+
+				if (!api_hand->sdk->ro)
+					dm_set_status(dev_idx, M_INIT, C_INIT);
+
+				ret = wm_set_run_mode(dev_idx, sdk->mode);
+				if (ret < 0)
+					goto put;
+			}
+		}
+
+		ret = sdk_on_app_event(sdk, dev_idx, AM_Open);
+put:
+		if (ret < 0)
+			sdk->dev_open[dev_idx] = FALSE;
+		dm_put_dev(dev_idx);
+	}
+out:
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_internal_device_close(struct sdk_internal_s *sdk, int dev_idx)
+{
+	int ret = 1;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk->dev_open[dev_idx]) {
+		if (!sdk->ro) {
+			wm_deinit_scan(dev_idx);
+#if defined(CONFIG_ENABLE_SERVICE_FLOW)
+			sf_deinit(dev_idx);
+#endif // CONFIG_ENABLE_SERVICE_FLOW
+		}
+
+		sdk_on_app_event(sdk, dev_idx, AM_Close);
+		sdk->dev_open[dev_idx] = FALSE;
+
+		ret = dm_close_device(dev_idx);
+	}
+
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_device_close(api_hand_t *api_hand, int dev_idx)
+{
+	int ret = 0;
+
+	xfunc_in("dev=%d", dev_idx);
+
+
+	if (api_hand && api_hand->sdk && !api_hand->sdk->dev_open[dev_idx]) {
+		xprintf(SDK_DBG, "device(%d) has been closed or was not opened!\n");
+		goto out;
+	}
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	ret = sdk_internal_device_close(api_hand->sdk, dev_idx);
+out:
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_get_status(sdk_internal_t *sdk, int dev_idx, int *m_status, int *c_status)
+{
+	device_t *dev;
+	int ret = 0;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	if (sdk && sdk->ro)
+		ret = dm_get_status(dev_idx, m_status, c_status);
+	else {
+		*m_status = dev->fsm.m_status;
+		*c_status = dev->fsm.c_status;
+	}
+
+	dm_put_dev(dev_idx);
+	xfunc_out("m_status=%d, c_status=%d", *m_status, *c_status);
+	return ret;
+}
+
+int sdk_set_status(sdk_internal_t *sdk, int dev_idx, int m_status, int c_status)
+{
+	device_t *dev;
+	int ret = 0;
+	fsm_t fsm;
+
+	xfunc_in("dev=%d, m_status=%d, c_status=%d", dev_idx, m_status, c_status);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	if (!sdk || !sdk->ro) {
+		fsm = dev->fsm;
+		dev->fsm.m_status = m_status;
+		dev->fsm.c_status = c_status;
+
+		ret = dm_set_status(dev_idx, m_status, c_status);
+
+		if (!ret) {
+			if (m_status == M_CONNECTED)
+				net_updown(dev_idx, TRUE);
+			else if (fsm.m_status == M_CONNECTED)
+				net_updown(dev_idx, FALSE);
+		}
+	}
+
+	dm_put_dev(dev_idx);
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_convert_status(int dev_idx, WIMAX_API_DEVICE_STATUS_P status,
+						WIMAX_API_CONNECTION_PROGRESS_INFO_P connect_prog_info,
+						int m_status, int c_status)
+{
+	/*
+		return value
+		0:	ok. Status-Indication is called.
+		1:	ok. Status-Indication is NOT called.
+		-1:	error.
+	*/
+	int ret = 0;
+
+	if ((u32)m_status >= M_FSM_END || (u32)c_status >= C_FSM_END) {
+		xprintf(SDK_ERR, "Unknown status: m_s=%d, c_s=%d\n", m_status, c_status);
+		return sdk_set_errno(ERR_UNKNOWN_STAT);
+	}
+
+	switch(m_status) {
+		case M_INIT:
+			*status = WIMAX_API_DEVICE_STATUS_UnInitialized;
+			break;
+		case M_OPEN_OFF:
+			*status = WIMAX_API_DEVICE_STATUS_RF_OFF_HW_SW;
+			break;
+		case M_OPEN_ON:
+			*status = WIMAX_API_DEVICE_STATUS_Ready;
+			break;
+		case M_SCAN:
+			*status = WIMAX_API_DEVICE_STATUS_Scanning;
+			break;
+		case M_CONNECTING:
+			*status = WIMAX_API_DEVICE_STATUS_Connecting;
+			switch(c_status) {
+				case C_INIT:
+					*connect_prog_info = WIMAX_API_DEVICE_CONNECTION_PROGRESS_Ranging;
+					ret = 1;
+					break;
+				case C_CONNSTART:
+					*connect_prog_info = WIMAX_API_DEVICE_CONNECTION_PROGRESS_Ranging;
+					break;
+				case C_ASSOCSTART:
+					*connect_prog_info = WIMAX_API_DEVICE_CONNECTION_PROGRESS_Ranging;
+					ret = 1;
+					break;
+				case C_RNG:
+					*connect_prog_info = WIMAX_API_DEVICE_CONNECTION_PROGRESS_Ranging;
+					ret = 1;
+					break;
+				case C_SBC:
+					*connect_prog_info = WIMAX_API_DEVICE_CONNECTION_PROGRESS_SBC;
+					break;
+				case C_AUTH:
+					*connect_prog_info = WIMAX_API_DEVICE_CONNECTION_PROGRESS_EAP_authentication_User;
+					break;
+				case C_REG:
+					*connect_prog_info = WIMAX_API_DEVICE_CONNECTION_PROGRESS_Registration;
+					break;
+				case C_DSX:
+					*connect_prog_info = WIMAX_API_DEVICE_CONNECTION_PROGRESS_Registration_DSX;
+					break;
+				case C_ASSOCCOMPLETE:
+					*connect_prog_info = WIMAX_API_DEVICE_CONNECTION_PROGRESS_Registered;
+					ret = 1;
+					break;
+				case C_CONNCOMPLETE:
+					*connect_prog_info = WIMAX_API_DEVICE_CONNECTION_PROGRESS_Registered;
+					break;
+				default:
+					ret = -1;
+					break;
+			}
+			break;
+		case M_CONNECTED:
+			*status = WIMAX_API_DEVICE_STATUS_Data_Connected;
+			break;
+		default:
+			ret = -1;
+			break;
+	}
+	return ret;
+}
+
+int sdk_get_device_status(api_hand_t *api_hand, int dev_idx,
+		WIMAX_API_DEVICE_STATUS_P status,
+		WIMAX_API_CONNECTION_PROGRESS_INFO_P connect_prog_info)
+{
+	int m_status, c_status;
+	int ret;
+
+	xfunc_in();
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	ret = sdk_get_status(api_hand->sdk, dev_idx, &m_status, &c_status);
+	if (!ret) {
+		ret = sdk_convert_status(dev_idx, status, connect_prog_info, m_status, c_status);
+		if (ret >= 0)
+			ret = 0;
+	}
+
+	xfunc_out("ret=%d, m_s=%d, c_s=%d", ret, m_status, c_status);
+	return ret;
+}
+
+static void sdk_hook_writing_hci(int dev_idx, void *buf, int len)
+{
+	hci_t *hci = (hci_t *) buf;
+	hci_image_payload_t *img;
+	unsigned short cmd_evt;
+
+	cmd_evt = B2H(hci->cmd_evt);
+	switch (cmd_evt) {
+		case WIMAX_DL_IMAGE:
+			img = (hci_image_payload_t *) hci->data;
+			switch (B2H(img->type)) {
+				case DLIMG_OMA_XML:
+					if (DB2H(img->offset) == -1/*EOF*/) {
+						xprintf(SDK_DBG, "Hooked HCI(%04x)\n", cmd_evt);
+						wm_sync_subscription(dev_idx);
+					}
+					break;
+			}
+			break;
+	}
+}
+
+int sdk_write_hci_packet(api_hand_t *api_hand, int dev_idx, void *buf, int len)
+{
+	int ret;
+
+	xfunc_in("[%d] len=%d", dev_idx, len);
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	ret = io_send(dev_idx, buf, len);
+	if (ret == len) {
+		sdk_hook_writing_hci(dev_idx, buf, len);
+		ret = 0;
+	}
+	else
+		ret = -1;
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_set_power_control(api_hand_t *api_hand, int dev_idx, rf_stat_t rf_stat)
+{
+	//#define NO_CHECK_POWER_CONTROL
+	sdk_internal_t *sdk = api_hand->sdk;
+	#if !defined(NO_CHECK_POWER_CONTROL)
+	rf_stat_t get_rf_stat;
+	#endif
+	int ret = -1;
+
+	xfunc_in("rf=%s", (rf_stat==rf_on) ? "On" : "Off");
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		goto out;
+
+	if (sdk->ro) {
+		ret = sdk_set_errno(ERR_PERM);
+		goto out;
+	}
+
+	#if defined(NO_CHECK_POWER_CONTROL)
+	ret = wm_set_rf_state(dev_idx, rf_stat, SDK_RF_UPDOWN_RESP_TIMEOUT_SEC);
+	#else
+	ret = wm_get_rf_state(dev_idx, &get_rf_stat);
+
+	if (!ret && get_rf_stat != rf_stat)
+		ret = wm_set_rf_state(dev_idx, rf_stat, SDK_RF_UPDOWN_RESP_TIMEOUT_SEC);
+	#endif
+out:
+	xfunc_out();
+	return ret;
+}
+
+int sdk_get_device_info(api_hand_t *api_hand, int dev_idx,
+		WIMAX_API_DEVICE_INFO_P dev_info)
+{
+	device_t *dev;
+	wimax_t *wm;
+	wm_device_info_t *devi;
+	wm_rev_info_t *rev;
+	char str[256];
+	int ret;
+	u8 *p, *p2;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	wm = dev->wimax;
+	devi = &wm->dev_info;
+	rev = &devi->revision;
+
+	dev_info->structureSize = sizeof(WIMAX_API_DEVICE_INFO);
+
+	dev_info->hwVersion.structureSize = sizeof(WIMAX_API_DEVICE_VERSION);
+	wcscpy((wchar_t *)dev_info->hwVersion.name, L"GCT H/W");
+	p = (u8 *) &rev->phy_hw_ver;
+	ret = sprintf(str, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+	mbstowcs((wchar_t *)dev_info->hwVersion.version, str, ret+1);
+		
+	dev_info->swVersion.structureSize = sizeof(WIMAX_API_DEVICE_VERSION);
+	wcscpy((wchar_t *)dev_info->swVersion.name, L"GCT S/W");
+	p = (u8 *) &rev->rel_ver;
+	p2 = (u8 *) &rev->fw_ver;
+	ret = sprintf(str, "FW(%d.%d.%d.%d : %d.%d.%d.%d)",
+		p[0], p[1], p[2], p[3], p2[0], p2[1], p2[2], p2[3]);
+	mbstowcs((wchar_t *)dev_info->swVersion.version, str, ret+1);
+
+	dev_info->rfVersion.structureSize = sizeof(WIMAX_API_DEVICE_VERSION);
+	wcscpy((wchar_t *)dev_info->rfVersion.name, L"GCT RF");
+	wcscpy((wchar_t *)dev_info->rfVersion.version, (wchar_t *)dev_info->hwVersion.version);
+	dev_info->asicVersion.structureSize = sizeof(WIMAX_API_DEVICE_VERSION);
+	wcscpy((wchar_t *)dev_info->asicVersion.name, L"GCT ASIC");
+	wcscpy((wchar_t *)dev_info->asicVersion.version, (wchar_t *)dev_info->hwVersion.version);
+
+	memcpy(dev_info->macAddress, devi->device_mac, sizeof(devi->device_mac));
+	
+	mbstowcs((wchar_t*)dev_info->vendorName, (char *)devi->vendor_name,
+		strlen((char *)devi->vendor_name)+1);
+	dev_info->vendorSpecificInfoIncl = FALSE;
+	memset(dev_info->vendorSpecificInfo, 0, sizeof(dev_info->vendorSpecificInfo));
+
+	dm_put_dev(dev_idx);
+	xfunc_out();
+	return 0;
+}
+
+int sdk_get_profile_list(api_hand_t *api_hand, int dev_idx,
+		WIMAX_API_PROFILE_INFO_P list, int *list_cnt)
+{
+	device_t *dev;
+	wimax_t *wm;
+	struct list_head *head;
+	wm_subscription_info_t *ss_info;
+	u8 profile_name[MAX_SIZE_OF_STRING_BUFFER];
+	int cnt = 0;
+
+	xfunc_in("dev=%d, list_cnt=%d", dev_idx, *list_cnt);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	wm = dev->wimax;
+	head = &wm->subs_list.head;
+	xprintf(SDK_DBG, "subs_list.cnt=%d\n", wm->subs_list.cnt);
+	list_for_each_entry(ss_info, head, list) {
+		if (cnt >= *list_cnt)
+			break;
+		list[cnt].structureSize = sizeof(WIMAX_API_PROFILE_INFO);
+ 		list[cnt].profileID = U82U24(ss_info->subscription_id.hnspid.id);
+		set_msb(list[cnt].profileID, ss_info->idx);
+		sprintf((char *)profile_name, "%s:%s", 
+			ss_info->subscription_id.user_hnai,
+			ss_info->subscription_id.hnspid.name);
+		mbstowcs((wchar_t*)list[cnt].profileName, (char *)profile_name,
+			strlen((char *)profile_name)+1);
+		cnt++;
+	}
+	*list_cnt = cnt;
+
+	xfunc_out("list_cnt=%d", *list_cnt);
+	dm_put_dev(dev_idx);
+	return 0;
+}
+
+int sdk_set_profile(api_hand_t *api_hand, int dev_idx, u32 profile_id)
+{
+	sdk_internal_t *sdk = api_hand->sdk;
+	device_t *dev;
+	u8 nspid[NSP_ID_SIZE];
+	u8 subs_idx;
+	int ret = 0;
+
+	xfunc_in("dev=%d, profile_id=0x%08x", dev_idx, profile_id);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	if (sdk->ro)
+		return sdk_set_errno(ERR_PERM);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	subs_idx = get_msb(profile_id);
+	U242U8(nspid, profile_id);
+	if (!(dev->wimax->scan.selected_subs = wm_get_subscription(dev_idx, subs_idx, nspid))) {
+		ret = -1;
+		goto out;
+	}
+
+	wm_set_scan_type(dev_idx, wm_scan_curr_subscription);
+
+	ret = sdk_set_ioctl_profile_id(dev_idx, profile_id);
+out:
+	dm_put_dev(dev_idx);
+	xfunc_out();
+	return ret;
+}
+
+int sdk_set_scan_interval(api_hand_t *api_hand, int dev_idx, u32 interval_sec)
+{
+	device_t *dev;
+	int ret;
+
+	xfunc_in("dev=%d, interval=%d", dev_idx, interval_sec);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	if (dev->wimax->scan.selected_subs)
+		wm_set_scan_type(dev_idx, wm_scan_curr_subscription);
+	else
+		wm_set_scan_type(dev_idx, wm_scan_all_subscriptions);
+
+	ret = wm_active_scan_interval(dev_idx, interval_sec);
+
+	dm_put_dev(dev_idx);
+	xfunc_out();
+	return ret;
+}
+
+static void sdk_init_cr801(wimax_t *wm)
+{
+	wm_eap_param_t *eapp;
+
+	eapp = &wm->dev_info.eapp;
+	
+	if (eapp->cr801_enabled)
+		eapp->cr801_mode = CR801_TTLS;
+	else
+		eapp->cr801_mode = CR801_DISABLE;
+	xprintf(SDK_DBG, "cr801_mode=%d\n", eapp->cr801_mode);
+}
+
+int sdk_set_eap(api_hand_t *api_hand, int dev_idx, GCT_API_EAP_PARAM_P eap)
+{
+	sdk_internal_t *sdk = api_hand->sdk;
+	device_t *dev;
+	wm_eap_param_t *eapp;
+	int ret = 0;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	eapp = &dev->wimax->dev_info.eapp;
+	memset(eapp, 0, sizeof(*eapp));
+	eapp->type = eap->type;
+
+	if (eapp->type == GCT_WIMAX_NO_EAP) {
+		if (!sdk->ro)
+			ret = wm_set_eap(dev_idx, FALSE);
+		return ret;
+	}
+
+	assert(GCT_WIMAX_EAP_TLS == W_EAP_TLS);
+
+	if (eap && GCT_API_IS_EAP_TLS(eap->type)) {
+		if (!(eapp->use_nv_info = eap->useNvramParam)) {
+			strcpy(eapp->userid, (char *) eap->userId);
+			strcpy(eapp->userid_pwd, (char *) eap->userIdPwd);
+			strcpy(eapp->anony_id, (char *) eap->anonymousId);
+			strcpy(eapp->pri_key_pwd, (char *) eap->privateKeyPwd);
+		}
+		eapp->frag_size = eap->fragSize;
+		eapp->use_delimiter = eap->useDelimiter;
+		eapp->dev_cert_null = eap->devCertNULL;
+		eapp->ca_cert_null = eap->caCertNULL;
+		eapp->disable_resumptoin = eap->disableResumption;
+		eapp->cr801_enabled = eap->cr801Enable;
+		eapp->disable_sessionticket = eap->disableSessionTicket;
+		strcpy(eapp->decoration[DECORATION_IDX1], (char *) eap->decoration);
+		eapp->log_enabled = eap->logEnable;
+		if (!sdk->ro)
+			eap_prepare_log_env(dev_idx, eapp->log_enabled);
+	}
+	
+	sdk_init_cr801(dev->wimax);
+	
+	if (!sdk->ro)
+		ret = wm_set_eap(dev_idx, TRUE);
+
+	dm_put_dev(dev_idx);
+	xfunc_out();
+	return ret;
+}
+
+int sdk_get_statistics(api_hand_t *api_hand, int dev_idx,
+		WIMAX_API_CONNECTION_STAT_P statistics)
+{
+	wm_net_info_t net_info;
+	int ret;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	ret = wm_get_netinfo(dev_idx, &net_info);
+	if (!ret) {
+		statistics->structureSize = sizeof(WIMAX_API_CONNECTION_STAT);
+		statistics->totalRxByte = net_info.rx_bytes;
+		statistics->totalTxByte = net_info.tx_bytes;
+		statistics->totalRxPackets = net_info.rx_packets;
+		statistics->totalTxPackets = net_info.tx_packets;
+	}
+	xfunc_out();
+	return ret;
+}
+
+int sdk_get_linkstatus(api_hand_t *api_hand, int dev_idx,
+		WIMAX_API_LINK_STATUS_INFO_P link_status)
+{
+	device_t *dev;
+	struct wimax_s *wm;
+	wm_link_status_t link_s;
+	int ret;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	wm = dev->wimax;
+
+	ret = wm_get_linkinfo(dev_idx, &link_s);
+	if (!ret) {
+		link_status->structureSize = sizeof(WIMAX_API_LINK_STATUS_INFO);
+		link_status->centerFrequency = link_s.cur_freq;
+		link_status->RSSI = link_s.rssi;
+		link_status->CINR = link_s.cinr;
+		link_status->txPWR = link_s.tx_power;
+		memcpy(link_status->bsId, wm->conn_comp.net_id.bs.id, BS_ID_SIZE);
+	}
+
+	dm_put_dev(dev_idx);
+	xfunc_out();
+	return ret;
+}
+
+static int get_connected_nsp(int dev_idx, WIMAX_API_CONNECTED_NSP_INFO_P nsp_info)
+{
+	device_t *dev;
+	wimax_t *wm;
+	wm_nsp_t *nsp;
+	struct list_head *head;
+	int ret = -1;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+	
+	wm = dev->wimax;
+	head = &wm->scan_list.head;
+
+	nsp_info->structureSize = sizeof(WIMAX_API_CONNECTED_NSP_INFO);
+	nsp_info->activated = TRUE;
+	nsp_info->NSPid = U82U24(wm->conn_comp.net_id.nsp.id);
+
+	pthread_mutex_lock(&wm->scan_list.lock);
+	list_for_each_entry(nsp, head, list) {
+		if (nsp_info->NSPid == nsp->id) {
+			mbstowcs((wchar_t *)nsp_info->NSPName, (char *)nsp->name,
+				strlen((char *)nsp->name)+1);
+			nsp_info->RSSI = nsp->rssi;
+			nsp_info->CINR = nsp->cinr;
+			nsp_info->networkType = nsp->type;
+			#if defined( NO_IMPLIMENT )
+			nsp_info->NSPRealm
+			#else
+			memset(nsp_info->NSPRealm, 0, sizeof(nsp_info->NSPRealm));
+			#endif
+			ret = 0;
+			break;
+		}
+	}
+	pthread_mutex_unlock(&wm->scan_list.lock);
+
+	xfunc_out("ret=%d", ret);
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+int sdk_set_ioctl_connected_nsp(sdk_internal_t *sdk, int dev_idx)
+{
+	WIMAX_API_CONNECTED_NSP_INFO nsp_info;
+	int ret = -1;
+
+	xfunc_in("dev=%d, ro=%d", dev_idx, sdk->ro);
+
+	if (sdk->ro)
+		return 0;
+
+	if (!(ret = get_connected_nsp(dev_idx, &nsp_info))) {
+		ret = net_ioctl_set_data(dev_idx, SIOC_DATA_CONNNSP, &nsp_info, sizeof(nsp_info));
+		if (ret > 0) ret = 0;
+	}
+	
+	xfunc_out("ret=%d", ret);
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+int sdk_get_ioctl_connected_nsp(int dev_idx, WIMAX_API_CONNECTED_NSP_INFO_P nsp_info)
+{
+	int ret;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	ret = net_ioctl_get_data(dev_idx, SIOC_DATA_CONNNSP, nsp_info, sizeof(*nsp_info));
+	if (ret > 0) ret = 0;
+	
+	xfunc_out("ret=%d", ret);
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+int sdk_get_connected_nsp(api_hand_t *api_hand, int dev_idx, 
+		WIMAX_API_CONNECTED_NSP_INFO_P nsp_info)
+{
+	#define GET_CURRENT_LINK
+	#if defined(GET_CURRENT_LINK)
+	wm_link_status_t link_s;
+	#endif
+	int ret;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+	
+	if (api_hand->sdk->ro)
+		ret = sdk_get_ioctl_connected_nsp(dev_idx, nsp_info);
+	else
+		ret = get_connected_nsp(dev_idx, nsp_info);
+	
+	#if defined(GET_CURRENT_LINK)
+	if (!wm_get_linkinfo(dev_idx, &link_s)) {
+		nsp_info->RSSI = link_s.rssi;
+		nsp_info->CINR = link_s.cinr;
+	}
+	#endif
+
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_set_ioctl_complete_info(int dev_idx)
+{
+	device_t *dev;
+	wimax_t *wm;
+	int ret = -1;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+	wm = dev->wimax;
+
+	ret = net_ioctl_set_data(dev_idx, SIOC_DATA_CONNCOMP,
+		&wm->conn_comp, sizeof(wm->conn_comp));
+	if (ret > 0) ret = 0;
+	
+	dm_put_dev(dev_idx);
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_load_ioctl_complete_info(int dev_idx)
+{
+	device_t *dev;
+	wimax_t *wm;
+	int ret;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+	wm = dev->wimax;
+
+	ret = net_ioctl_get_data(dev_idx, SIOC_DATA_CONNCOMP,
+		&wm->conn_comp, sizeof(wm->conn_comp));
+	if (ret > 0) ret = 0;
+
+	dm_put_dev(dev_idx);
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+static int sdk_set_ioctl_profile_id(int dev_idx, u32 profile_id)
+{
+	int ret = -1;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	ret = net_ioctl_set_data(dev_idx, SIOC_DATA_PROFILEID,
+		&profile_id, sizeof(profile_id));
+	if (ret > 0) ret = 0;
+
+	dm_put_dev(dev_idx);
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+static int sdk_load_ioctl_profile_id(int dev_idx)
+{
+	device_t *dev;
+	u32 profile_id = 0;
+	u8 nspid[NSP_ID_SIZE];
+	u8 subs_idx;
+	int ret = 0;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	if (dev->wimax->scan.type != wm_scan_curr_subscription) {
+		xprintf(SDK_DBG, "Scan type(%d) does not need loading profile_id\n",
+			dev->wimax->scan.type);
+		goto out;
+	}
+
+	if ((ret = net_ioctl_get_data(dev_idx, SIOC_DATA_PROFILEID,
+		&profile_id, sizeof(profile_id))) < 0)
+		goto out;
+	ret = 0;
+
+	subs_idx = get_msb(profile_id);
+	U242U8(nspid, profile_id);
+	if (!(dev->wimax->scan.selected_subs = wm_get_subscription(dev_idx, subs_idx, nspid)))
+		ret = -1;
+
+out:
+	dm_put_dev(dev_idx);
+	xfunc_out("ret=%d, *profile_id=0x%08X", ret, profile_id);
+	return ret;
+}
+
+static int get_network_list(int dev_idx, WIMAX_API_NSP_INFO_P list, u32 *list_cnt)
+{
+	device_t *dev;
+	wimax_t *wm;
+	wm_nsp_t *nsp;
+	struct list_head *head;
+	int cnt = 0;
+
+	xfunc_in("dev=%d, list_cnt=%d", dev_idx, *list_cnt);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	wm = dev->wimax;
+	head = &wm->scan_list.head;
+
+	pthread_mutex_lock(&wm->scan_list.lock);
+	xprintf(SDK_DBG, "scan_list.cnt=%d\n", wm->scan_list.cnt);
+	list_for_each_entry(nsp, head, list) {
+		if (cnt >= *list_cnt)
+			break;
+		list[cnt].structureSize = sizeof(WIMAX_API_NSP_INFO);
+		mbstowcs((wchar_t *)list[cnt].NSPName, (char *)nsp->name,
+			strlen((char *)nsp->name)+1);
+		list[cnt].NSPid = nsp->id;
+		list[cnt].RSSI = nsp->rssi;
+		list[cnt].CINR = nsp->cinr;
+		list[cnt].networkType = nsp->type;
+		cnt++;
+	}
+	*list_cnt = cnt;
+	pthread_mutex_unlock(&wm->scan_list.lock);
+
+	xfunc_out("cnt=%d", cnt);
+	dm_put_dev(dev_idx);
+	return 0;
+}
+
+int sdk_set_ioctl_network_list(sdk_internal_t *sdk, int dev_idx)
+{
+	device_t *dev;
+	wimax_t *wm;
+	WIMAX_API_NSP_INFO *nsp_info = NULL;
+	int ret = 0, cnt, cnt2;
+
+	xfunc_in("dev=%d, ro=%d", dev_idx, sdk->ro);
+
+	if (sdk->ro)
+		return 0;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+	
+	wm = dev->wimax;
+	cnt = cnt2 = wm->scan_list.cnt;
+
+	if (!cnt)
+		goto out;
+
+	nsp_info = (WIMAX_API_NSP_INFO *) sdk_malloc(sizeof(WIMAX_API_NSP_INFO) * cnt);
+	assert(nsp_info);
+
+	ret = get_network_list(dev_idx, nsp_info, (u32 *)&cnt2);
+	if (ret < 0)
+		goto out;
+	assert(cnt == cnt2);
+
+	ret = net_ioctl_set_data(dev_idx, SIOC_DATA_NETLIST,
+		nsp_info, sizeof(*nsp_info) * cnt);
+	if (ret > 0) ret = 0;
+out:
+	if (nsp_info)
+		sdk_free(nsp_info);
+	
+	xfunc_out("ret=%d", ret);
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+int sdk_get_ioctl_network_list(int dev_idx, WIMAX_API_NSP_INFO_P list, u32 *list_cnt)
+{
+	device_t *dev;
+	int ret;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	if ((ret = net_ioctl_get_data(dev_idx, SIOC_DATA_NETLIST,
+		list, sizeof(*list) * *list_cnt)) > 0) {
+		assert(ret % sizeof(WIMAX_API_NSP_INFO) == 0);
+		*list_cnt = ret / sizeof(WIMAX_API_NSP_INFO);
+	}
+
+	xfunc_out("ret=%d", ret);
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+int sdk_get_network_list(api_hand_t *api_hand, int dev_idx, WIMAX_API_NSP_INFO_P list,
+		u32 *list_cnt)
+{
+	int ret;
+
+	xfunc_in("dev=%d, list_cnt=%d", dev_idx, *list_cnt);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	if (api_hand->sdk->ro)
+		ret = sdk_get_ioctl_network_list(dev_idx, list, list_cnt);
+	else
+		ret = get_network_list(dev_idx, list, list_cnt);
+
+	xfunc_out("ret=%d, cnt=%d", ret, *list_cnt);
+	return ret;
+}
+
+static bool is_connection_ready(sdk_internal_t *sdk, int dev_idx, char *state)
+{
+	int m_status, c_status;
+	bool ret = FALSE;
+	
+	sdk_get_status(sdk, dev_idx, &m_status, &c_status);
+
+	switch (m_status) {
+		case M_INIT:
+		case M_OPEN_OFF:
+			strcpy(state, "RF-off");
+			break;
+		case M_OPEN_ON:
+			strcpy(state, "Ready");
+			ret = TRUE;
+			break;
+		case M_SCAN:
+			strcpy(state, "Scanning");
+			ret = TRUE;
+			break;
+		case M_CONNECTING:
+			strcpy(state, "Connecting");
+			break;
+		case M_CONNECTED:
+			strcpy(state, "Connected");
+			break;
+		default:
+			strcpy(state, "Unknown");
+			break;
+	}
+
+	return ret;
+}
+
+int sdk_connect_network(api_hand_t *api_hand, int dev_idx, uchar *nsp_name, u32 profile_id)
+{
+	device_t *dev = NULL;
+	wimax_t *wm;
+	wm_nsp_t *nsp;
+	u8 hnspid[NSP_ID_SIZE], vnspid[NSP_ID_SIZE];
+	u8 srched_nspid[NSP_ID_SIZE];
+	u8 nspname[WM_MAX_NSP_NAME_LEN];
+	char conn_state[128];
+	wm_subscription_info_t	*subs;
+	int ret;
+
+	xfunc_in("[%d], nsp=%S, 0x%08x", dev_idx, nsp_name, profile_id);
+
+	if ((ret = sdk_check_handle(api_hand, dev_idx)) < 0)
+		goto out;
+
+	if (api_hand->sdk->ro) {
+		ret = sdk_set_errno(ERR_PERM);
+		goto out;
+	}
+
+	if (!(dev = dm_get_dev(dev_idx))) {
+		ret = -1;
+		goto out;
+	}
+
+	if (!is_connection_ready(api_hand->sdk, dev_idx, conn_state)) {
+		xprintf(SDK_ERR, "Current state(%s) is not connectable state!!\n", conn_state);
+		ret = -1;
+		goto out;
+	}
+
+	wm = dev->wimax;
+
+	if (wm->scan.sf_mode) {
+		u8 nspid[NSP_ID_SIZE];
+		WIMAX_API_NSP_INFO net_info;
+		u32 cnt = 1;
+
+		if (!get_network_list(dev_idx, &net_info, &cnt)) {
+			if (cnt == 1) {
+				U242U8(nspid, net_info.NSPid);
+				if ((subs = wm_get_subscription(dev_idx, 0, nspid))) {
+					wm->scan.selected_subs = subs;
+					xprintf(SDK_INFO, "user_hnai=%s\n",
+						wm->scan.selected_subs->subscription_id.hnspid.name);
+				}
+			}
+			else
+				xprintf(SDK_ERR, "get_network_list is %d\n", cnt);
+		}
+	}
+	
+	if (!wm->scan.selected_subs && wm->scan.type != wm_scan_all_channels && !profile_id) {
+		xprintf(SDK_ERR, "There is no selected subscription\n");
+		goto out;
+	}
+
+	wcstombs((char *)nspname, (wchar_t *)nsp_name, wcslen((wchar_t *)nsp_name)+1);
+	xprintf(SDK_DBG, "nspname=%s(%d)\n", nspname, strlen((char *)nspname));
+	
+	if (wm->scan.type == wm_scan_all_channels)
+		U242U8(hnspid, WIDE_SCAN_HNSP_ID);
+	else {
+		if (profile_id) {
+			if (!wm->scan.selected_subs) {
+				u8 subs_idx = get_msb(profile_id);
+				U242U8(hnspid, profile_id);
+				wm->scan.selected_subs = wm_get_subscription(dev_idx, subs_idx, hnspid);
+			}
+		}
+		if (!wm->scan.selected_subs) {
+			xprintf(SDK_ERR, "selected_subs is NULL\n");
+			ret = -1;
+			goto out;
+		}
+		memcpy(hnspid, wm->scan.selected_subs->subscription_id.hnspid.id, NSP_ID_SIZE);
+	}
+
+	if (profile_id) {
+		U242U8(srched_nspid, profile_id);
+		if ((nsp = wm_lookup_nsp_by_id(wm, srched_nspid)) == NULL) {
+			xprintf(SDK_ERR, "[%d] NSP(%06x) is not found\n",
+				dev_idx, U82U24(srched_nspid));
+			ret = sdk_set_errno(ERR_NO_NSPID);
+			goto out;
+		}
+	}
+	else {
+		if ((nsp = wm_lookup_nsp_by_name(wm, nspname)) == NULL) {
+			xprintf(SDK_ERR, "[%d] NSP(%s) is not found\n", dev_idx, nspname);
+			ret = sdk_set_errno(ERR_NO_NSPID);
+			goto out;
+		}
+	}
+	U242U8(vnspid, nsp->id);
+	
+	if (wm->dev_info.eapp.cr801_enabled) {
+		wm->dev_info.eapp.cr801_server_reject_cnt = 0;
+		sdk_init_cr801(wm);
+		if (E_EAP_TLS_ENABLED(dev))
+			wm_set_eap(dev_idx, TRUE);
+	}
+
+	ret = wm_connect_network(dev_idx, hnspid, vnspid);
+out:
+	xfunc_out("ret=%d", ret);
+	if (dev)
+		dm_put_dev(dev_idx);
+	return ret;
+}
+
+int sdk_disconnect_network(api_hand_t *api_hand, int dev_idx)
+{
+	int ret;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	if (api_hand->sdk->ro)
+		return sdk_set_errno(ERR_PERM);
+
+	ret = wm_disconnect_network(dev_idx, SDK_DISCONN_RESP_TIMEOUT_SEC);
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_get_rf_info(api_hand_t *api_hand, int dev_idx, GCT_API_RF_INFORM_P rf_info)
+{
+	int ret;
+
+	xfunc_in("dev=%d rf_info=0x%08x", dev_idx, rf_info);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	ret = wm_get_rf_info(dev_idx, rf_info);
+
+	dm_put_dev(dev_idx);
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_get_bl_ver(api_hand_t *api_hand, int dev_idx, char *buf, int size)
+{
+	device_t *dev;
+	char str[64];
+	u8 *ver;
+	int ret;
+
+	xfunc_in("dev=%d size=%d", dev_idx, size);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	ver = (u8 *) &dev->wimax->dev_info.revision.bl_ver;
+	ret = sprintf(str, "%d.%d.%d.%d", ver[0], ver[1], ver[2], ver[3]);
+
+	xprintf(SDK_DBG, "%s\n", str);
+	if (size < ret)
+		ret = -1;
+	else {
+		strcpy(buf, str);
+		ret = 0;
+	}
+
+	dm_put_dev(dev_idx);
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_get_capability(api_hand_t *api_hand, int dev_idx, u32 *cap)
+{
+	device_t *dev;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	*cap = dev->capability;
+
+	dm_put_dev(dev_idx);
+	xfunc_out("dev->capability=%d", dev->capability);
+	return 0;
+}
+
+int sdk_set_capability(api_hand_t *api_hand, int dev_idx, u32 cap)
+{
+	device_t *dev;
+	int ret;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	ret = wm_set_capability(dev_idx, cap);
+
+	dm_put_dev(dev_idx);
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_get_neighbor_list(api_hand_t *api_hand, int dev_idx,
+		GCT_API_NEIGHBOR_LIST_P list, int *list_cnt)
+{
+	device_t *dev;
+	wm_bs_neigh_t *neigh = NULL;
+	int cnt, ret, i;
+
+	xfunc_in("dev=%d, list_cnt=%d", dev_idx, *list_cnt);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	cnt = *list_cnt;
+	neigh = (wm_bs_neigh_t *) sdk_malloc(sizeof(wm_bs_neigh_t) * cnt);
+	assert(neigh);
+	if (!(ret = wm_get_neighbor_list(dev_idx, neigh, &cnt))) {
+		for (i = 0; i < cnt; i++) {
+			list[i].structureSize = sizeof(*list);
+			memcpy(list[i].bsId, neigh[i].bsid, sizeof(list[i].bsId));
+			list[i].rssi = neigh[i].rssi;
+			list[i].cinr = neigh[i].cinr;
+			list[i].preamble = neigh[i].preamble;
+			list[i].frequency = neigh[i].frequency;
+		}
+		*list_cnt = cnt;
+	}
+	else
+		*list_cnt = 0;
+
+	sdk_free(neigh);
+	dm_put_dev(dev_idx);
+	xfunc_out("ret=%d, cnt=%d", ret, cnt);
+	return ret;
+}
+
+int sdk_net_search_scan(api_hand_t *api_hand, int dev_idx, GCT_API_SCAN_TYPE type)
+{
+	sdk_internal_t *sdk;
+	int ret;
+
+	xfunc_in("dev=%d, type=%d", dev_idx, type);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	sdk = api_hand->sdk;
+
+	if (sdk->ro)
+		return sdk_set_errno(ERR_PERM);
+
+	ret = wm_net_search_scan(dev_idx, type);
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_cancel_scan(api_hand_t *api_hand, int dev_idx)
+{
+	int ret;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	if (api_hand->sdk->ro)
+		return sdk_set_errno(ERR_PERM);
+
+	ret = wm_cancel_scan(dev_idx);
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_cmd_mac_state(api_hand_t *api_hand, int dev_idx, GCT_API_CMD_MAC_STATE_TYPE type)
+{
+	int ret;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	if (api_hand->sdk->ro)
+		return sdk_set_errno(ERR_PERM);
+
+	ret = wm_cmd_mac_state(dev_idx, type);
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_set_idle_mode_timeout(api_hand_t *api_hand, int dev_idx, u16 timeoutSec)
+{
+	int ret;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	if (api_hand->sdk->ro)
+		return sdk_set_errno(ERR_PERM);
+
+	ret = wm_set_idle_mode_timeout(dev_idx, timeoutSec);
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_get_phy_mac_basic(api_hand_t *api_hand, int dev_idx, GCT_API_MAC_PHY_MAC_BASIC_P pData)
+{
+	int ret;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	ret = wm_get_phy_mac_basic(dev_idx, pData);
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_get_phy_mcs(api_hand_t *api_hand, int dev_idx, GCT_API_MAC_PHY_MCS_P pData)
+{
+	int ret;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	ret = wm_get_phy_mcs(dev_idx, pData);
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_get_phy_cinr_rssi(api_hand_t *api_hand, int dev_idx, GCT_API_MAC_PHY_CINR_RSSI_P pData)
+{
+	int ret;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	ret = wm_get_phy_cinr_rssi(dev_idx, pData);
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_on_app_event(sdk_internal_t *sdk, int dev_idx, fsm_event_t event)
+{
+	device_t *dev;
+	wimax_t *wm;
+	int m_status, c_status;
+	rf_stat_t rf_stat;
+	int ret = 0;
+	int evt_mask = SDK_INFO;
+
+	xfunc_in("dev=%d, event=%d", dev_idx, event);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+	wm = dev->wimax;
+
+	#if 0
+	if ((ret = dm_get_status(dev_idx, &m_status, &c_status)) < 0) {
+		ret = -1;
+		goto out;
+	}
+	#else
+	if ((ret = sdk_get_status(sdk, dev_idx, &m_status, &c_status)) < 0) {
+		ret = -1;
+		goto out;
+	}
+	#endif
+
+	dev->a_status = event;
+
+	switch ((int)event) {
+		case AM_Open:
+			xprintf(evt_mask, "[%d] %s: m_s=%d, c_s=%d\n",
+				dev_idx, STR(AM_Open), m_status, c_status);
+			if (sdk->ro) {
+				if (m_status == M_CONNECTED)
+					sdk_load_ioctl_complete_info(dev_idx);
+				break;
+			}
+			if (m_status == M_INIT) {
+				sdk_set_status(sdk, dev_idx, M_OPEN_OFF, C_INIT);
+				ret = wm_get_rf_state(dev_idx, &rf_stat);
+				if (ret < 0)
+					break;
+				if (rf_stat == rf_on) {
+					#if 1
+					ret = wm_set_rf_state(dev_idx, rf_off, SDK_RF_UPDOWN_RESP_TIMEOUT_SEC);
+					#else
+					ret = sdk_on_ind_event(sdk, dev_idx, NM_RadioOn);
+					#endif
+				}
+			}
+			break;
+		case AM_Scan:
+			xprintf(evt_mask, "[%d] %s: m_s=%d, c_s=%d\n",
+				dev_idx, STR(AM_Scan), m_status, c_status);
+			if (sdk->ro)
+				break;
+			if (m_status == M_OPEN_ON) {
+				ret = sdk_set_status(sdk, dev_idx, M_SCAN, C_INIT);
+				wm_set_scan_type(dev_idx, wm_scan_all_channels);
+			}
+			break;
+		case AM_Close:
+			xprintf(evt_mask, "[%d] %s: m_s=%d, c_s=%d\n",
+				dev_idx, STR(AM_Close), m_status, c_status);
+			if (sdk->ro)
+				break;
+			sdk_set_status(sdk, dev_idx, M_INIT, C_INIT);
+			switch (m_status) {
+				case M_CONNECTING:
+				case M_CONNECTED:
+					#if 0
+					if (dev->inserted)
+						wm_disconnect_network(dev_idx, SDK_DISCONN_RESP_TIMEOUT_SEC);
+					#endif
+				case M_OPEN_ON:
+				case M_SCAN:
+					if (dev->inserted) {
+						sdk_set_status(sdk, dev_idx, M_INIT, C_INIT);
+						#if 1
+						wm_set_rf_state(dev_idx, rf_off, 0);
+						#else
+						wm_set_rf_state(dev_idx, rf_off, SDK_RF_UPDOWN_RESP_TIMEOUT_SEC);
+						#endif
+					}
+					break;
+			}
+			break;
+	}
+
+out:
+	dm_put_dev(dev_idx);
+	xfunc_out("m_s=%d, c_s=%d", m_status, c_status);
+	return ret;
+}
+
+int sdk_on_ind_event(sdk_internal_t *sdk, int dev_idx, fsm_event_t event)
+{
+	device_t *dev;
+	wimax_t *wm;
+	int m_status, c_status;
+	int ret = 0;
+	int evt_mask = SDK_INFO;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+	wm = dev->wimax;
+
+	pthread_mutex_lock(&wm->fsm_lock);
+
+	sdk_get_status(sdk, dev_idx, &m_status, &c_status);
+
+	xfunc_in("dev=%d, event=%d, m_s=%d, c_s=%d", dev_idx, event, m_status, c_status);
+
+	switch ((int)event) {
+		case NM_RadioOn:
+			xprintf(evt_mask, "[%d] %s\n", dev_idx, STR(NM_RadioOn));
+			if (m_status == M_OPEN_OFF) {
+				sdk_set_status(sdk, dev_idx, M_OPEN_ON, C_INIT);
+				sdk_ind_power_ctrl(sdk, dev_idx, TRUE);
+				if (!sdk->ro)
+					ret = wm_req_scan(dev_idx);
+			}
+			break;
+		case NM_RadioOff:
+			xprintf(evt_mask, "[%d] %s\n", dev_idx, STR(NM_RadioOff));
+			switch (m_status) {
+				case M_OPEN_ON:
+				case M_SCAN:
+				case M_CONNECTING:
+				case M_CONNECTED:
+					sdk_set_status(sdk, dev_idx, M_OPEN_OFF, C_INIT);
+					sdk_ind_power_ctrl(sdk, dev_idx, FALSE);
+					if (!sdk->ro)
+						wm_clean_scan_info(dev_idx);
+					break;
+			}
+			break;
+		case NM_ScanComplete:
+			xprintf(evt_mask, "[%d] %s\n", dev_idx, STR(NM_ScanComplete));
+			if (!sdk->ro) {
+				if (m_status != M_CONNECTING) {
+					#if defined(CONFIG_ENABLE_BW_SWITCHING_FOR_KT)
+					nds_update_switching_bw(dev_idx);
+					#endif
+					sdk_set_ioctl_network_list(sdk, dev_idx);
+					if ((ret = sdk_set_status(sdk, dev_idx, M_OPEN_ON, C_INIT)) < 0)
+						break;
+					if ((ret = wm_req_interval_scan(dev_idx, 0)) < 0)
+						break;
+					if (wm->scan.type == wm_scan_all_channels)
+						ret = sdk_ind_net_search_wscan(sdk, dev_idx);
+				}
+			}
+			break;
+		case NC_ConnectStart:
+			xprintf(evt_mask, "[%d] %s\n", dev_idx, STR(NC_ConnectStart));
+			if (sdk->ro)
+				sdk_load_ioctl_profile_id(dev_idx);
+			break;
+		case NC_ConnectComplete:
+			xprintf(evt_mask, "[%d] %s(%d)\n", dev_idx, STR(NC_ConnectComplete), c_status);
+			if (c_status == C_ASSOCCOMPLETE) {
+				if (!sdk->ro) {
+					sdk_set_ioctl_connected_nsp(sdk, dev_idx);
+					sdk_set_ioctl_complete_info(dev_idx);
+					sdk_set_status(sdk, dev_idx, M_CONNECTED, C_CONNCOMPLETE);
+				}
+				sdk_ind_connect_net(sdk, dev_idx, TRUE);
+			}
+			else if (!sdk->ro)
+				wm_req_interval_scan(dev_idx, 100);
+			break;
+		case NC_ConnectFail:
+			xprintf(evt_mask, "[%d] %s(%d)\n", dev_idx, STR(NC_ConnectFail), c_status);
+			if (c_status == C_CONNSTART || c_status == C_ASSOCCOMPLETE) {
+				if (!sdk->ro && wm->dev_info.eapp.cr801_enabled) {
+					pthread_mutex_unlock(&wm->fsm_lock);
+					if (!wm_cr801_re_connect(dev_idx))
+						goto out_no_unlock;
+				}
+				sdk_set_status(sdk, dev_idx, M_OPEN_ON, C_INIT);
+				sdk_ind_connect_net(sdk, dev_idx, FALSE);
+				if (!sdk->ro) {
+					wm_req_interval_scan(dev_idx, 100);
+				}
+			}
+			break;
+		case NC_Disconnect:
+			xprintf(evt_mask, "[%d] %s\n", dev_idx, STR(NC_Disconnect));
+			if (m_status == M_CONNECTED) {
+				if (!sdk->ro) {
+					sdk_ind_disconnect_net(sdk, dev_idx, TRUE);
+					/*We should change the state after calling indication.*/
+					sdk_set_status(sdk, dev_idx, M_OPEN_ON, C_INIT);
+					wm_req_interval_scan(dev_idx, 100);
+				}
+				else
+					sdk_ind_disconnect_net(sdk, dev_idx, TRUE);
+			}
+		case NC_AssocStart:
+			xprintf(evt_mask, "[%d] %s\n", dev_idx, STR(NC_AssocStart));
+			if (c_status == C_CONNSTART || c_status == C_ASSOCCOMPLETE)
+				sdk_set_status(sdk, dev_idx, m_status, C_ASSOCSTART);
+			break;
+		case NC_AssocSuccess:
+			xprintf(evt_mask, "[%d] %s\n", dev_idx, STR(NC_AssocSuccess));
+			if (c_status == C_REG || c_status == C_DSX)
+				sdk_set_status(sdk, dev_idx, m_status, C_ASSOCCOMPLETE);
+			break;
+		case NC_AssocFail:
+			xprintf(evt_mask, "[%d] %s\n", dev_idx, STR(NC_AssocFail));
+			switch (c_status) {
+				case C_ASSOCSTART:
+				case C_RNG:
+				case C_SBC:
+				case C_AUTH:
+				case C_REG:
+				case C_DSX:
+					sdk_set_status(sdk, dev_idx, m_status, C_ASSOCCOMPLETE);
+					break;
+			}
+			break;
+		case NC_RangingStart:
+			xprintf(evt_mask, "[%d] %s\n", dev_idx, STR(NC_RangingStart));
+			if (c_status == C_ASSOCSTART)
+				sdk_set_status(sdk, dev_idx, m_status, C_RNG);
+			break;
+		case NC_RangingComplete:
+			xprintf(evt_mask, "[%d] %s\n", dev_idx, STR(NC_RangingComplete));
+			break;
+		case NC_SbcStart:
+			xprintf(evt_mask, "[%d] %s\n", dev_idx, STR(NC_SbcStart));
+			if (c_status == C_RNG)
+				sdk_set_status(sdk, dev_idx, m_status, C_SBC);
+			break;
+		case NC_SbcComplete:
+			xprintf(evt_mask, "[%d] %s\n", dev_idx, STR(NC_SbcComplete));
+			break;
+		case NC_AuthStart:
+			xprintf(evt_mask, "[%d] %s\n", dev_idx, STR(NC_AuthStart));
+			if (c_status == C_RNG || c_status == C_SBC)
+				sdk_set_status(sdk, dev_idx, m_status, C_AUTH);
+			break;
+		case NC_AuthComplete:
+			xprintf(evt_mask, "[%d] %s\n", dev_idx, STR(NC_AuthComplete));
+			if (E_EAP_TLS_ENABLED(dev) && wm->dev_info.eapp.log_enabled)
+				eap_start_e_eaplog_thread(dev_idx);
+			break;
+		case NC_RegStart:
+			xprintf(evt_mask, "[%d] %s\n", dev_idx, STR(NC_RegStart));
+			if (c_status == C_RNG || c_status == C_SBC || c_status == C_AUTH)
+				sdk_set_status(sdk, dev_idx, m_status, C_REG);
+			break;
+		case NC_RegComplete:
+			xprintf(evt_mask, "[%d] %s\n", dev_idx, STR(NC_RegComplete));
+			break;
+		case NC_DsxStart:
+			xprintf(evt_mask, "[%d] %s\n", dev_idx, STR(NC_DsxStart));
+			if (c_status == C_REG)
+				sdk_set_status(sdk, dev_idx, m_status, C_DSX);
+			break;
+		case NC_DsxComplete:
+			xprintf(evt_mask, "[%d] %s\n", dev_idx, STR(NC_DsxComplete));
+			break;
+	}
+
+	pthread_mutex_unlock(&wm->fsm_lock);
+out_no_unlock:
+	dm_put_dev(dev_idx);
+	xfunc_out();
+	return ret;
+}
+
+int sdk_ind_event(int dev_idx, fsm_event_t event)
+{
+	struct list_head *head = hand_get_api_handle_list();
+	api_hand_t *handle;
+
+	pthread_mutex_lock(&api_handle_lock);
+	list_for_each_entry(handle, head, list) {
+		if (handle->sdk && handle->sdk->dev_open[dev_idx] && dm_tst_dev(dev_idx))
+			sdk_on_ind_event(handle->sdk, dev_idx, event);
+	}
+	pthread_mutex_unlock(&api_handle_lock);
+	return 0;
+}
+
+#if defined(CONFIG_ENABLE_SERVICE_FLOW)
+int sdk_sf_BeginSFRead(api_hand_t *api_hand, int dev_idx)
+{
+	int ret = 0;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	BeginSFRead(dev_idx);
+
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_sf_EndSFRead(api_hand_t *api_hand, int dev_idx)
+{
+	int ret = 0;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	EndSFRead(dev_idx);
+	
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_sf_GetNextSF(api_hand_t *api_hand, int dev_idx,
+				WIMAX_SERVICE_FLOW *pSF,
+				UINT8 Direction,
+				WIMAX_SERVICE_FLOW **ppRetSF)
+{
+	int ret = 0;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	*ppRetSF = GetNextSF(dev_idx, pSF, Direction);
+	
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_sf_GetServiceFlow(api_hand_t *api_hand, int dev_idx,
+				UINT32 SFID,
+				WIMAX_SERVICE_FLOW **ppRetSF)
+{
+	int ret = 0;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	*ppRetSF = GetServiceFlow(dev_idx, SFID);
+	
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_sf_GetNextClfrRule(api_hand_t *api_hand, int dev_idx, 
+				WIMAX_SERVICE_FLOW *pSF,
+				WIMAX_CLFR_RULE *pCLFRRule,
+				WIMAX_CLFR_RULE **ppRetCLFRRule)
+{
+	int ret = 0;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	*ppRetCLFRRule = GetNextClfrRule(pSF, pCLFRRule);
+
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_sf_GetClfrRule(api_hand_t *api_hand, int dev_idx, 
+				WIMAX_SERVICE_FLOW *pSF,
+				UINT16 PacketClassfierRuleIndex,
+				WIMAX_CLFR_RULE **ppRetCLFRRule)
+{
+	int ret = 0;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	*ppRetCLFRRule = GetClfrRule(pSF, PacketClassfierRuleIndex);
+	
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_sf_GetNextPHSRule(api_hand_t *api_hand, int dev_idx, 
+				WIMAX_SERVICE_FLOW *pSF,
+				WIMAX_PHS_RULE *pPHSRule,
+				WIMAX_PHS_RULE **ppRetPHSRule)
+{
+	int ret = 0;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	*ppRetPHSRule = GetNextPHSRule(pSF, pPHSRule);
+	
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_sf_GetPHSRule(api_hand_t *api_hand, int dev_idx, 
+				WIMAX_SERVICE_FLOW *pSF, 
+				UINT8 PHSI,
+				WIMAX_PHS_RULE **ppRetPHSRule)
+{
+	int ret = 0;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	*ppRetPHSRule = GetPHSRule(pSF, PHSI);
+	
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_sf_CmdAddSF(api_hand_t *api_hand, int dev_idx,
+				WIMAX_SF_PARAM_P pSFParam,
+				WIMAX_CLFR_RULE_P pClfrRule,
+				WIMAX_PHS_RULE_P pPHSRule)
+{
+	int ret = 0;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	if (WIMAX_SF_SUCCESS != CmdAddSF(dev_idx, pSFParam, pClfrRule, pPHSRule)) {
+		ret = -1;
+	}
+	
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_sf_CmdChangeSF(api_hand_t *api_hand, int dev_idx,
+				WIMAX_SF_PARAM_P pSFParam,
+				WIMAX_CLFR_DSC_ACTION CLFRDSCAction,
+				WIMAX_CLFR_RULE_P pClfrRule,
+				WIMAX_PHS_DSC_ACTION PHSDSCAction,
+				WIMAX_PHS_RULE_P pPHSRule)
+{
+	int ret = 0;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	if (WIMAX_SF_SUCCESS != CmdChangeSF(dev_idx, pSFParam, CLFRDSCAction, pClfrRule, PHSDSCAction, pPHSRule)) {
+		ret = -1;
+	}
+	
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_sf_CmdDeleteSF(api_hand_t *api_hand, int dev_idx,
+				WIMAX_SF_PARAM_P pSFParam)
+{
+	int ret = 0;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (sdk_check_handle(api_hand, dev_idx) < 0)
+		return -1;
+
+	if (WIMAX_SF_SUCCESS != CmdDeleteSF(dev_idx, pSFParam)) {
+		ret = -1;
+	}
+	
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_sf_recv_dsx_complete(int dev_idx, u8 *buf, int len)
+{
+	struct hci *hci = (struct hci *)buf;
+	int ret = 0;
+
+	xfunc_in("dev=%d", dev_idx);
+	
+	hci->cmd_evt = ntohs(hci->cmd_evt);
+	hci->length = ntohs(hci->length);
+
+	dev_update_service_flow(dev_idx, hci);
+
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+#endif // CONFIG_ENABLE_SERVICE_FLOW
+
+int sdk_ind_recv_hci_pkt(int dev_idx, char *buf, int len)
+{
+	struct list_head *head = hand_get_api_handle_list();
+	api_hand_t *handle;
+
+	xfunc_in("dev=%d, len=%d", dev_idx, len);
+
+	pthread_mutex_lock(&api_handle_lock);
+	list_for_each_entry(handle, head, list) {
+		if (handle->sdk->dev_open[dev_idx] && handle->sdk->ind.recv_hci
+			&& dm_tst_dev(dev_idx)) {
+			ind_msg_t *msg = (ind_msg_t *) sdk_malloc(sizeof(ind_msg_t));
+			msg->dev_idx = dev_idx;
+			msg->u.recv_hci.buf = sdk_malloc(len+1/*null char*/);
+			memcpy(msg->u.recv_hci.buf, buf, len);
+			#if 0
+			msg->u.recv_hci.buf[len] = 0;	/*set null char*/
+			#endif
+			msg->u.recv_hci.len = len;
+			msg_send(&handle->sdk->ind.msg_cb, ind_recv_hci, msg);
+		}
+	}
+	pthread_mutex_unlock(&api_handle_lock);
+
+	xfunc_out();
+	return 0;
+}
+
+int sdk_ind_dev_insert_remove(int dev_idx, bool is_insert)
+{
+	struct list_head *head = hand_get_api_handle_list();
+	api_hand_t *handle;
+
+	xfunc_in("dev=%d, %s", dev_idx, is_insert ? "insert" : "remove");
+
+	pthread_mutex_lock(&api_handle_lock);
+	list_for_each_entry(handle, head, list) {
+		if (handle->sdk->ind.insert_remove) {
+			ind_msg_t *msg;
+			msg = (ind_msg_t *) sdk_malloc(sizeof(ind_msg_t));
+			msg->dev_idx = dev_idx;
+			msg->u.insert_remove.presence = is_insert;
+			msg_send(&handle->sdk->ind.msg_cb, ind_insert_remove, msg);
+		}
+	}
+	pthread_mutex_unlock(&api_handle_lock);
+
+	xfunc_out();
+	return 0;
+}
+
+int sdk_ind_status_update(int dev_idx, u8 *buf, int len)
+{
+	device_t *dev;
+	struct list_head *head = hand_get_api_handle_list();
+	api_hand_t *handle;
+	WIMAX_API_DEVICE_STATUS status;
+	WIMAX_API_STATUS_REASON reason = WIMAX_API_STATUS_REASON_Normal;
+	WIMAX_API_CONNECTION_PROGRESS_INFO conn_prog = 0;
+	int m_status, c_status;
+	int ret = 0;
+
+	if (len < (int) sizeof(int)*2) {
+		xprintf(SDK_ERR, "[%d] HCI length < %d\n", dev_idx, sizeof(int)*2);
+		return sdk_set_errno(ERR_HCI);
+	}
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	memcpy(&m_status, buf, sizeof(int));
+	memcpy(&c_status, &buf[sizeof(int)], sizeof(int));
+			
+	xfunc_in("dev=%d, m_s=%d, c_s=%d", dev_idx, m_status, c_status);
+
+	if (dev->a_status == AM_Close) {
+		xprintf(SDK_DBG, "APP is in cloasing.\n");
+		goto out;
+	}
+
+	ret = sdk_convert_status(dev_idx, &status, &conn_prog, m_status, c_status);
+
+	if (!ret) {
+		pthread_mutex_lock(&api_handle_lock);
+		list_for_each_entry(handle, head, list) {
+			if (handle->sdk->dev_open[dev_idx] && handle->sdk->ind.stat_update
+				&& dm_tst_dev(dev_idx)) {
+				ind_msg_t *msg;
+				msg = (ind_msg_t *) sdk_malloc(sizeof(ind_msg_t));
+				msg->dev_idx = dev_idx;
+				msg->u.stat_update.device_status = status;
+				msg->u.stat_update.status_reason = reason;
+				msg->u.stat_update.progress_info = conn_prog;
+				msg_send(&handle->sdk->ind.msg_cb, ind_stat_update, msg);
+			}
+		}
+		pthread_mutex_unlock(&api_handle_lock);
+	}
+out:
+	dm_put_dev(dev_idx);
+	xfunc_out();
+	return ret;
+}
+
+int sdk_ind_if_updown(int dev_idx, u8 *buf, int len)
+{
+	sdk_internal_t *sdk = sdk_get_rw_handle();
+	device_t *dev;
+	bool if_updown;
+	int m_status, c_status;
+	int ret = 0;
+
+	xfunc_in("dev=%d, buf[0]=%d\n", dev_idx, *buf);
+
+	if (len < sizeof(if_updown)) {
+		xprintf(SDK_ERR, "[%d] HCI length < %d\n", dev_idx, sizeof(if_updown));
+		return sdk_set_errno(ERR_HCI);
+	}
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	if_updown = *buf;
+
+	sdk_get_status(sdk, dev_idx, &m_status, &c_status);
+
+	xprintf(SDK_INFO, "dev inserted=%d, if=%s, m_status=%d\n",
+		dev->inserted, if_updown==WIMAX_IF_UP ? "up" : "down", m_status);
+
+	if (dev->inserted && m_status == M_CONNECTED && if_updown == WIMAX_IF_DOWN) {
+		net_updown(dev_idx, TRUE);
+		xprintf(SDK_INFO, "Re-up network interface(%s)\n", dev->name);
+	}
+
+	dm_put_dev(dev_idx);
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int sdk_ind_power_ctrl(sdk_internal_t *sdk, int dev_idx, bool on)
+{
+	WIMAX_API_RF_STATE rf_state;
+	int ret = 0;
+
+	xfunc_in("dev=%d, power=%s", dev_idx, on ? "On" : "Off");
+
+	if (on)
+		rf_state = WIMAX_API_RF_ON;
+	else
+		rf_state = WIMAX_API_RF_OFF;
+
+	if (sdk->dev_open[dev_idx] && sdk->ind.pow_mng && dm_tst_dev(dev_idx)) {
+		ind_msg_t *msg = (ind_msg_t *) sdk_malloc(sizeof(ind_msg_t));
+		msg->dev_idx = dev_idx;
+		msg->u.pow_mng.state = rf_state;
+		msg_send(&sdk->ind.msg_cb, ind_pow_mng, msg);
+	}
+
+	xfunc_out();
+	return ret;
+}
+
+int sdk_ind_connect_net(sdk_internal_t *sdk, int dev_idx, bool success)
+{
+	WIMAX_API_NETWORK_CONNECTION_RESP conn_status;
+	int ret = 0;
+
+	xfunc_in("dev=%d, connected=%d", dev_idx, success);
+
+	if (success)
+		conn_status = WIMAX_API_CONNECTION_SUCCESS;
+	else
+		conn_status = WIMAX_API_CONNECTION_FAILURE;
+
+	if (sdk->dev_open[dev_idx] && sdk->ind.connect_net && dm_tst_dev(dev_idx)) {
+		ind_msg_t *msg = (ind_msg_t *) sdk_malloc(sizeof(ind_msg_t));
+		msg->dev_idx = dev_idx;
+		msg->u.connect_net.response = conn_status;
+		msg_send(&sdk->ind.msg_cb, ind_connect_net, msg);
+	}
+
+	xfunc_out();
+	return ret;
+}
+
+int sdk_ind_disconnect_net(sdk_internal_t *sdk, int dev_idx, bool success)
+{
+	WIMAX_API_NETWORK_CONNECTION_RESP conn_status;
+	int ret = 0;
+
+	xfunc_in("dev=%d, connected=%d", dev_idx, success);
+
+	if (success)
+		conn_status = WIMAX_API_CONNECTION_SUCCESS;
+	else
+		conn_status = WIMAX_API_CONNECTION_FAILURE;
+
+	if (sdk->dev_open[dev_idx] && sdk->ind.disconnect_net && dm_tst_dev(dev_idx)) {
+		ind_msg_t *msg = (ind_msg_t *) sdk_malloc(sizeof(ind_msg_t));
+		msg->dev_idx = dev_idx;
+		msg->u.disconnect_net.response = conn_status;
+		msg_send(&sdk->ind.msg_cb, ind_disconnect_net, msg);
+	}
+
+	xfunc_out();
+	return ret;
+}
+
+int sdk_ind_net_search_wscan(sdk_internal_t *sdk, int dev_idx)
+{
+	device_t *dev;
+	wimax_t *wm;
+	WIMAX_API_NSP_INFO_P nsp_list;
+	int ret = 0;
+	u32 nsp_cnt;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+	wm = dev->wimax;
+
+	nsp_cnt = wm->scan_list.cnt;
+	nsp_list = (WIMAX_API_NSP_INFO_P) sdk_malloc(sizeof(WIMAX_API_NSP_INFO)*nsp_cnt);
+
+	if ((ret = get_network_list(dev_idx, nsp_list, &nsp_cnt)) < 0)
+		goto out;
+
+	if (sdk->dev_open[dev_idx] && sdk->ind.net_search_wscan && dm_tst_dev(dev_idx)) {
+		ind_msg_t *msg = (ind_msg_t *) sdk_malloc(sizeof(ind_msg_t));
+		msg->dev_idx = dev_idx;
+		msg->u.net_search_wscan.nsp_list = nsp_list;
+		msg->u.net_search_wscan.list_cnt = nsp_cnt;
+		msg_send(&sdk->ind.msg_cb, ind_net_search_wscan, msg);
+	}
+out:
+	xfunc_out();
+	return ret;
+}
+
+int sdk_ind_rf_state(int dev_idx, u8 *buf, int len)
+{
+	rf_stat_t rf_stat = buf[0];
+	fsm_event_t event;
+
+	xfunc_in("dev=%d, rf=%s", dev_idx, rf_stat==rf_on ? "On" : "Off");
+
+	event = (rf_stat==rf_on) ? NM_RadioOn : NM_RadioOff;
+	sdk_ind_event(dev_idx, event);
+
+	xfunc_out();
+	return 0;
+}
+
+int sdk_ind_provisioning_op(int dev_idx, WIMAX_API_PROV_OPERATION operation,
+	WIMAX_API_CONTACT_TYPE contact_type)
+{
+	struct list_head *head = hand_get_api_handle_list();
+	api_hand_t *handle;
+
+	xfunc_in("dev=%d, %d, %d", dev_idx, operation, contact_type);
+
+	pthread_mutex_lock(&api_handle_lock);
+	list_for_each_entry(handle, head, list) {
+		if (handle->sdk->ind.provisioning) {
+			ind_msg_t *msg;
+			msg = (ind_msg_t *) sdk_malloc(sizeof(ind_msg_t));
+			msg->dev_idx = dev_idx;
+			msg->u.provisioning.operation = operation;
+			msg->u.provisioning.contact_type = contact_type;
+			msg_send(&handle->sdk->ind.msg_cb, ind_provisioning, msg);
+		}
+	}
+	pthread_mutex_unlock(&api_handle_lock);
+
+	xfunc_out();
+	return 0;
+}
+
+static void sdk_chk_cr801(int dev_idx, GCT_API_NOTI_CATEGORY category,
+						GCT_API_NOTI_TYPE type, char *buf, int len)
+{
+	device_t *dev;
+	short code;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return;
+
+	xfunc_in("dev=%d, category=%d, type=%d", dev_idx, category, type);
+
+	assert(dev->wimax->dev_info.eapp.cr801_enabled);
+
+	if (category == GCT_API_ERROR_NOTI_EAP && type == GCT_API_NOTI_TYPE_CODE) {
+		memcpy(&code, buf, sizeof(code));
+		code = B2H(code);
+		if (code == E_WM_CR801_EAP_FAILURE) {
+			dev->wimax->dev_info.eapp.cr801_server_reject_cnt++;
+			xprintf(SDK_DBG, "cr801_server_reject_cnt=%d\n",
+				dev->wimax->dev_info.eapp.cr801_server_reject_cnt);
+		}
+
+		dm_put_dev(dev);
+	}
+	xfunc_out();
+}
+
+int sdk_ind_noti(int dev_idx, GCT_API_NOTI_CATEGORY category,
+						GCT_API_NOTI_TYPE type, char *buf, int len)
+{
+	device_t *dev;
+	struct list_head *head = hand_get_api_handle_list();
+	api_hand_t *handle;
+	int ret = 0;
+
+	xfunc_in("dev=%d, %d, %d", dev_idx, category, type);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	if (E_EAP_TLS_ENABLED(dev)) {
+		if (dev->wimax->dev_info.eapp.cr801_enabled) {
+			xprintf(SDK_DBG, "cr801_enabled=%d\n", dev->wimax->dev_info.eapp.cr801_enabled);
+			sdk_chk_cr801(dev_idx, category, type, buf, len);
+		}
+	}
+
+	pthread_mutex_lock(&api_handle_lock);
+	list_for_each_entry(handle, head, list) {
+		if (handle->sdk->ind.notification) {
+			ind_msg_t *msg;
+			msg = (ind_msg_t *) sdk_malloc(sizeof(ind_msg_t));
+			msg->dev_idx = dev_idx;
+			msg->u.notification.category = category;
+			msg->u.notification.type = type;
+			if (len > sizeof(msg->u.notification.buf)) {
+				xprintf(SDK_ERR, "Notification buffer is too small(%d > %d).",
+					len, sizeof(msg->u.notification.buf));
+				ret = -1;
+				break;
+			}
+			assert(len < sizeof(msg->u.notification.buf));
+			memcpy(msg->u.notification.buf, buf, len);
+			msg->u.notification.buf[len] = 0;
+			msg->u.notification.buf_len = len;
+			msg_send(&handle->sdk->ind.msg_cb, ind_notification, msg);
+		}
+	}
+	pthread_mutex_unlock(&api_handle_lock);
+
+	xfunc_out();
+	dm_put_dev(dev);
+	return ret;
+}
+
+static GCT_API_POWER_MODE convert_hci_power_mode(u8 mode)
+{
+	GCT_API_POWER_MODE m;
+
+	switch (mode) {
+		case MODE_W_AWAKE:
+			m = WiMAXPowerModeNormal;
+			break;
+		case MODE_W_IDLE:
+			m = WiMAXPowerModeIdle;
+			break;
+		case MODE_W_SLEEP:
+			m = WiMAXPowerModeSleep;
+			break;
+		default:
+			m = WiMAXPowerModeMaximum;
+			break;
+	}
+
+	return m;
+}
+
+int sdk_ind_power_mode_change(int dev_idx, u8 *buf, int len)
+{
+	struct list_head *head = hand_get_api_handle_list();
+	api_hand_t *handle;
+	hci_mode_change_t *hci = (hci_mode_change_t *) buf;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	xprintf(SDK_INFO, "status=%d, power_state=%d\n",
+		U82U24(hci->status), convert_hci_power_mode(hci->power_state));
+
+	pthread_mutex_lock(&api_handle_lock);
+	list_for_each_entry(handle, head, list) {
+		if (handle->sdk->ind.power_mode) {
+			ind_msg_t *msg;
+			msg = (ind_msg_t *) sdk_malloc(sizeof(ind_msg_t));
+			msg->dev_idx = dev_idx;
+			msg->u.power_mode.status = U82U24(hci->status);
+			msg->u.power_mode.power_mode = convert_hci_power_mode(hci->power_state);
+			msg_send(&handle->sdk->ind.msg_cb, ind_mode_change, msg);
+		}
+	}
+	pthread_mutex_unlock(&api_handle_lock);
+
+	xfunc_out();
+	return 0;
+}
+
+int sdk_reg_ind(const char *name, void_func_t *reg, void_func_t callback)
+{
+	if (*reg && callback) {
+		xprintf(SDK_ERR, "%s(0x%08X-0x%08X) was registered already\n", name, *reg, callback);
+		return -ERR_ALREADY;
+	}
+	else if (!*reg && !callback) {
+		xprintf(SDK_ERR, "%s(NULL) was removed already\n", name);
+		return -ERR_ALREADY;
+	}
+
+	*reg = callback;
+	return 0;
+}
+
+int sdk_reg_recv_hci_packet(api_hand_t *api_hand, SDKIndRcvHCIPacket callback)
+{
+	void_func_t *reg = (void_func_t *) &api_hand->sdk->ind.recv_hci;
+	if (sdk_check_handle(api_hand, NO_DEV) < 0)
+		return -1;
+	assert(api_hand->sdk != NULL && api_hand->sdk->struct_size == sizeof(sdk_internal_t));
+	return sdk_reg_ind(STR(SDKIndRcvHCIPacket), reg, (void_func_t) callback);
+}
+
+int sdk_reg_dev_insert_remove(api_hand_t *api_hand, SDKIndDeviceInsertRemove callback)
+{
+	void_func_t *reg = (void_func_t *) &api_hand->sdk->ind.insert_remove;
+	if (sdk_check_handle(api_hand, NO_DEV) < 0)
+		return -1;
+	assert(api_hand->sdk != NULL && api_hand->sdk->struct_size == sizeof(sdk_internal_t));
+	return sdk_reg_ind(STR(SDKIndDeviceInsertRemove), reg, (void_func_t) callback);
+}
+
+int sdk_reg_ctrl_power_mng(api_hand_t *api_hand, SDKIndControlPowerManagement callback)
+{
+	void_func_t *reg = (void_func_t *) &api_hand->sdk->ind.pow_mng;
+	if (sdk_check_handle(api_hand, NO_DEV) < 0)
+		return -1;
+	assert(api_hand->sdk != NULL && api_hand->sdk->struct_size == sizeof(sdk_internal_t));
+	return sdk_reg_ind(STR(SDKIndControlPowerManagement), reg, (void_func_t) callback);
+}
+
+int sdk_reg_dev_stat_update(api_hand_t *api_hand, SDKIndDeviceStatusUpdate callback)
+{
+	void_func_t *reg = (void_func_t *) &api_hand->sdk->ind.stat_update;
+	if (sdk_check_handle(api_hand, NO_DEV) < 0)
+		return -1;
+	assert(api_hand->sdk != NULL && api_hand->sdk->struct_size == sizeof(sdk_internal_t));
+	return sdk_reg_ind(STR(SDKIndDeviceStatusUpdate), reg, (void_func_t) callback);
+}
+
+int sdk_reg_connect_network(api_hand_t *api_hand, SDKIndConnectToNetwork callback)
+{
+	void_func_t *reg = (void_func_t *) &api_hand->sdk->ind.connect_net;
+	if (sdk_check_handle(api_hand, NO_DEV) < 0)
+		return -1;
+	assert(api_hand->sdk != NULL && api_hand->sdk->struct_size == sizeof(sdk_internal_t));
+	return sdk_reg_ind(STR(SDKIndConnectToNetwork), reg, (void_func_t) callback);
+}
+
+int sdk_reg_disconnect_network(api_hand_t *api_hand,
+		SDKIndDisconnectFromNetwork callback)
+{
+	void_func_t *reg = (void_func_t *) &api_hand->sdk->ind.disconnect_net;
+	if (sdk_check_handle(api_hand, NO_DEV) < 0)
+		return -1;
+	assert(api_hand->sdk != NULL && api_hand->sdk->struct_size == sizeof(sdk_internal_t));
+	return sdk_reg_ind(STR(SDKIndDisconnectFromNetwork), reg, (void_func_t) callback);
+}
+
+int sdk_reg_network_search_wscn(api_hand_t *api_hand,
+		SDKIndNetworkSearchWideScan callback)
+{
+	void_func_t *reg = (void_func_t *) &api_hand->sdk->ind.net_search_wscan;
+	if (sdk_check_handle(api_hand, NO_DEV) < 0)
+		return -1;
+	assert(api_hand->sdk != NULL && api_hand->sdk->struct_size == sizeof(sdk_internal_t));
+	return sdk_reg_ind(STR(SDKIndNetworkSearchWideScan), reg, (void_func_t) callback);
+}
+
+int sdk_reg_provisioning_op(api_hand_t *api_hand, SDKIndProvisioningOperation callback)
+{
+	void_func_t *reg = (void_func_t *) &api_hand->sdk->ind.provisioning;
+	if (sdk_check_handle(api_hand, NO_DEV) < 0)
+		return -1;
+	assert(api_hand->sdk != NULL && api_hand->sdk->struct_size == sizeof(sdk_internal_t));
+	return sdk_reg_ind(STR(SDKIndProvisioningOperation), reg, (void_func_t) callback);
+}
+
+int sdk_reg_package_update(api_hand_t *api_hand, SDKIndPackageUpdate callback)
+{
+	void_func_t *reg = (void_func_t *) &api_hand->sdk->ind.package_update;
+	if (sdk_check_handle(api_hand, NO_DEV) < 0)
+		return -1;
+	assert(api_hand->sdk != NULL && api_hand->sdk->struct_size == sizeof(sdk_internal_t));
+	return sdk_reg_ind(STR(SDKIndPackageUpdate), reg, (void_func_t) callback);
+}
+
+int sdk_reg_notification(api_hand_t *api_hand, SDKIndNotification callback)
+{
+	void_func_t *reg = (void_func_t *) &api_hand->sdk->ind.notification;
+	if (sdk_check_handle(api_hand, NO_DEV) < 0)
+		return -1;
+	assert(api_hand->sdk != NULL && api_hand->sdk->struct_size == sizeof(sdk_internal_t));
+	return sdk_reg_ind(STR(SDKIndNotification), reg, (void_func_t) callback);
+}
+
+int sdk_reg_mode_change(api_hand_t *api_hand, SDKIndModeChange callback)
+{
+	void_func_t *reg = (void_func_t *) &api_hand->sdk->ind.power_mode;
+	if (sdk_check_handle(api_hand, NO_DEV) < 0)
+		return -1;
+	assert(api_hand->sdk != NULL && api_hand->sdk->struct_size == sizeof(sdk_internal_t));
+	return sdk_reg_ind(STR(SDKIndModeChange), reg, (void_func_t) callback);
+}
+
+#if defined(CONFIG_ENABLE_SERVICE_FLOW)
+int sdk_reg_noti_service_flow(api_hand_t *api_hand,
+				SDKIndNotiServiceFlow callback)
+{
+	void_func_t *reg = (void_func_t *) &api_hand->sdk->ind.noti_service_flow;
+	if (sdk_check_handle(api_hand, NO_DEV) < 0)
+		return -1;
+	assert(api_hand->sdk != NULL && api_hand->sdk->struct_size == sizeof(sdk_internal_t));
+	return sdk_reg_ind(STR(SDKIndNotiServiceFlow), reg, (void_func_t) callback);
+}
+#endif // CONFIG_ENABLE_SERVICE_FLOW
+
+int sdk_read_file(const char *file, void *buf, int size)
+{
+	char *pbuf = (char *) buf;
+	int fd, len, total = 0;
+
+	if ((fd = open(file, O_RDONLY)) < 0) {
+		xprintf(SDK_STD_ERR, "open(%s) failed\n", file);
+		return -1;
+	}
+	while ((len = read(fd, &pbuf[total], size-total)) > 0) {
+		total += len;
+		if (size-total == 0)
+			break;
+	}
+
+	if (len < 0)
+		xprintf(SDK_STD_ERR,"read(%s) failed. ret=%d\n", file, len);
+
+	close(fd);
+	return total;
+}
+
+int sdk_write_file(const char *file, void *buf, int size, int flags)
+{
+	char *pbuf = (char *) buf;
+	int fd, len = 0, total = 0;
+	mode_t mode = 0;
+
+	if (flags & O_CREAT)
+		mode = 0644;
+
+	if ((fd = open(file, flags, mode)) < 0) {
+		xprintf(SDK_STD_ERR, "open(%s) failed\n", file);
+		return -1;
+	}
+
+	if (size) {
+		while ((len = write(fd, &pbuf[total], size-total)) > 0) {
+			total += len;
+			if (size-total == 0)
+				break;
+		}
+	}
+
+	if (len < 0)
+		xprintf(SDK_STD_ERR, "write(%s) failed, ret=%d\n", file, len);
+
+	close(fd);
+	return total;
+}
diff --git a/sdk/sdk.h b/sdk/sdk.h
new file mode 100644
index 0000000..94d1c9d
--- /dev/null
+++ b/sdk/sdk.h
@@ -0,0 +1,411 @@
+// 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.
+
+#if !defined(SDK_H_20080715)
+#define SDK_H_20080715
+#include "global.h"
+#include "gcttype.h"
+#include "hci.h"
+#include "handle.h"
+#include "msg.h"
+#include "msg_thread.h"
+
+#define SDK_VERSION	"1.6.8"
+
+#if !defined(MAX_DEVICE)
+#define MAX_DEVICE 256
+#endif
+#define NO_DEV	0
+
+#define SDK_RF_UPDOWN_RESP_TIMEOUT_SEC		5
+#define SDK_DISCONN_RESP_TIMEOUT_SEC		5
+
+typedef void (*SDKIndRcvHCIPacket) (dev_hand_t *hand, char *buf, int len);
+typedef void (*SDKIndDeviceInsertRemove)(dev_hand_t *hand, BOOL presence);
+typedef void (*SDKIndControlPowerManagement)(dev_hand_t *hand,
+				WIMAX_API_RF_STATE power_state);
+typedef void (*SDKIndDeviceStatusUpdate)(dev_hand_t *hand,
+				WIMAX_API_DEVICE_STATUS device_status, 
+				WIMAX_API_STATUS_REASON status_reason, 
+				WIMAX_API_CONNECTION_PROGRESS_INFO progress_info);
+typedef void (*SDKIndConnectToNetwork) (dev_hand_t *hand,
+				WIMAX_API_NETWORK_CONNECTION_RESP connection_response);
+typedef void (*SDKIndDisconnectFromNetwork) (dev_hand_t *hand,
+				WIMAX_API_NETWORK_CONNECTION_RESP disconnect_response);
+typedef void (*SDKIndNetworkSearchWideScan) (dev_hand_t *hand,
+				WIMAX_API_NSP_INFO_P nsp_list, UINT32 list_cnt);
+typedef void (*SDKIndProvisioningOperation) (dev_hand_t *hand,
+				WIMAX_API_PROV_OPERATION provisioning_operation,
+				WIMAX_API_CONTACT_TYPE contact_type);
+typedef void (*SDKIndPackageUpdate) (dev_hand_t *hand,
+				WIMAX_API_PACK_UPDATE package_update);
+typedef void (*SDKIndNotification) (dev_hand_t *hand,
+				GCT_API_NOTI_CATEGORY category,
+				GCT_API_NOTI_TYPE type, int buf_size, char *buf);
+typedef void (*SDKIndModeChange) (dev_hand_t *hand,
+				GCT_API_POWER_MODE power_mode);
+
+#if defined(CONFIG_ENABLE_SERVICE_FLOW)
+typedef void (*SDKIndNotiServiceFlow)(dev_hand_t *hand, WIMAX_SF_EVENT_P pSfEvent);
+#endif // CONFIG_ENABLE_SERVICE_FLOW
+
+typedef struct sdk_ind_s {
+	pthread_t						thread;
+	msg_cb_t						msg_cb;
+
+	SDKIndRcvHCIPacket				recv_hci;
+	SDKIndDeviceInsertRemove		insert_remove;
+	SDKIndControlPowerManagement	pow_mng;
+	SDKIndDeviceStatusUpdate		stat_update;
+	SDKIndConnectToNetwork			connect_net;
+	SDKIndDisconnectFromNetwork		disconnect_net;
+	SDKIndNetworkSearchWideScan		net_search_wscan;
+	SDKIndProvisioningOperation		provisioning;
+	SDKIndPackageUpdate				package_update;
+	SDKIndNotification				notification;
+	SDKIndModeChange				power_mode;
+
+	#if defined(CONFIG_ENABLE_SERVICE_FLOW)
+	SDKIndNotiServiceFlow			noti_service_flow;
+	#endif // CONFIG_ENABLE_SERVICE_FLOW
+} sdk_ind_t;
+
+typedef enum {
+	ind_recv_hci,
+	ind_insert_remove,
+	ind_pow_mng,
+	ind_stat_update,
+	ind_connect_net,
+	ind_disconnect_net,
+	ind_net_search_wscan,
+	ind_provisioning,
+	ind_package_update,
+	ind_notification,
+	ind_mode_change,
+
+	ind_end
+
+} ind_type_t;
+
+typedef struct {
+	char *buf;
+	int len;
+
+} ind_recv_hci_t;
+
+typedef struct {
+	bool presence;
+
+} ind_insert_remove_t;
+
+typedef struct {
+	WIMAX_API_RF_STATE state;
+
+} ind_pow_mng_t;
+
+typedef struct {
+	WIMAX_API_DEVICE_STATUS device_status;
+	WIMAX_API_STATUS_REASON status_reason;
+	WIMAX_API_CONNECTION_PROGRESS_INFO progress_info;
+
+} ind_stat_update_t;
+
+typedef struct {
+	WIMAX_API_NETWORK_CONNECTION_RESP response;
+
+} ind_connect_net_t;
+
+typedef struct {
+	WIMAX_API_NETWORK_CONNECTION_RESP response;
+
+} ind_disconnect_net_t;
+
+typedef struct {
+	WIMAX_API_NSP_INFO_P nsp_list;
+	UINT32 list_cnt;
+
+} ind_net_search_wscan_t;
+
+typedef struct {
+	WIMAX_API_PROV_OPERATION operation;
+	WIMAX_API_CONTACT_TYPE contact_type;
+
+} ind_provisioning_t;
+
+typedef struct {
+	WIMAX_API_PACK_UPDATE update;
+
+} ind_package_update_t;
+
+#define MAX_NOTI_BUF	512
+typedef struct {
+	GCT_API_NOTI_CATEGORY category;
+	GCT_API_NOTI_TYPE type;
+	char buf[MAX_NOTI_BUF];
+	int buf_len;
+
+} ind_notification_t;
+
+typedef struct {
+	u32	status;
+	GCT_API_POWER_MODE	power_mode;
+
+} ind_mode_change_t;
+
+typedef struct {
+	int 				dev_idx;
+
+	union {
+		ind_recv_hci_t			recv_print;
+		ind_recv_hci_t			recv_hci;
+		ind_insert_remove_t		insert_remove;
+		ind_pow_mng_t 			pow_mng;
+		ind_stat_update_t		stat_update;
+		ind_connect_net_t		connect_net;
+		ind_disconnect_net_t	disconnect_net;
+		ind_net_search_wscan_t	net_search_wscan;
+		ind_provisioning_t		provisioning;
+		ind_package_update_t	package_update;
+		ind_notification_t		notification;
+		ind_mode_change_t		power_mode;
+	} u;
+
+} ind_msg_t;
+
+typedef struct sdk_internal_s {
+	u32			struct_size;
+	api_hand_t	*api;
+	sdk_ind_t	ind;
+
+	bool		dev_open[MAX_DEVICE];
+
+	bool		ro;	/* Read-Only mdoe*/
+	int			mode;
+
+} sdk_internal_t;
+
+/* FSM event */
+typedef enum {
+	AM_Open,
+	AM_Scan,
+	AM_Close,
+
+	NM_ScanComplete,
+	NM_RadioOn,
+	NM_RadioOff,
+	NM_ModeChange,
+	NC_ConnectStart,
+	NC_ConnectComplete,
+	NC_ConnectFail,
+	NC_AssocStart,
+	NC_AssocSuccess,
+	NC_AssocFail,
+	NC_Disconnect,
+	NC_RangingStart,
+	NC_RangingComplete,
+	NC_SbcStart,
+	NC_SbcComplete,
+	NC_AuthStart,
+	NC_AuthComplete,
+	NC_RegStart,
+	NC_RegComplete,
+	NC_DsxStart,
+	NC_DsxComplete,
+
+	fsm_ind_end
+} fsm_event_t;
+
+typedef enum {
+	sdk_read_only = (1<<0),
+
+	sdk_eng_mode = (1<<8)
+
+} sdk_mode_t;;
+
+typedef struct sdk_mng_s {
+	char nonvolatile_dir[256];
+	char log_path[256];
+	char eap_pcap[256];
+	char eap_dec[256];
+	bool	eeap_enabled;
+	bool	odm_enabled;
+	msg_thr_t hci_recvr;
+	msg_thr_t odm_evt;
+
+} sdk_mng_t;
+
+extern sdk_mng_t sdk_mng;
+
+#define SDK_USE_EEAP	(sdk_mng.eeap_enabled)
+#define SDK_USE_ODM	(sdk_mng.odm_enabled)
+
+const char *sdk_version(void);
+struct sdk_internal_s *sdk_get_rw_handle(void);
+int sdk_init(GCT_WIMAX_SDK_MODE mode, GCT_WIMAX_API_PARAM *sdk_param);
+int sdk_deinit(void);
+
+api_hand_t *sdk_api_open(int mode);
+int sdk_api_close(api_hand_t *api_hand);
+int sdk_debug_level(api_hand_t *api_hand, int level);
+int sdk_print_log(api_hand_t *api_hand, int flag, const char *title, const char *str);
+int sdk_get_device_list(api_hand_t *api_hand, WIMAX_API_HW_DEVICE_ID *dev_list,
+		u32 *list_cnt);
+int sdk_device_open(api_hand_t *api_hand, int dev_idx);
+int sdk_internal_device_close(struct sdk_internal_s *sdk, int dev_idx);
+int sdk_device_close(api_hand_t *api_hand, int dev_idx);
+int sdk_get_status(sdk_internal_t *sdk, int dev_idx, int *m_status, int *c_status);
+int sdk_set_status(sdk_internal_t *sdk, int dev_idx, int m_status, int c_status);
+int sdk_get_device_status(api_hand_t *api_hand, int dev_idx,
+		WIMAX_API_DEVICE_STATUS_P status,
+		WIMAX_API_CONNECTION_PROGRESS_INFO_P connect_prog_info);
+int sdk_write_hci_packet(api_hand_t *api_hand, int dev_idx, void *buf, int len);
+int sdk_set_power_control(api_hand_t *api_hand, int dev_idx, rf_stat_t rf_stat);
+int sdk_get_profile_list(api_hand_t *api_hand, int dev_idx,
+		WIMAX_API_PROFILE_INFO_P list, int *list_cnt);
+int sdk_set_profile(api_hand_t *api_hand, int dev_idx, u32 profile_id);
+int sdk_set_scan_interval(api_hand_t *api_hand, int dev_idx, u32 interval_sec);
+int sdk_set_eap(api_hand_t *api_hand, int dev_idx, GCT_API_EAP_PARAM_P eap);
+int sdk_get_statistics(api_hand_t *api_hand, int dev_idx,
+		WIMAX_API_CONNECTION_STAT_P statistics);
+int sdk_get_linkstatus(api_hand_t *api_hand, int dev_idx,
+		WIMAX_API_LINK_STATUS_INFO_P link_status);
+int sdk_get_connected_nsp(api_hand_t *api_hand, int dev_idx, 
+		WIMAX_API_CONNECTED_NSP_INFO_P nsp_info);
+int sdk_get_network_list(api_hand_t *api_hand, int dev_idx, WIMAX_API_NSP_INFO_P list,
+		u32 *list_cnt);
+int sdk_connect_network(api_hand_t *api_hand, int dev_idx, uchar *nsp_name, u32 profile_id);
+int sdk_disconnect_network(api_hand_t *api_hand, int dev_idx);
+int sdk_get_device_info(api_hand_t *api_hand, int dev_idx,
+		WIMAX_API_DEVICE_INFO_P dev_info);
+int sdk_get_rf_info(api_hand_t *api_hand, int dev_idx, GCT_API_RF_INFORM_P rf_info);
+int sdk_get_bl_ver(api_hand_t *api_hand, int dev_idx, char *buf, int size);
+int sdk_get_capability(api_hand_t *api_hand, int dev_idx, u32 *cap);
+int sdk_set_capability(api_hand_t *api_hand, int dev_idx, u32 cap);
+int sdk_get_neighbor_list(api_hand_t *api_hand, int dev_idx,
+		GCT_API_NEIGHBOR_LIST_P list, int *list_cnt);
+int sdk_net_search_scan(api_hand_t *api_hand, int dev_idx, GCT_API_SCAN_TYPE type);
+int sdk_cancel_scan(api_hand_t *api_hand, int dev_idx);
+int sdk_on_ind_event(sdk_internal_t *sdk, int dev_idx, fsm_event_t event);
+int sdk_ind_event(int dev_idx, fsm_event_t event);
+int sdk_cmd_mac_state(api_hand_t *api_hand, int dev_idx, GCT_API_CMD_MAC_STATE_TYPE type);
+int sdk_set_idle_mode_timeout(api_hand_t *api_hand, int dev_idx, u16 timeoutSec);
+int sdk_get_phy_mac_basic(api_hand_t *api_hand, int dev_idx, GCT_API_MAC_PHY_MAC_BASIC_P pData);
+int sdk_get_phy_mcs(api_hand_t *api_hand, int dev_idx, GCT_API_MAC_PHY_MCS_P pData);
+int sdk_get_phy_cinr_rssi(api_hand_t *api_hand, int dev_idx, GCT_API_MAC_PHY_CINR_RSSI_P pData);
+
+#if defined(CONFIG_ENABLE_SERVICE_FLOW)
+int sdk_sf_BeginSFRead(api_hand_t *api_hand, int dev_idx);
+int sdk_sf_EndSFRead(api_hand_t *api_hand, int dev_idx);
+int sdk_sf_GetNextSF(api_hand_t *api_hand, int dev_idx,
+				WIMAX_SERVICE_FLOW *pSF,
+				UINT8 Direction,
+				WIMAX_SERVICE_FLOW **ppRetSF);
+int sdk_sf_GetServiceFlow(api_hand_t *api_hand, int dev_idx,
+				UINT32 SFID,
+				WIMAX_SERVICE_FLOW **ppRetSF);
+int sdk_sf_GetNextClfrRule(api_hand_t *api_hand, int dev_idx, 
+				WIMAX_SERVICE_FLOW *pSF,
+				WIMAX_CLFR_RULE *pCLFRRule,
+				WIMAX_CLFR_RULE **ppRetCLFRRule);
+int sdk_sf_GetClfrRule(api_hand_t *api_hand, int dev_idx, 
+				WIMAX_SERVICE_FLOW *pSF,
+				UINT16 PacketClassfierRuleIndex,
+				WIMAX_CLFR_RULE **ppRetCLFRRule);
+int sdk_sf_GetNextPHSRule(api_hand_t *api_hand, int dev_idx, 
+				WIMAX_SERVICE_FLOW *pSF,
+				WIMAX_PHS_RULE *pPHSRule,
+				WIMAX_PHS_RULE **ppRetPHSRule);
+int sdk_sf_GetPHSRule(api_hand_t *api_hand, int dev_idx, 
+				WIMAX_SERVICE_FLOW *pSF, 
+				UINT8 PHSI,
+				WIMAX_PHS_RULE **ppRetPHSRule);
+int sdk_sf_CmdAddSF(api_hand_t *api_hand, int dev_idx,
+				WIMAX_SF_PARAM_P pSFParam,
+				WIMAX_CLFR_RULE_P pClfrRule,
+				WIMAX_PHS_RULE_P pPHSRule);
+int sdk_sf_CmdChangeSF(api_hand_t *api_hand, int dev_idx,
+				WIMAX_SF_PARAM_P pSFParam,
+				WIMAX_CLFR_DSC_ACTION CLFRDSCAction,
+				WIMAX_CLFR_RULE_P pClfrRule,
+				WIMAX_PHS_DSC_ACTION PHSDSCAction,
+				WIMAX_PHS_RULE_P pPHSRule);
+int sdk_sf_CmdDeleteSF(api_hand_t *api_hand, int dev_idx,
+				WIMAX_SF_PARAM_P pSFParam);
+int sdk_sf_recv_dsx_complete(int dev_idx, u8 *buf, int len);
+#endif // CONFIG_ENABLE_SERVICE_FLOW
+
+int sdk_ind_recv_hci_pkt(int dev_idx, char *buf, int len);
+int sdk_ind_dev_insert_remove(int dev_idx, bool is_insert);
+int sdk_ind_status_update(int dev_idx, u8 *buf, int len);
+int sdk_ind_if_updown(int dev_idx, u8 *buf, int len);
+int sdk_ind_power_ctrl(sdk_internal_t *sdk, int dev_idx, bool on);
+int sdk_ind_connect_net(sdk_internal_t *sdk, int dev_idx, bool success);
+int sdk_ind_disconnect_net(sdk_internal_t *sdk, int dev_idx, bool success);
+int sdk_ind_net_search_wscan(sdk_internal_t *sdk, int dev_idx);
+int sdk_ind_rf_state(int dev_idx, u8 *buf, int len);
+int sdk_ind_provisioning_op(int dev_idx, WIMAX_API_PROV_OPERATION operation,
+	WIMAX_API_CONTACT_TYPE contact_type);
+int sdk_ind_noti(int dev_idx, GCT_API_NOTI_CATEGORY category,
+						GCT_API_NOTI_TYPE type, char *buf, int len);
+int sdk_ind_power_mode_change(int dev_idx, u8 *buf, int len);
+
+int sdk_reg_recv_hci_packet(api_hand_t *api_hand, SDKIndRcvHCIPacket callback);
+int sdk_reg_dev_insert_remove(api_hand_t *api_hand, SDKIndDeviceInsertRemove callback);
+int sdk_reg_ctrl_power_mng(api_hand_t *api_hand, SDKIndControlPowerManagement callback);
+int sdk_reg_dev_stat_update(api_hand_t *api_hand, SDKIndDeviceStatusUpdate callback);
+int sdk_reg_connect_network(api_hand_t *api_hand, SDKIndConnectToNetwork callback);
+int sdk_reg_disconnect_network(api_hand_t *api_hand,
+		SDKIndDisconnectFromNetwork callback);
+int sdk_reg_network_search_wscn(api_hand_t *api_hand,
+		SDKIndNetworkSearchWideScan callback);
+int sdk_reg_provisioning_op(api_hand_t *api_hand, SDKIndProvisioningOperation callback);
+int sdk_reg_package_update(api_hand_t *api_hand, SDKIndPackageUpdate callback);
+int sdk_reg_notification(api_hand_t *api_hand, SDKIndNotification callback);
+int sdk_reg_mode_change(api_hand_t *api_hand, SDKIndModeChange callback);
+
+#if defined(CONFIG_ENABLE_SERVICE_FLOW)
+int sdk_reg_noti_service_flow(api_hand_t *api_hand,
+				SDKIndNotiServiceFlow callback);
+#endif // CONFIG_ENABLE_SERVICE_FLOW
+
+#define sdk_unreg_recv_hci_packet(api_hand)\
+			sdk_reg_recv_hci_packet(api_hand, (SDKIndRcvHCIPacket)0)
+#define sdk_unreg_dev_insert_remove(api_hand)\
+			sdk_reg_dev_insert_remove(api_hand, (SDKIndDeviceInsertRemove)0)
+#define sdk_unreg_ctrl_power_mng(api_hand)\
+			sdk_reg_ctrl_power_mng(api_hand, (SDKIndControlPowerManagement)0)
+#define sdk_unreg_dev_stat_update(api_hand)\
+			sdk_reg_dev_stat_update(api_hand, (SDKIndDeviceStatusUpdate)0)
+#define sdk_unreg_connect_network(api_hand)\
+			sdk_reg_connect_network(api_hand, (SDKIndConnectToNetwork)0)
+#define sdk_unreg_disconnect_network(api_hand)\
+			sdk_reg_disconnect_network(api_hand, (SDKIndDisconnectFromNetwork)0)
+#define sdk_unreg_network_search_wscn(api_hand)\
+			sdk_reg_network_search_wscn(api_hand, (SDKIndNetworkSearchWideScan)0)
+#define sdk_unreg_provisioning_op(api_hand)\
+			sdk_reg_provisioning_op(api_hand, (SDKIndProvisioningOperation)0)
+#define sdk_unreg_package_update(api_hand)\
+			sdk_reg_package_update(api_hand, (SDKIndPackageUpdate)0)
+#define sdk_unreg_notification(api_hand)\
+			sdk_reg_notification(api_hand, (SDKIndNotification)0)
+#define sdk_unreg_mode_change(api_hand)\
+			sdk_reg_mode_change(api_hand, (SDKIndModeChange)0)
+
+#if defined(CONFIG_ENABLE_SERVICE_FLOW)
+#define sdk_unreg_noti_service_flow(api_hand)\
+			sdk_reg_noti_service_flow(api_hand, (SDKIndNotiServiceFlow)0)
+#endif // CONFIG_ENABLE_SERVICE_FLOW
+
+int sdk_set_errno(int err_no);
+int sdk_get_errno(void);
+
+
+int sdk_read_file(const char *file, void *buf, int size);
+int sdk_write_file(const char *file, void *buf, int size, int flags);
+#define sdk_creat_file(file, buf, size)	\
+		sdk_write_file(file, buf, size, O_CREAT|O_WRONLY|O_TRUNC)
+#define sdk_append_file(file, buf, size)	\
+		sdk_write_file(file, buf, size, O_APPEND)
+#endif
+
diff --git a/sdk/sf.c b/sdk/sf.c
new file mode 100644
index 0000000..5f1f101
--- /dev/null
+++ b/sdk/sf.c
@@ -0,0 +1,2892 @@
+// 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.
+
+/*
+ * sf.c - WIMAX service flow manipulation
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+
+#include <sys/sem.h>
+#include <sys/shm.h>
+#include "gcttype.h"
+#include "device.h"
+#include "sdk.h"
+#include "sf.h"
+
+#define DSX_REQUEST_TIMEOUT	10
+
+/*----------------------------------------------------------------------
+ *
+ * Common to SDK server and client
+ *
+ *----------------------------------------------------------------------*/
+const WIMAX_CLFR_RULE classifier_rule_init = {
+	.IPTypeOfService.low		= 1,
+	.Protocol			= 255,
+	.IPv4MaskedSourceAddress = {
+		.address.s_addr 	= 0xffffffffUL,
+	},
+	.IPv4MaskedDestAddress = {
+		.address.s_addr 	= 0xffffffffUL,
+	},
+	.IPv6MaskedSourceAddress = {
+		.address 	= IN6ADDR_LOOPBACK_INIT,
+	},
+	.IPv6MaskedDestAddress = {
+		.address 	= IN6ADDR_LOOPBACK_INIT,
+	},
+	.ProtocolSourcePort.low		= 1,
+	.ProtocolDestPort.low		= 1,
+	.EthernetDestMACAddress = {
+		.addr 			= {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+	},
+	.EthernetSourceMACAddress = {
+		.addr 			= {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+	},
+	.EtherType.type 		= 4,
+	.IEEE802_1D_UserPriority.low	= 8,
+	.IEEE802_1Q_VLANID 		= 0xfff,
+	.AssociatedPHSI			= 0,
+};
+
+
+const WIMAX_PHS_RULE phs_rule_init = {
+	.PHSI	= 0,
+	.PHSS	= 0,
+	.PHSV 	= 0,
+};
+
+/*
+ * TLV related routines
+ */
+
+/*
+ * ptr - points where L is expected.
+ * ll - actual length of this TLV.
+ * returns a pointer to the location where V starts.
+ */ 
+static uint8_t *sf_hci_calc_length(uint8_t *ptr, uint32_t *l)
+{
+	uint8_t ll = *ptr;	/* length of length */
+	int i;
+	
+	if (ll < 0x80) {
+		*l = (uint32_t) ll;
+		return ptr+1;	/* V starts right after ptr */
+	}
+	
+	assert(ll != 0x80);
+	ll &= ~0x80;
+
+	/* Here, l is the length (in byte) of L */
+	*l = 0;
+	for (i = 1; i <= ll; i++) {
+		*l = (*l << 8) + ptr[i];
+	}
+	/* assert(ll == 2); */
+	/*(*l) = ntohs(*l);*/
+
+	return ptr + ll + 1; /* V starts ll bytes after ptr */
+}
+
+/* Find a TLV within [start, end)
+ *
+ * 
+ * return 1 if found, 0, otherwise.
+ */
+
+static int32_t sf_hci_find_tlv_range(struct hci *pkt, uint8_t T, uint32_t *L, uint8_t **V,
+			    uint32_t start, uint32_t end)
+{
+	uint8_t *ptr = pkt->data + start;
+	
+	while (ptr < pkt->data + end) {
+		if (*ptr == T) {
+			*V = sf_hci_calc_length(ptr + 1, L);
+			return 1;
+		}
+		ptr = sf_hci_calc_length(ptr + 1, L);
+
+		/* ptr points to the start of V */
+		ptr += *L; /* T: 1 byte, L: 1 byte: V: L byte */
+	}
+	
+	return 0;
+}
+
+/*
+ * hci_get_tlv() obtains T, L, and V of a TLV variable at
+ * the offset @oft.
+ *
+ * It is up to the caller to provide a valid @oft. Otherwise,
+ * this function won't work correctly.
+ */
+static uint32_t sf_hci_get_tlv(struct hci *pkt, uint8_t *T, uint32_t *L, uint8_t **V, uint32_t oft)
+{
+	uint8_t *ptr = pkt->data + oft;
+	
+	*T = *ptr++;
+	*V = ptr = sf_hci_calc_length(ptr, L);
+
+	return ptr + *L - pkt->data;
+}
+
+/*
+ * Currently, l < 0x10000 is only supported.
+ *
+ * In addition, this routine blindly sets LL to be 2 regardless of
+ * actual value of l.
+ *
+ */
+static uint8_t *sf_hci_put_length(uint8_t *ptr, uint32_t l)
+{
+	if (l < 0x80) {
+		*ptr = (uint8_t)(l & 0xff);
+		return ptr+1;
+	}
+
+	assert(l < 0x10000);
+	*ptr++ = 0x82;
+	*ptr++ = (l >> 8) & 0xff;
+	*ptr++ = (l & 0xff);
+
+	return ptr;
+}
+
+/*
+ * sf_hci_append_tlv() - appends given (T, L, V) to the current hci packet pkt.
+ *
+ * pkt->length is increased appropriately.
+ * The function returns the last offset of hci packet after appending the given
+ * (T, L, V).
+ */
+static void sf_hci_append_tlv(struct hci *pkt, uint8_t T, uint32_t L, void *V)
+{
+	unsigned oft = pkt->length;
+	unsigned char *ptr = pkt->data + oft;
+	
+	*ptr++ = T;
+	
+	ptr = sf_hci_put_length(ptr, L);
+	memcpy(ptr, V, L);
+
+	pkt->length = (ptr + L) - pkt->data;
+
+	return;
+}
+
+/*
+ * hci->cmd_evt: host byte order
+ * hci->length: host byte order
+ */
+static int sf_send_hci(int dev_idx, struct hci *hci)
+{
+	return hci_send(dev_idx, WIMAX_DSX_REQUEST, hci->data, hci->length);
+}
+
+static inline unsigned get_unaligned_u32(void *ptr)
+{
+	unsigned char *p = (unsigned char *)ptr;
+	
+	return ntohl(((p[0] << 24)|(p[1] << 16)|(p[2] << 8)|p[3]));
+}
+
+static inline unsigned get_unaligned_u16(void *ptr)
+{
+	unsigned char *p = (unsigned char *)ptr;
+	
+	return ntohs((u_short)((p[0] << 8) | p[1]));
+}
+
+static inline void put_unaligned_u32(void *ptr, unsigned le_val)
+{
+	unsigned char *p = (unsigned char *)ptr;
+	le_val = htonl(le_val);
+	
+	*p++ = (le_val >> 24) & 0xff;
+	*p++ = (le_val >> 16) & 0xff;
+	*p++ = (le_val >> 8) & 0xff;
+	*p++ = le_val & 0xff;
+}
+
+static inline void put_unaligned_u16(void *ptr, unsigned le_val)
+{
+	unsigned char *p = (unsigned char *)ptr;
+	
+	le_val = htons((u_short)le_val);
+	
+	*p++ = (le_val >> 8) & 0xff;
+	*p++ = le_val & 0xff;	
+}
+
+/*
+ * find_service_flow() attempts to find the service flow
+ * that matches the given @sfid.
+ */
+struct wimax_service_flow *find_service_flow(int dev_idx,
+					     uint32_t sfid)
+{
+	device_t *dev;
+	struct wimax_service_flow *sf;
+	int i;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return NULL;
+	
+	for (i = 0; i < WIMAX_MAX_SERVICE_FLOW; i++) {
+		sf = dev->wimax->dev_info.service_flow.sf + i;
+		if (sf->valid && sf->param.SFID == sfid)
+			goto out;
+	}
+	sf = NULL;
+
+out:
+	dm_put_dev(dev_idx);
+	xfunc_out();
+	return sf;
+}
+
+
+struct wimax_classification_rule *
+find_classification_rule(struct wimax_service_flow *sf, uint16_t index)
+{
+	struct wimax_classification_rule *rule;
+	int i;
+
+	rule = sf->classification_rule;
+	for (i = 0; i < WIMAX_MAX_RULES; i++, rule++) {
+		if (rule->valid && rule->PacketClassifierRuleIndex == index) {
+			return rule;
+		}
+	}
+	return NULL;
+}
+
+static struct wimax_classification_rule *
+next_classification_rule(struct wimax_service_flow *sf,
+			 struct wimax_classification_rule *start)
+{
+	struct wimax_classification_rule *rule;
+
+	if (start == NULL)
+		rule = sf->classification_rule;
+	else
+		rule = start + 1;
+
+	for (; rule - sf->classification_rule < WIMAX_MAX_RULES; rule++)
+		if (rule->valid)
+			return rule;
+
+	return NULL;
+}
+
+
+
+struct wimax_phs_rule *find_phs_rule(struct wimax_service_flow *sf,
+				     uint16_t index)
+{
+	struct wimax_phs_rule *rule;
+	int i;
+
+	rule = sf->phs_rule;
+	for (i = 0; i < WIMAX_MAX_RULES; i++, rule++) {
+		if (rule->valid && rule->PHSI == index) {
+			return rule;
+		}
+	}
+	return NULL;
+}
+
+static struct wimax_phs_rule *
+next_phs_rule(struct wimax_service_flow *sf,
+	      struct wimax_phs_rule *start)
+{
+	struct wimax_phs_rule *rule;
+
+	if (start == NULL)
+		rule = sf->phs_rule;
+	else
+		rule = start + 1;
+
+	for (; rule - sf->phs_rule < WIMAX_MAX_RULES; rule++)
+		if (rule->valid)
+			return rule;
+
+	return NULL;
+}
+
+
+static char *schedstr[] = {"Reserved", "Undefined", "BE", "nrtPS", "rtPS", "ertPS", "UGS"};
+static char *ddsstr[] = {"UGS", "RT-VR", "NRT-VR", "BE", "ERT-VR"};
+static char *csstr[] = {
+	"Reserved",
+	"Packet, IPv4",
+	"Packet, IPv6",
+	"Packet, IEEE802.3/Ethernet",
+	"Packet, IEEE 802 1Q VLAN",
+	"Packet, IPv4 over IEEE 802.3/Ethernet",
+	"Packet, IPv6 over IEEE 802.3/Ethernet",
+	"Packet, IPv4 over IEEE 802 1Q VLAN",
+	"Packet, IPv6 over IEEE 802 1Q VLAN",
+	"ATM",
+};
+
+#define print_field(obj, x, fmt)	snprintf(str+oft, (size > oft)? size-oft: 0, "\t" #x "=" fmt "\n", obj->x)
+#define nnsize	(size > oft)? (size-oft): 0
+
+int sprintf_sf_param(char *str, unsigned int size, struct wimax_sf_param *sfp)
+{
+	int oft = 0;
+	
+	oft += print_field(sfp, DL, "%d");
+	oft += print_field(sfp, SFID, "%08x");
+	oft += print_field(sfp, CID, "%04x");
+	oft += print_field(sfp, ServiceClassName, "'%s'");
+	oft += print_field(sfp, QosParamSetType, "%d");
+	oft += print_field(sfp, TrafficPriority, "%d");
+	oft += print_field(sfp, MaxSustainedTrafficRate, "%d");
+	oft += print_field(sfp, MaxTrafficBurst, "%d");
+	oft += print_field(sfp, MinReservedTrafficRate, "%d");
+	oft += print_field(sfp, MinTolerableRate, "%d");
+	/* Even for DL, we add ULGrantSchedulingType (some BS needs this) */
+	oft += snprintf(str+oft, size-oft, "\tULGrantSchedulingType='%s'\n",
+				schedstr[sfp->ULGrantSchedulingType]);
+#if 0
+	if (!sfp->DL) {
+		oft += print_field(sfp, RequestTransmissionPolicy, "0x%02x");	    
+	}
+#endif
+	oft += print_field(sfp, RequestTransmissionPolicy, "0x%02x");	    
+	
+	oft += print_field(sfp, ToleratedJitter, "%d");
+	oft += print_field(sfp, MaxLatency, "%d");
+	oft += print_field(sfp, FixedLengthSDUIndicator, "%d");
+	if (sfp->FixedLengthSDUIndicator)
+		oft += print_field(sfp, SDUSize, "%d");
+	if (sfp->TargetSAID != 0xffff)
+		oft += print_field(sfp, TargetSAID, "%02x");
+
+	oft += print_field(sfp, ARQEnable, "%d");
+	if (sfp->ARQEnable) {
+		oft += print_field(sfp, ARQWindowSize, "%d");
+		oft += print_field(sfp, ARQTransmitterDelay, "%d");
+		oft += print_field(sfp, ARQReceiverDelay, "%d");
+		oft += print_field(sfp, ARQBlockLifeTime, "%d");
+		oft += print_field(sfp, ARQSyncLossTimeout, "%d");
+		oft += print_field(sfp, ARQDeliverInOrder, "%d");
+		oft += print_field(sfp, ARQRxPurgeTimeout, "%d");
+		oft += print_field(sfp, ARQBlockSize, "%d");
+		oft += print_field(sfp, ReceiverARQAckProcessingTime, "%d");
+	}
+
+	oft += snprintf(str+oft, nnsize, "\tCSSpecification='%s'\n",
+			csstr[sfp->CSSpecification]);
+	if (sfp->DL) 
+	    oft += snprintf(str+oft, nnsize, "\tTypeOfDataDeliveryServices='%s'\n",
+			    ddsstr[sfp->TypeOfDataDeliveryServices]);
+
+	oft += print_field(sfp, SDUInterArrivalInterval, "%d");
+	oft += print_field(sfp, TimeBase, "%d");
+	oft += print_field(sfp, PagingPreference, "%d");
+	oft += print_field(sfp, TrafficPreferenceIndication, "%d");
+	oft += print_field(sfp, SNFeedbackEnabled, "%d");
+	oft += print_field(sfp, FSNSize, "%d");
+	
+	switch (sfp->ULGrantSchedulingType) {
+		case UL_SCHED_TYPE_UGS:
+		case UL_SCHED_TYPE_ertPS:
+			oft += print_field(sfp, UnsolicitedGrantInterval, "%d");
+			break;
+		case UL_SCHED_TYPE_rtPS:
+		case UL_SCHED_TYPE_nrtPS:
+			oft += print_field(sfp, UnsolicitedPollingInterval, "%d");
+			break;
+		default:
+			break;
+	}
+	
+	oft += print_field(sfp, HARQServiceFlows, "%d");
+	if (sfp->HARQServiceFlows) {
+		oft += print_field(sfp, PDUSNExtendedSubheaderForHARQReordering, "%d");
+	}
+	return oft;
+}
+
+
+#define etherstr	"%02x:%02x:%02x:%02x:%02x:%02x"
+#define ether(x)	x[0], x[1], x[2], x[3], x[4], x[5]
+
+int sprintf_classifier_rule(char *str, unsigned int size, struct wimax_classification_rule *c)
+{
+	int oft = 0;
+	char addr[INET6_ADDRSTRLEN], mask[INET6_ADDRSTRLEN];
+	
+	if (c == NULL)
+		return 0;
+
+	oft += print_field(c, ClassifierRulePriority, "%d");
+
+	if (c->IPTypeOfService.low <= c->IPTypeOfService.high) {
+		oft += snprintf(str+oft, size, "\tToS=[%02x-%02x]/%02x\n",
+				c->IPTypeOfService.low, c->IPTypeOfService.high,
+				c->IPTypeOfService.mask);
+	}
+	oft += print_field(c, PacketClassifierRuleIndex, "%d");
+
+	if (c->Protocol != 255)
+		oft += print_field(c, Protocol, "%d");
+
+	/* IPv4 */
+	if (memcmp(&c->IPv4MaskedSourceAddress,
+		   &classifier_rule_init.IPv4MaskedSourceAddress, 8)) {
+		inet_ntop(AF_INET, &c->IPv4MaskedSourceAddress.address,
+			  addr, sizeof(addr));
+		inet_ntop(AF_INET, &c->IPv4MaskedSourceAddress.mask,
+			  mask, sizeof(mask));
+		oft += snprintf(str+oft, nnsize, "\tIPv4MaskedSourceAddress=%s/%s\n",
+				addr, mask);
+	}
+
+	if (memcmp(&c->IPv4MaskedDestAddress,
+		   &classifier_rule_init.IPv4MaskedDestAddress, 8)) {
+		inet_ntop(AF_INET, &c->IPv4MaskedDestAddress.address,
+			  addr, sizeof(addr));
+		inet_ntop(AF_INET, &c->IPv4MaskedDestAddress.mask,
+			  mask, sizeof(mask));
+		oft += snprintf(str+oft, nnsize, "\tIPv4MaskedDestAddress=%s/%s\n",
+				addr, mask);
+	}
+		    
+	/* IPv6 */
+	if (memcmp(&c->IPv6MaskedSourceAddress,
+		   &classifier_rule_init.IPv6MaskedSourceAddress, 32)) {
+		inet_ntop(AF_INET6, &c->IPv6MaskedSourceAddress.address,
+			  addr, sizeof(addr));
+		inet_ntop(AF_INET6, &c->IPv6MaskedSourceAddress.mask,
+			  mask, sizeof(mask));
+		oft += snprintf(str+oft, nnsize, "\tIPv6MaskedSourceAddress=%s/%s\n",
+				addr, mask);
+	}
+
+
+	if (memcmp(&c->IPv6MaskedDestAddress,
+		   &classifier_rule_init.IPv6MaskedDestAddress, 32)) {
+		inet_ntop(AF_INET6, &c->IPv6MaskedDestAddress.address,
+			  addr, sizeof(addr));
+		inet_ntop(AF_INET6, &c->IPv6MaskedDestAddress.mask,
+			  mask, sizeof(mask));
+		oft += snprintf(str+oft, nnsize, "\tIPv6MaskedDestAddress=%s/%s\n",
+				addr, mask);
+	}
+
+	if (c->Protocol != 255) {
+		if (c->ProtocolSourcePort.low <= c->ProtocolSourcePort.high) {
+			oft += snprintf(str+oft, nnsize, "\tSourcePort=[%d-%d]\n",
+					c->ProtocolSourcePort.low, c->ProtocolSourcePort.high);
+		}
+	
+		if (c->ProtocolDestPort.low <= c->ProtocolDestPort.high) {
+			oft += snprintf(str+oft, nnsize, "\tDestPort=[%d-%d]\n",
+					c->ProtocolDestPort.low, c->ProtocolDestPort.high);
+		}
+	}
+
+	/* Ether */
+	if (memcmp(&c->EthernetDestMACAddress,
+		   &classifier_rule_init.EthernetDestMACAddress, 12)) {
+		oft += snprintf(str+oft, nnsize, "\tEthernetDestMACAddress=" etherstr "/" etherstr"\n",
+				ether(c->EthernetDestMACAddress.addr),
+				ether(c->EthernetDestMACAddress.mask));		
+	}
+
+	if (memcmp(&c->EthernetSourceMACAddress,
+		   &classifier_rule_init.EthernetSourceMACAddress, 12)) {
+		oft += snprintf(str+oft, nnsize, "\tEthernetSourceMACAddress=" etherstr "/" etherstr"\n",
+				ether(c->EthernetSourceMACAddress.addr),
+				ether(c->EthernetSourceMACAddress.mask));
+	}
+
+	if (c->EtherType.type != 4) {
+		oft += snprintf(str+oft, nnsize, "\tEtherType={type=%d, %02x%02x}\n",
+				c->EtherType.type, c->EtherType.eprot1, c->EtherType.eprot2);
+	}
+
+	if (c->IEEE802_1D_UserPriority.low < 8)
+		oft += snprintf(str+oft, nnsize, "\tIEEE802_1D_UserPriority=[%d-%d]\n",
+				c->IEEE802_1D_UserPriority.low,
+				c->IEEE802_1D_UserPriority.high);
+
+	if (c->IEEE802_1Q_VLANID != 0xfff)
+		oft += snprintf(str+oft, nnsize, "\tIEEE802_1Q_VLANID=%04x\n",
+				c->IEEE802_1Q_VLANID);
+
+	if (c->AssociatedPHSI != 0)
+		oft += print_field(c, AssociatedPHSI, "%d");
+
+	return oft;
+}
+
+int sprintf_phs_rule(char *str, unsigned int size, struct wimax_phs_rule *p)
+{
+	int oft = 0, i = 0, phsm_size;
+
+	if ((p == NULL) || !p->PHSS)
+		return 0;
+	
+	if (p->PHSI)
+		oft += print_field(p, PHSI, "%d");
+
+	oft += print_field(p, PHSS, "%d");
+	
+	/* PHSM */
+	if (p->PHSM) {
+		phsm_size = (p->PHSS + 7)/8;
+		oft += snprintf(str+oft, size, "\tPHSM=");
+		for (i=0; i < phsm_size; i++) {
+			oft += snprintf(str+oft, nnsize, "%02x", p->PHSM[i]);
+		}
+		oft += snprintf(str+oft, nnsize, "\n");
+	}
+	
+	/* PHSF */
+	if (p->PHSF) {
+		oft += snprintf(str+oft, nnsize, "\tPHSF=");
+		for (i=0; i < p->PHSS; i++) {
+			oft += snprintf(str+oft, nnsize, "%02x", p->PHSF[i]);
+		}
+		oft += snprintf(str+oft, nnsize, "\n");
+	}
+	
+	oft += print_field(p, PHSV, "%d");
+
+	return oft;
+}
+
+static const char *ccstr[] = {
+	"OK/Success",
+	"reject-other",
+	"reject-unrecoginized-configuration-setting",
+	"reject-temporary/reject-resource",
+	"reject-permanent/reject-admin",
+	"reject-not-owner",
+	"reject-service-flow-not-found",
+	"reject-service-flow-exists",
+	"reject-required-parameter-not-present",
+	"reject-header-suppression",
+	"reject-unknown-transaction-id",
+	"reject-authentication-failure",
+	"reject-add-aborted",
+	"reject-exceeded-dynamic-service-limit",
+	"reject-not-authorized-for-requested-SAID",
+	"reject-fail-to-establish-the-requested-SA",
+	"reject-not-supported-parameter",
+	"reject-not-supported-parameter-value",
+};
+
+const char *wimax_stringify_dsx_cc(WIMAX_SF_CC cc)
+{
+	if (cc >= WIMAX_SF_SUCCESS &&
+	    cc <= WIMAX_SF_NOT_SUPPORTED_PARAMETER_VALUE)
+		return ccstr[cc];
+	else if (cc == 128)
+		return "reject-time-out";
+	else
+		return "reject-unknown";
+}
+
+/*----------------------------------------------------------------------
+ *
+ * SDK server routines
+ *
+ *----------------------------------------------------------------------*/
+
+#define C_RULE_PARAM(i, l, x) {i, l, offsetof(struct wimax_classification_rule, x)}
+#define PHS_RULE_PARAM(i, x) {i, 0, offsetof(struct wimax_phs_rule, x)}
+#define SF_PARAM(i, x)	{i, 0, offsetof(struct wimax_sf_param, x)}
+
+struct tlv_offset {
+	uint8_t		T;
+	uint32_t	L;
+	uint32_t	offset;
+};
+
+struct tlv_offset c_rule_oft_tbl[] = {
+	C_RULE_PARAM(1, 1, ClassifierRulePriority),
+	C_RULE_PARAM(2, 3, IPTypeOfService),
+	C_RULE_PARAM(3, 1, Protocol),
+	C_RULE_PARAM(4, 8, IPv4MaskedSourceAddress),
+	C_RULE_PARAM(5, 8, IPv4MaskedDestAddress),
+	C_RULE_PARAM(6, 4, ProtocolSourcePort),
+	C_RULE_PARAM(7, 4, ProtocolDestPort),
+	C_RULE_PARAM(8, 12, EthernetDestMACAddress),
+	C_RULE_PARAM(9, 12, EthernetSourceMACAddress),
+	C_RULE_PARAM(10, 3, EtherType),
+	C_RULE_PARAM(11, 2, IEEE802_1D_UserPriority),
+	C_RULE_PARAM(12, 2, IEEE802_1Q_VLANID),
+	C_RULE_PARAM(13, 1, AssociatedPHSI),
+	C_RULE_PARAM(14, 2, PacketClassifierRuleIndex),
+	C_RULE_PARAM(15, 3, IPv6FlowLabel),
+	C_RULE_PARAM(18, 1, ContextID),
+};
+
+struct tlv_offset phs_tlv_oft_tbl[] = {
+	PHS_RULE_PARAM(1, PHSI),
+	PHS_RULE_PARAM(2, PHSF),
+	PHS_RULE_PARAM(3, PHSM),
+	PHS_RULE_PARAM(4, PHSS),
+	PHS_RULE_PARAM(5, PHSV),
+};
+
+struct tlv_offset sf_tlv_oft_tbl[] = {
+	SF_PARAM(1, SFID),
+	SF_PARAM(2, CID),
+	SF_PARAM(3, ServiceClassName),
+	SF_PARAM(4, MBSService),
+	SF_PARAM(5, QosParamSetType),
+	SF_PARAM(6, TrafficPriority),
+	SF_PARAM(7, MaxSustainedTrafficRate),
+	SF_PARAM(8, MaxTrafficBurst),
+	SF_PARAM(9, MinReservedTrafficRate),
+	SF_PARAM(10, MinTolerableRate),
+	SF_PARAM(11, ULGrantSchedulingType),
+	SF_PARAM(12, RequestTransmissionPolicy),
+	SF_PARAM(13, ToleratedJitter),
+	SF_PARAM(14, MaxLatency),
+	SF_PARAM(15, FixedLengthSDUIndicator),
+	SF_PARAM(16, SDUSize),
+	SF_PARAM(17, TargetSAID),
+	SF_PARAM(18, ARQEnable),
+	SF_PARAM(19, ARQWindowSize),
+	SF_PARAM(20, ARQTransmitterDelay),
+	SF_PARAM(21, ARQReceiverDelay),
+	SF_PARAM(22, ARQBlockLifeTime),
+	SF_PARAM(23, ARQSyncLossTimeout),
+	SF_PARAM(24, ARQDeliverInOrder),
+	SF_PARAM(25, ARQRxPurgeTimeout),
+	SF_PARAM(26, ARQBlockSize),
+	SF_PARAM(27, ReceiverARQAckProcessingTime),
+	SF_PARAM(28, CSSpecification),
+	SF_PARAM(29, TypeOfDataDeliveryServices),	// 29
+	SF_PARAM(30, SDUInterArrivalInterval),	// 30
+	SF_PARAM(31, TimeBase),			// 31
+	SF_PARAM(32, PagingPreference),		// 32
+	SF_PARAM(33, MBSZoneID),			// 33
+	SF_PARAM(34, TrafficPreferenceIndication),	// 34
+	SF_PARAM(35, GlobalServiceClassName),	// 35
+	SF_PARAM(36, SNFeedbackEnabled),		// 37
+	SF_PARAM(38, FSNSize),			// 38
+	SF_PARAM(39, CIDAllocForActiveBSs),	// 39 ??
+	SF_PARAM(40, UnsolicitedGrantInterval),	// 40
+	SF_PARAM(41, UnsolicitedPollingInterval),	// 41
+	SF_PARAM(42, PDUSNExtendedSubheaderForHARQReordering),	// 42
+	SF_PARAM(43, MBSContentsIDs),	// 43
+	SF_PARAM(44, HARQServiceFlows),		// 44
+	SF_PARAM(45, AuthorizationToken),
+	SF_PARAM(46, HARQChannelMapping),
+};
+
+static int32_t param_offset(struct tlv_offset *table, uint32_t nr_entry, uint8_t T)
+{
+	uint32_t i;
+
+	for (i = 0; i < nr_entry; i++) {
+		if (table[i].T == T)
+			return table[i].offset;
+	}
+
+	return -1;
+}
+
+
+/*----------------------------------------------------------------------
+ *
+ * CLASSIFICATION RULE
+ *
+ *----------------------------------------------------------------------*/
+struct wimax_classification_rule *
+create_classification_rule(struct wimax_service_flow *sf)
+{
+	struct wimax_classification_rule *rule;
+	int i;
+
+	rule = sf->classification_rule;
+	for (i = 0; i < WIMAX_MAX_RULES; i++, rule++) {
+		if (!rule->valid) {
+			*rule = classifier_rule_init;
+			rule->valid = 1;
+			return rule;
+		}
+	}
+	return NULL;	
+}
+
+void
+remove_classification_rule(struct wimax_service_flow *sf,
+			   struct wimax_classification_rule *rule)
+{
+	rule->valid = 0;
+}
+
+void
+remove_all_classification_rule(struct wimax_service_flow *sf)
+{
+	struct wimax_classification_rule *rule;
+	int i;
+
+	rule = sf->classification_rule;
+	for (i = 0; i < WIMAX_MAX_RULES; i++, rule++)
+		remove_classification_rule(sf, rule);
+}
+
+
+/*
+ * crule_param_offset() gives the offset ofthe member of the
+ * struct wimax_classification_rule, which corresponds to the given @T.
+ *
+ * For example, T=2 corresponds to struct wimax_classification_rule:IPTypeofService,
+ * whose offset is XXX in struct wimax_classification_rule.
+ */
+static inline int32_t crule_param_offset(uint8_t T) {
+	
+	return param_offset(c_rule_oft_tbl,
+			    sizeof(c_rule_oft_tbl)/sizeof(c_rule_oft_tbl[0]),
+			    T);
+}
+
+
+/*
+ * update_classification_rule() updates a particular classifier rule
+ * pointed to by @rule with the content in DSx_Complete HCI packet @pkt.
+ *
+ * @start and @end are the offsets in @pkt->data where service flow TLV
+ * [145/146].cst.3.xxx starts and ends, respectively.
+ *
+ * Currently, we simply update individual members of
+ * struct wimax_classification_rule depending on the TLVs included in @pkt.
+ */
+void update_classification_rule(struct wimax_service_flow *sf,
+				struct wimax_classification_rule *rule,
+				struct hci *pkt,
+				uint32_t start, uint32_t end)
+{
+	uint8_t T, *V;
+	uint32_t L;
+
+	while (start < end) {
+		start = sf_hci_get_tlv(pkt, &T, &L, &V, start);
+		memcpy((void *)rule + crule_param_offset(T), V, L);
+		rule->mask.all |= (1<<T);
+	}
+
+	return;
+}
+
+/*
+ * update_classification() updates (add/replace/delete) a particular
+ * classifier rules associated with given @sf.
+ *
+ * @sf: a service flow to work upon.
+ * @pkt: DSX_Complete HCI message received from the device.
+ * @start, @end: [@start, @end) contains the value of the
+ *  compound TLV [145/146].cst.
+ *
+ */
+
+int update_classification(struct wimax_service_flow *sf,
+			  struct hci *pkt,
+			  uint32_t start, uint32_t end,
+			  WIMAX_SF_EVENT_P event)
+{
+	uint32_t L, pstart, pend;
+	uint8_t *param, *V;
+	uint16_t index;
+	struct wimax_classification_rule *rule;
+
+	while (start < end) {
+
+		/* Search for [145/146].cst.3 - Classification rule parameter (compound) */
+		if (!sf_hci_find_tlv_range(pkt, 3, &L, &param, start, end))
+			break; /* No classifier rules - go out */
+
+		pstart = param - pkt->data;
+		pend = pstart + L;
+		
+		/* Search for [145/146].cst.3.14 - ClassifierRuleIndex */
+		if (!sf_hci_find_tlv_range(pkt, 14, &L, &V, pstart, pend)) {
+			xprintf(SDK_DBG, "Cannot find RuleIndex\n");
+			return -1;
+		}
+		index = get_unaligned_u16(V);
+	
+		if (!(rule = find_classification_rule(sf, index)))
+			rule = create_classification_rule(sf);
+		if (!rule) {
+			xprintf(SDK_ERR, "Too many classification rules\n");
+			return -1;
+		}
+
+		update_classification_rule(sf, rule, pkt, pstart, pend);
+
+		start = pend;
+	}
+
+	return 0;
+}
+
+/*----------------------------------------------------------------------
+ *
+ * PHS RULE
+ *
+ *----------------------------------------------------------------------*/
+struct wimax_phs_rule *create_phs_rule(struct wimax_service_flow *sf)
+{
+	struct wimax_phs_rule *rule;
+	int i;
+	
+	rule = sf->phs_rule;
+	for (i = 0; i < WIMAX_MAX_RULES; i++, rule++) {
+		if (!rule->valid) {
+			*rule = phs_rule_init;
+			rule->valid = 1;
+			return rule;
+		}
+	}
+	return NULL;	
+}
+
+void remove_phs_rule(struct wimax_service_flow *sf,
+		     struct wimax_phs_rule *rule)
+{
+	rule->valid = 0;
+}
+
+
+void remove_all_phs_rule(struct wimax_service_flow *sf)
+{
+	struct wimax_phs_rule *rule;
+	int i;
+
+	rule = sf->phs_rule;
+	for (i = 0; i < WIMAX_MAX_RULES; i++, rule++)
+		remove_phs_rule(sf, rule);
+}
+
+
+
+static inline int32_t phs_rule_param_offset(uint8_t T) {
+	
+	return param_offset(phs_tlv_oft_tbl,
+			    sizeof(phs_tlv_oft_tbl)/sizeof(phs_tlv_oft_tbl[0]),
+			    T);
+}
+
+/*
+ * [145/146].cst.6.xxx
+ */
+uint32_t update_phs_rule(struct wimax_service_flow *sf,
+			 struct wimax_phs_rule *rule,
+			 struct hci *pkt,
+			 uint32_t start, uint32_t end)
+{
+	uint8_t T, *V;
+	uint32_t L;
+
+	while (start < end) {
+		start = sf_hci_get_tlv(pkt, &T, &L, &V, start);
+		memcpy((void *)rule + phs_rule_param_offset(T), V, L);
+	}
+
+	return 0;
+}
+
+
+int update_phs(struct wimax_service_flow *sf,
+	       struct hci *pkt,
+	       uint32_t start, uint32_t end,
+	       WIMAX_SF_EVENT_P event)
+{
+	uint8_t *V;
+	uint32_t L, pstart, pend;
+	uint8_t *param;
+	struct wimax_phs_rule *rule;
+	uint8_t phsi;
+
+	while (start < end) {
+	    
+		/* Search for [145/146].cst.6 - PHS rule parameter (compound) */
+		if (!sf_hci_find_tlv_range(pkt, 6, &L, &param, start, end)) {
+			xprintf(SDK_DBG, "Could not find PHS Rule parameter\n");
+			goto out;
+		}
+
+		pstart = param - pkt->data;
+		pend = pstart + L;
+
+		/* Search for [145/146].cst.6.1 */
+		if (!sf_hci_find_tlv_range(pkt, 1, &L, &V, pstart, pend)) {
+			xprintf(SDK_DBG, "Cannot find PHSI\n");
+			goto out;
+		}
+		phsi = *V;
+
+		if (!(rule = find_phs_rule(sf, phsi)))
+			rule = create_phs_rule(sf);
+		if (!rule) {
+			xprintf(SDK_ERR, "Too many PHS rules\n");
+			return -1;
+		}
+			
+		update_phs_rule(sf, rule, pkt, pstart, pend);
+
+		start = pend;
+	}
+out:
+	return 0;
+}
+
+
+
+/*----------------------------------------------------------------------
+ *
+ * SERVICE FLOW
+ *
+ *----------------------------------------------------------------------*/
+
+static inline int32_t sf_param_offset(uint8_t T) {
+	
+	return param_offset(sf_tlv_oft_tbl,
+			    sizeof(sf_tlv_oft_tbl)/sizeof(sf_tlv_oft_tbl[0]),
+			    T);
+}
+
+
+struct wimax_service_flow *create_service_flow(int dev_idx,
+					       uint32_t sfid,
+					       uint8_t direction)
+{
+	device_t *dev;
+	struct wimax_service_flow *sf;
+	int i;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return NULL;
+	
+	for (i = 0; i < WIMAX_MAX_SERVICE_FLOW; i++) {
+		sf = dev->wimax->dev_info.service_flow.sf + i;
+		if (!sf->valid) {
+			/* Clear the service flow parameter */
+			memset(&sf->param, 0, sizeof(sf->param));
+			sf->param.SFID = sfid;
+			sf->param.DL = direction;
+			sf->param.TargetSAID = 0xffff;
+			sf->valid = 1;			
+			goto out;
+		}
+	}
+	sf = NULL;
+
+out:
+	dm_put_dev(dev_idx);
+	xfunc_out();
+	return sf;
+}
+
+void remove_service_flow(int dev_idx,
+			 struct wimax_service_flow *sf)
+{
+	sf->valid = 0;
+}
+
+void remove_all_service_flow(int dev_idx)
+{
+	device_t *dev;
+	struct wimax_service_flow *sf;
+	int i;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return;
+	
+	for (i = 0; i < WIMAX_MAX_SERVICE_FLOW; i++) {
+		sf = dev->wimax->dev_info.service_flow.sf + i;
+		
+		remove_all_classification_rule(sf);
+		remove_all_phs_rule(sf);
+		remove_service_flow(dev_idx, sf);
+	}
+
+	dm_put_dev(dev_idx);
+	xfunc_out();	
+}
+
+
+/*
+ * @sf (in): service flow to fill
+ * @payload: payload of DSx_Complete message that starts with 145/146.
+ */
+void update_service_flow(struct wimax_service_flow *sf,
+			 struct hci *pkt,
+			 uint32_t start, uint32_t end, uint8_t change,
+			 WIMAX_SF_EVENT_P event)
+{
+	uint8_t T, *V, cs;
+	uint32_t L, cstart, cend, oft = start;
+
+	while (oft < end) {
+		oft = sf_hci_get_tlv(pkt, &T, &L, &V, oft);
+		switch (T) {
+		default:
+			memcpy((void *)(&sf->param) + sf_param_offset(T), V, L);
+			break;
+		case 46:
+			/* TODO */
+			break;
+		case 99:	/* ATM */
+			cs = 9;
+			/* fall-through */
+		case 100:	/* Packet, IPv4 */
+		case 101:	/* Packet, IPv6 */
+		case 102:	/* Packet, IEEE 802.3/Ethernet */
+		case 103:	/* Packet, IEEE 802 1Q VLAN */
+		case 104:	/* Packet IPv4 over IEEE 802.3/Ethernet */ 
+		case 105:	/* Packet IPv6 over IEEE 802.3/Ethernet */
+		case 106:	/* Packet IPv4 over IEEE 802.1Q VLAN */
+		case 107:	/* Packet IPv6 over IEEE 802.1Q VLAN */
+			cs = T - 99;
+			if (sf->param.CSSpecification != cs) {
+				xprintf(SDK_NOTICE, "CS specification mismatch!\n");
+				break;
+			}
+			cstart = V - pkt->data;
+			cend = cstart + L;
+			update_classification(sf, pkt, cstart, cend, event);
+			update_phs(sf, pkt, cstart, cend, event);
+			break;
+		}
+	}
+}
+
+static int dev_notify_event(int dev_idx, WIMAX_SF_EVENT_P pSfEvent)
+{
+	sdk_internal_t *sdk = sdk_get_rw_handle();
+	dev_hand_t dev_hand;
+
+	xfunc_in("sfEvent->code=%d, confirm code=%d", pSfEvent->code, pSfEvent->sf.cc);
+
+	if (sdk->ind.noti_service_flow) {
+		dev_hand.api = sdk->api;
+		dev_hand.dev_idx = dev_idx;
+		xprintf(SDK_DBG, "Call callback(%s)\n", __FUNCTION__);
+		sdk->ind.noti_service_flow(&dev_hand, pSfEvent);
+	}
+	
+	xfunc_out();
+
+	return 0;
+}
+
+/* 
+ * compare the received service flow with the previous one to generate the event 
+ * Event generated:
+ *   - SF changed (classification/phs rule added/removed/changed)
+ */
+int compare_service_flow(struct wimax_service_flow *sf, 
+			 struct wimax_service_flow *old, 
+			 int dev_idx, 
+			 WIMAX_SF_EVENT_P event)
+{
+	struct wimax_classification_rule *clfr = NULL, *clfr_old = NULL;
+	struct wimax_phs_rule *phs = NULL, *phs_old = NULL;
+	uint8_t found = 0;
+
+	event->sf.phs_action = DSC_NOP_PHS;
+	event->sf.PHSI = 0;
+	
+	/* classification rule */
+	while ((clfr = next_classification_rule(sf, clfr))) {
+		while ((clfr_old = next_classification_rule(old, clfr_old))) {
+			if (clfr->PacketClassifierRuleIndex == clfr_old->PacketClassifierRuleIndex) {
+				found = 1;
+				/* replace */
+				if (memcmp(clfr, clfr_old, sizeof(struct wimax_classification_rule)) != 0) {
+					event->sf.clfr_action = DSC_REPLACE_CLASSIFIER;
+					event->sf.PacketClassificationRuleIndex = clfr->PacketClassifierRuleIndex;
+					dev_notify_event(dev_idx, event);
+				}
+				break;
+			}
+		}
+		
+		/* If the clfr of the received sf is not matched to any rule in the previous sf, 
+		 * it is regarded as newly added.
+		 * If it is matched to any rule, delete clfr in the previous sf.
+		 */
+		if (!found) {
+			event->sf.clfr_action = DSC_ADD_CLASSIFIER;
+			event->sf.PacketClassificationRuleIndex = clfr->PacketClassifierRuleIndex;
+			dev_notify_event(dev_idx, event);
+		} else 
+			remove_classification_rule(old, clfr_old);	/* delete the found one for replace */
+		
+		found = 0;
+	}
+	
+	/* find the removed classification rule index
+	 * If there remains any clfr rule in the previous service flow, it must be the deleted one.
+	 */
+	clfr_old = NULL;
+	while ((clfr_old = next_classification_rule(old, clfr_old))) {
+		event->sf.clfr_action = DSC_DELETE_CLASSIFIER;
+		event->sf.PacketClassificationRuleIndex = clfr_old->PacketClassifierRuleIndex;
+		dev_notify_event(dev_idx, event);
+	}
+	
+	event->sf.clfr_action = DSC_NOP_CLASSIFIER;
+	event->sf.PacketClassificationRuleIndex = 0;
+
+	/* phs rule */
+	found = 0;
+	while ((phs = next_phs_rule(sf, phs))) {
+		while ((phs_old = next_phs_rule(old, phs_old))) {
+			if (phs->PHSI == phs_old->PHSI) {
+				found = 1;
+				break;
+			}
+		}
+		if (!found) {
+			event->sf.phs_action = DSC_ADD_PHS;
+			event->sf.PHSI = phs->PHSI;
+			dev_notify_event(dev_idx, event);
+		} else
+			remove_phs_rule(old, phs_old);	/* remove the found phs rule */
+		
+		found = 0;
+	}
+	
+	/* find the removed phs rule */
+	phs_old = NULL;
+	while ((phs_old = next_phs_rule(old, phs_old))) {
+		event->sf.phs_action = DSC_DELETE_PHS;
+		event->sf.PHSI = phs_old->PHSI;
+		dev_notify_event(dev_idx, event);
+	}
+
+	return 0;
+}
+
+/*
+ * dev_update_service_flow() - Handles DSx_Complete HCI message.
+ * 
+ * Event generated:
+ *   - SF added (result, sfid)
+ *   - SF changed (result, sfid, classification/phs rule added/removed/changed)
+ *   - SF deleted (result, sfid)
+ */
+void dev_update_service_flow(int dev_idx, struct hci *pkt)
+{
+	device_t *dev;
+	struct wimax_service_flow *sf, sf_old;
+	uint8_t T, *V,  action = pkt->data[0];
+	uint8_t status = pkt->data[1], direction;
+	uint32_t sfid;
+	uint32_t L, start, end, oft = 2;
+	WIMAX_SF_EVENT levent, *event;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return;
+	
+	if ((action & 0x80) == 0x80) 
+		event = &dev->wimax->dev_info.service_flow.last_sf_event;
+	else
+		event = &levent;
+
+	xprintf(SDK_DBG, "DSX(len=%d)\n", pkt->length);
+	xprintf_hex(SDK_DBG, SDK_LOG_TITLE, pkt->data, pkt->length);
+	
+	/* DSX related event is generated only by server. */
+	memset(event, 0, sizeof(*event));
+	
+	/* initialize clfr and phs */
+	event->sf.clfr_action = DSC_NOP_CLASSIFIER;
+	event->sf.phs_action = DSC_NOP_PHS;
+	event->sf.PacketClassificationRuleIndex = 0;
+	event->sf.PHSI = 0;
+
+	/* filling event */
+	event->sf.cc = status;
+	event->sf.ms_initiated = ((action & 0x80) == 0x80);	
+	event->code = WIMAX_EVT_SERVICE_FLOW_ADDED + (action & 0x7f);
+	
+	if (status)
+		goto out;
+	
+	/* If action&0x7f is 7, it is only two-byte packet. */
+	if (pkt->length > 2) {
+		sf_hci_get_tlv(pkt, &T, &L, &V, oft);
+		if (T != 145 && T != 146)
+			T = 145; /* Workaround */
+		
+		direction = T - 145;
+		start = V - pkt->data;
+		end = start + L;
+		
+		/* Find SFID TLV */
+		if (!sf_hci_find_tlv_range(pkt, 1, &L, &V, start, end)) {
+			xprintf(SDK_ERR, "Warning: SFID missing\n");
+			goto out;
+		}
+		memcpy(&sfid, V, L);
+		event->sf.sfid = sfid;
+	}
+
+	pthread_mutex_lock(&dev->wimax->dev_info.service_flow.sfwritelock);
+	switch (action & 0x7f) {
+	case 0: /* DSA */
+		sf = find_service_flow(dev_idx, sfid);
+		if (sf == NULL) {
+			sf = create_service_flow(dev_idx, sfid, direction);
+			if (sf == NULL) {
+				xprintf(SDK_ERR, "DSA : cannot create service flow %d\n", sfid);
+				goto out2;
+			}
+		}
+		remove_all_classification_rule(sf);
+		remove_all_phs_rule(sf);
+		update_service_flow(sf, pkt, start, end, 0, event);
+		break;
+	case 1: /* DSC */
+		sf = find_service_flow(dev_idx, sfid);
+		if (sf == NULL) {
+			xprintf(SDK_ERR, "DSC : cannot find service flow %d\n", sfid);
+			goto out2;
+		}
+		/* Check if this DSC is for CID update */
+		if (pkt->data[3] == 0xa) {
+			if (!sf_hci_find_tlv_range(pkt, 2, &L, &V, start, end)) 
+				xprintf(SDK_ERR, "Warning: CID missing\n");
+			else {
+				memcpy(&sf->param.CID, V, L);
+				event->code = WIMAX_EVT_CID_UPDATE;
+				dev_notify_event(dev_idx, event);
+			}
+			pthread_mutex_unlock(&dev->wimax->dev_info.service_flow.sfwritelock);
+			goto out2;
+		}
+
+		memcpy(&sf_old, sf, sizeof(struct wimax_service_flow));
+		remove_all_classification_rule(sf);
+		remove_all_phs_rule(sf);
+		update_service_flow(sf, pkt, start, end, 0, event);
+		compare_service_flow(sf, &sf_old, dev_idx, event);
+		break;
+	case 2: /* DSD */
+		sf = find_service_flow(dev_idx, sfid);
+		if (sf)
+			remove_service_flow(dev_idx, sf);
+		else
+			xprintf(SDK_NOTICE, "DSD for non-existing SFID (%08x)\n", sfid);
+		break;
+	case 7: /* Delete all service flows */
+		remove_all_service_flow(dev_idx);
+		pthread_mutex_unlock(&dev->wimax->dev_info.service_flow.sfwritelock);
+		xprintf(SDK_DBG, "DSX : Remove all service flow\n");
+		goto out2;
+	default:
+		xprintf(SDK_NOTICE, "Unknown DSx_Complete mode %d\n", action);
+		pthread_mutex_unlock(&dev->wimax->dev_info.service_flow.sfwritelock);
+		goto out2;
+	}
+	pthread_mutex_unlock(&dev->wimax->dev_info.service_flow.sfwritelock);
+	
+out:	
+	if (event->sf.ms_initiated) {
+	    pthread_cond_signal(&dev->wimax->dev_info.service_flow.dsx_cond);
+	}
+	
+	if ((action & 0x7f) != 1) 
+		dev_notify_event(dev_idx, event);
+
+out2:
+	
+	dm_put_dev(dev_idx);
+	xfunc_out();
+	return;
+}
+
+struct dl_sf_stat {
+	uint32_t	sfid;
+	uint16_t	cid;
+	uint16_t	feature;
+
+	uint32_t	sdu_packets;
+	uint32_t	sdu_packets_dropped;
+	uint32_t	sdu_bytes;
+	uint32_t	sdu_bytes_dropped;
+	uint32_t	pdu_packets;
+	uint32_t	pdu_bytes;
+
+	uint32_t	arq_blocks;
+	uint32_t	arq_blocks_retry;
+	uint16_t	arq_discard;
+	uint16_t	arq_reset;
+	uint16_t	arq_sync_loss;
+} __attribute__((packed));
+
+struct ul_sf_stat {
+	uint32_t	sfid;
+	uint16_t	cid;
+	uint16_t	feature;
+
+	uint32_t	sdu_packets;
+	uint32_t	sdu_packets_dropped;
+	uint32_t	sdu_bytes;
+	uint32_t	sdu_bytes_dropped;	
+	uint32_t	pdu_packets;
+	uint32_t	pdu_bytes;
+	
+	uint32_t	bwreq;
+	uint32_t	gmsh;
+
+	uint32_t	arq_blocks;
+	uint32_t	arq_blocks_retry;
+	uint16_t	arq_discard;
+	uint16_t	arq_reset;
+	uint16_t	arq_sync_loss;	
+} __attribute__((packed)) ;
+
+/*----------------------------------------------------------------------
+ *
+ * Client API for SF information retrieval
+ *
+ *----------------------------------------------------------------------*/
+
+void BeginSFRead(int dev_idx)
+{
+	device_t *dev;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return;
+
+	pthread_mutex_lock(&dev->wimax->dev_info.service_flow.sfreadlock);
+
+	dm_put_dev(dev_idx);
+	xfunc_out();
+}
+
+
+void EndSFRead(int dev_idx)
+{
+	device_t *dev;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return;
+
+	pthread_mutex_unlock(&dev->wimax->dev_info.service_flow.sfreadlock);
+
+	dm_put_dev(dev_idx);
+	xfunc_out();
+}
+
+/*
+ * GetNextSF() - returns a pointer to the vailable service flow
+ * in the device that apears right after pSFParam.
+ *
+ * Direction: 0 (UL), 1 (DL), 2 (DL + UL)
+ *
+ * To get the first service flow, set pSFParam to NULL.
+ * If the function returns NULL, we are done.
+ *
+ * SYNOPSIS:
+ *
+ * WIMAX_SERVICE_FLOW_P sf;
+ *
+ * sf = BeginSF(pDeviceID, direction);
+ * while (sf) {
+ *	DO ACTION on sf
+ *  	sf = GetNextSF(pDeviceID, sf, direction)));
+ * }
+ * EndSF(pDeviceID);
+ * 
+ *
+ * NOTE:
+ * The object referenced by the return value of GetNextSF is
+ * read-only. Do not modify its content.
+ *
+ * Limitation:
+ * It is not allowed to break inside the above while loop.
+ * 
+ */
+WIMAX_SERVICE_FLOW *GetNextSF(int dev_idx,
+			      WIMAX_SERVICE_FLOW *pSF,
+			      UINT8 Direction)
+{
+	device_t *dev;
+	WIMAX_SERVICE_FLOW *sf;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return NULL;
+
+	if (pSF == NULL)
+		sf = dev->wimax->dev_info.service_flow.sf;
+	else
+		sf = pSF + 1;
+
+	for (; sf - dev->wimax->dev_info.service_flow.sf < WIMAX_MAX_SERVICE_FLOW; sf++)
+		if (sf->valid) {
+			if (Direction == 2)
+				goto out;
+			else if (Direction == sf->param.DL)
+				goto out;
+			continue;
+		}
+	sf = NULL;
+
+out:
+	dm_put_dev(dev_idx);
+	xfunc_out();
+	return sf;
+}
+
+
+/*
+ * GetServiceFlow() returns a pointer to WIMAX_SERVICE_FLOW that
+ * matches the given SFID.
+ *
+ * The object referenced by the returned pointer is read-only.
+ */
+WIMAX_SERVICE_FLOW *GetServiceFlow(int dev_idx,
+				   UINT32 SFID)
+
+{
+	device_t *dev;
+	WIMAX_SERVICE_FLOW *sf;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return NULL;
+
+	sf = find_service_flow(dev_idx, SFID);
+
+	dm_put_dev(dev_idx);
+	xfunc_out();
+	return sf;
+}
+
+
+/*
+ * GetCalssificationRule() - Get a single classification rule.
+ *
+ * pSFParam->SFID, pCLFRRule->ClassficationRuleIndex should be
+ * set by caller.
+ *  
+ */
+WIMAX_CLFR_RULE *GetNextClfrRule(WIMAX_SERVICE_FLOW *pSF,
+				 WIMAX_CLFR_RULE *pCLFRRule)
+{
+	return next_classification_rule(pSF, pCLFRRule);
+}
+
+
+WIMAX_CLFR_RULE *GetClfrRule(WIMAX_SERVICE_FLOW *pSF,
+			     UINT16 PacketClassfierRuleIndex)
+{
+	return find_classification_rule(pSF, PacketClassfierRuleIndex);
+}
+
+
+WIMAX_PHS_RULE *GetNextPHSRule(WIMAX_SERVICE_FLOW *pSF,
+			       WIMAX_PHS_RULE *pPHSRule)
+{
+
+	return next_phs_rule(pSF, pPHSRule);
+}
+
+WIMAX_PHS_RULE *GetPHSRule(WIMAX_SERVICE_FLOW *pSF,
+			   UINT8 PHSI)
+{
+	return find_phs_rule(pSF, PHSI);
+}
+
+/*----------------------------------------------------------------------
+ *
+ * SDK Client API for dynamic service flow management
+ *
+ *----------------------------------------------------------------------*/
+
+const WIMAX_SF_PARAM sf_param_init = {
+	.QosParamSetType 		= 0x7, 	/* admitted, active, and provisioned */
+	.TrafficPriority		= 0, 	/* lowest priority - default */
+	.ULGrantSchedulingType		= UL_SCHED_TYPE_BE,
+	.RequestTransmissionPolicy	= 0x10,	/* No PHS */
+	.TargetSAID			= 0xffff,
+	.ARQEnable			= 0,
+	.ARQWindowSize			= 1024,
+	.ARQTransmitterDelay		= 750,	/* 750usec */
+	.ARQReceiverDelay		= 750,	/* 750usec */
+	.ARQBlockLifeTime		= 0,	/* ? */
+	.ARQSyncLossTimeout		= 0,	/* ? */
+	.ARQDeliverInOrder		= 1,	
+	.ARQRxPurgeTimeout		= 0,	/* ? */
+	.ARQBlockSize			= 0x60, /* ? */
+	.ReceiverARQAckProcessingTime	= 2, 	/* ? */
+	.CSSpecification		= 1,	/* ? */
+	.TypeOfDataDeliveryServices	= DATA_SERVICE_BE,
+	.PagingPreference		= 0, 	/* ? */
+	.TrafficPreferenceIndication	= 0, 	/* ? */
+	.SNFeedbackEnabled		= 0, 	/* ? */
+	.FSNSize			= 1, 	/* default */
+	.HARQServiceFlows		= 0, 	/* default */	
+	.PDUSNExtendedSubheaderForHARQReordering = 2, /* default is 0, our default is 2 */
+};
+
+void InitClassificationRule(uint32_t sfid, WIMAX_CLFR_RULE_P pClfrRule)
+{
+	memset(pClfrRule, 0, sizeof(WIMAX_CLFR_RULE));
+
+	pClfrRule->IPTypeOfService.low = 1; /* invalid: low > high */
+	pClfrRule->Protocol = 255; 	/* invalid: which is reserved */
+
+	/* The trick here is we set address mask to 0x0 and address to a non-zero value, so that
+	 * ANDing address and mask always produces zero address, making the test always fails.
+	 * The routines that adds TLV to DSx_Request uses the same criterion to check whether
+	 * these masked source/destination address is actually set.
+	 */
+	pClfrRule->IPv4MaskedSourceAddress.address.s_addr = htonl(INADDR_NONE); /* ip-src & mask != INADDR_NONE */
+	pClfrRule->IPv4MaskedDestAddress.address.s_addr = htonl(INADDR_NONE);   /* ip-dst & mask != INADDR_NONE */
+	
+	pClfrRule->IPv6MaskedSourceAddress.address = in6addr_loopback;
+	pClfrRule->IPv6MaskedDestAddress.address = in6addr_loopback;
+
+	/* The trick here is to make the port range [low, high] illegal by setting low=1 and high=0 */
+
+	pClfrRule->ProtocolSourcePort.low = 1;  /* low > high */
+	pClfrRule->ProtocolDestPort.low = 1;	/* low > high */
+
+	memset(pClfrRule->EthernetDestMACAddress.addr, 0xff, 6);
+	memset(pClfrRule->EthernetSourceMACAddress.addr, 0xff, 6);
+
+	pClfrRule->EtherType.type = 4; /* which is invalid */
+	pClfrRule->IEEE802_1D_UserPriority.low = 8; /* which is out of range */
+
+	pClfrRule->IEEE802_1Q_VLANID = 0xfff; /* which is reserved */
+	pClfrRule->AssociatedPHSI = 0; /* not used - we support less than 255 PHSI */
+	pClfrRule->PacketClassifierRuleIndex = 0;
+}
+
+
+#define append_non_zero_tlv(h, t, l, v) \
+	if ((v)) sf_hci_append_tlv((h), (t), (l), &(v))
+
+#define append_tlv(h, t, l, v)	sf_hci_append_tlv((h), (t), (l), &(v))
+
+
+static uint32_t add_one_classification_rule(struct hci *hci,
+					    WIMAX_SF_PARAM_P pSFParam,
+					    WIMAX_CLFR_RULE_P pClfrRule)
+{
+	uint8_t cs = pSFParam->CSSpecification;
+	uint32_t offset;
+
+	hci->data[hci->length++] = 3; /* Packet classification rules */
+	offset = hci->length; /* at most 127 byte long, hopefully */
+	hci->length++;
+
+	append_tlv(hci, 1, 1, pClfrRule->ClassifierRulePriority);
+
+	if (pClfrRule->IPTypeOfService.low <= pClfrRule->IPTypeOfService.high)
+		append_tlv(hci, 2, 3, pClfrRule->IPTypeOfService);
+	
+	append_tlv(hci, 14, 2, pClfrRule->PacketClassifierRuleIndex);
+
+	if (pClfrRule->Protocol != 255)
+		append_tlv(hci, 3, 1, pClfrRule->Protocol);
+
+	/* IP */
+	if (cs !=2 && cs != 6 && cs != 8) {
+		/* IPv4 */
+		if (memcmp(&pClfrRule->IPv4MaskedSourceAddress,
+			   &classifier_rule_init.IPv4MaskedSourceAddress, 8))
+			append_tlv(hci, 4, 8, pClfrRule->IPv4MaskedSourceAddress);
+
+		if (memcmp(&pClfrRule->IPv4MaskedDestAddress,
+			   &classifier_rule_init.IPv4MaskedDestAddress, 8))
+			append_tlv(hci, 5, 8, pClfrRule->IPv4MaskedDestAddress);
+		    
+	} else if (cs != 1 && cs != 5 && cs != 7) {
+		/* IPv6 */
+		if (memcmp(&pClfrRule->IPv6MaskedSourceAddress,
+			    &classifier_rule_init.IPv6MaskedSourceAddress, 32))
+			append_tlv(hci, 4, 32, pClfrRule->IPv6MaskedSourceAddress);
+
+		if (memcmp(&pClfrRule->IPv6MaskedDestAddress,
+			    &classifier_rule_init.IPv6MaskedDestAddress, 32))
+			append_tlv(hci, 5, 32, pClfrRule->IPv6MaskedDestAddress);
+	}
+
+	if (pClfrRule->Protocol != 255) {
+		if (pClfrRule->ProtocolSourcePort.low <= pClfrRule->ProtocolSourcePort.high)
+			append_tlv(hci, 6, 4, pClfrRule->ProtocolSourcePort);
+	
+		if (pClfrRule->ProtocolDestPort.low <= pClfrRule->ProtocolDestPort.high)
+			append_tlv(hci, 7, 4, pClfrRule->ProtocolDestPort);
+	}
+	
+	/* Ether */
+	if (cs >= 3 && cs <= 8) {
+
+		if (memcmp(&pClfrRule->EthernetDestMACAddress,
+			   &classifier_rule_init.EthernetDestMACAddress, 12))
+			append_tlv(hci, 8, 12, pClfrRule->EthernetDestMACAddress);
+
+		if (memcmp(&pClfrRule->EthernetSourceMACAddress,
+			   &classifier_rule_init.EthernetSourceMACAddress, 12))
+			append_tlv(hci, 9, 12, pClfrRule->EthernetSourceMACAddress);
+
+		if (pClfrRule->EtherType.type != 4)
+			append_tlv(hci, 10, 3, pClfrRule->EtherType);
+		
+		if (pClfrRule->IEEE802_1D_UserPriority.low < 8)
+			append_tlv(hci, 11, 2, pClfrRule->IEEE802_1D_UserPriority); 
+
+		if (cs == 4 || cs == 7 || cs == 8)
+			if (pClfrRule->IEEE802_1Q_VLANID != 0xfff)
+				append_tlv(hci, 12, 2, pClfrRule->IEEE802_1Q_VLANID);
+	}
+	
+	if (pClfrRule->AssociatedPHSI != 0)
+		append_tlv(hci, 13, 1, pClfrRule->AssociatedPHSI);
+
+	hci->data[offset] = hci->length - offset - 1;
+	return 2 + hci->data[offset];
+}
+
+#define ceiling(x, y)	(((x) + (y)-1)/(y))
+
+static uint32_t add_one_phs_rule(struct hci *hci,
+				 WIMAX_SF_PARAM_P pSFParam,
+				 WIMAX_PHS_RULE_P pPHSRule)
+{
+	uint32_t oft, L;
+	
+	if ( (pPHSRule == NULL) || !pPHSRule->PHSS)
+		return 0;
+
+	hci->data[hci->length++] = 6;
+	oft = hci->length;
+	hci->length += 3;
+	
+	/* Do not append PHSI here as PHS rule does not support replace */
+	append_tlv(hci, 2, pPHSRule->PHSS, pPHSRule->PHSF);
+	append_tlv(hci, 3, ceiling(pPHSRule->PHSS, 8), pPHSRule->PHSM);
+	append_tlv(hci, 4, 1, pPHSRule->PHSS);
+	append_tlv(hci, 5, 1, pPHSRule->PHSV);
+
+	L = hci->length - oft - 3;
+	hci->data[oft] = 0x82;
+	hci->data[oft+1] = (L >> 8) & 0xff;
+	hci->data[oft+2] = L & 0xff;
+
+	return L;
+}
+
+static void add_sf_param(struct hci *hci,
+			 WIMAX_SF_PARAM_P sfp)
+{
+	if (!hci->data[0])
+		sfp->SFID = 0;
+	append_tlv(hci, 1, 4, sfp->SFID);
+
+	if (sfp->ServiceClassName[0])
+		sf_hci_append_tlv(hci, 3, strlen((const char*)sfp->ServiceClassName)+1,
+			       sfp->ServiceClassName);
+
+	append_tlv(hci, 4, 1, sfp->MBSService);
+
+	/* QoS */
+	append_tlv(hci, 5, 1, sfp->QosParamSetType);
+	append_tlv(hci, 6, 1, sfp->TrafficPriority);
+	append_tlv(hci, 7, 4, sfp->MaxSustainedTrafficRate);
+	append_non_zero_tlv(hci, 8, 4, sfp->MaxTrafficBurst);
+	append_tlv(hci, 9, 4, sfp->MinReservedTrafficRate);
+	append_non_zero_tlv(hci, 10, 4, sfp->MinTolerableRate);
+	/* This one is needed for DL as well */
+	append_tlv(hci, 11, 1, sfp->ULGrantSchedulingType);
+	append_tlv(hci, 12, 1, sfp->RequestTransmissionPolicy);
+	append_tlv(hci, 13, 4, sfp->ToleratedJitter);
+	append_tlv(hci, 14, 4, sfp->MaxLatency);
+	append_tlv(hci, 15, 1, sfp->FixedLengthSDUIndicator);
+	if (sfp->FixedLengthSDUIndicator)
+		append_tlv(hci, 16, 1, sfp->SDUSize);
+
+	if (sfp->TargetSAID != 0xffff)
+		append_tlv(hci, 17, 2, sfp->TargetSAID);
+	
+	append_tlv(hci, 18, 1, sfp->ARQEnable);
+	if (sfp->ARQEnable) {
+		append_tlv(hci, 19, 2, sfp->ARQWindowSize);
+		append_tlv(hci, 20, 2, sfp->ARQTransmitterDelay);
+		append_tlv(hci, 21, 2, sfp->ARQReceiverDelay);
+		append_tlv(hci, 22, 2, sfp->ARQBlockLifeTime);
+		append_tlv(hci, 23, 2, sfp->ARQSyncLossTimeout);
+		append_tlv(hci, 24, 1, sfp->ARQDeliverInOrder);
+		append_tlv(hci, 25, 2, sfp->ARQRxPurgeTimeout);
+		append_tlv(hci, 26, 2, sfp->ARQBlockSize);
+		append_tlv(hci, 27, 1, sfp->ReceiverARQAckProcessingTime);
+	}
+	append_tlv(hci, 28, 1, sfp->CSSpecification);
+
+	if (sfp->DL)
+		append_tlv(hci, 29, 1, sfp->TypeOfDataDeliveryServices);
+
+	append_non_zero_tlv(hci, 30, 2, sfp->SDUInterArrivalInterval);
+	append_non_zero_tlv(hci, 31, 2, sfp->TimeBase);
+	append_tlv(hci, 32, 1, sfp->PagingPreference);
+	if (sfp->MBSService)
+		append_tlv(hci, 33, 8, sfp->MBSZoneID);
+	append_tlv(hci, 34, 1, sfp->TrafficPreferenceIndication);
+	append_tlv(hci, 35, strlen((const char*)sfp->ServiceClassName)+1,
+			       sfp->ServiceClassName);
+	append_tlv(hci, 37, 1, sfp->SNFeedbackEnabled);
+	append_tlv(hci, 38, 1, sfp->FSNSize);
+
+	switch (sfp->ULGrantSchedulingType) {
+		case UL_SCHED_TYPE_UGS:
+		case UL_SCHED_TYPE_ertPS:
+			append_tlv(hci, 40, 2, sfp->UnsolicitedGrantInterval);
+			break;
+		case UL_SCHED_TYPE_rtPS:
+		case UL_SCHED_TYPE_nrtPS:
+			append_tlv(hci, 41, 2, sfp->UnsolicitedPollingInterval);
+			break;
+		default:
+			break;
+	}
+	
+	if (sfp->HARQServiceFlows)
+		append_tlv(hci, 42, 1, sfp->PDUSNExtendedSubheaderForHARQReordering);
+
+	append_tlv(hci, 44, 1, sfp->HARQServiceFlows);
+}
+
+
+/*
+ * CmdAddSF() - Add a new service flow
+ *
+ * Limitation:
+ * 1. Currently, only one classification rule and phs rule can
+ *    be specified in CmdAddSF().
+ *
+ */ 
+
+WIMAX_SF_CC CmdAddSF(int dev_idx,
+		     WIMAX_SF_PARAM_P pSFParam,
+		     WIMAX_CLFR_RULE_P pClfrRule,
+		     WIMAX_PHS_RULE_P pPHSRule)
+{
+#define timeval2timespec(tv,ts) \
+		((ts)->tv_sec = (tv)->tv_sec, (ts)->tv_nsec = (tv)->tv_usec * 1000)
+
+	device_t *dev;
+	struct timeval tv;
+	struct timespec ts;
+	int ret = 0;
+
+	struct hci *hci;
+	uint16_t cst_len = 0;
+	uint16_t cst_oft, dsx_oft;
+	WIMAX_SF_CC cc;
+	char buf[2048], *ptr = buf;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	if (dev->fsm.m_status != M_CONNECTED) {
+		cc = WIMAX_SF_OTHER;
+		goto out;
+	}
+
+	hci = malloc(sizeof(struct hci) + 1024); /* large enough? */
+	if (!hci) {
+		cc = -1; //WIMAX_API_RET_FAILED;
+		goto out;
+	}
+
+	xprintf(SDK_INFO, "CmdAddSF:");
+	ptr += snprintf(ptr, buf + sizeof(buf)-ptr, "SF={\n");
+	ptr += sprintf_sf_param(ptr, sizeof(buf), pSFParam);
+	if (pClfrRule) {
+		ptr += snprintf(ptr, buf + sizeof(buf)-ptr, "\tClassifierRule={\n");
+		ptr += sprintf_classifier_rule(ptr, buf + sizeof(buf) - ptr, pClfrRule);	
+	}
+	if (pPHSRule) {
+		ptr += snprintf(ptr, buf + sizeof(buf)-ptr, "\tPHSRule={\n");
+		ptr += sprintf_phs_rule(ptr, buf + sizeof(buf) - ptr, pPHSRule);	
+	}
+	xprintf(SDK_INFO, "%s\t}\n}", buf);
+	
+	hci->cmd_evt = htons(WIMAX_DSX_REQUEST);
+	hci->length = 0;
+	hci->data[hci->length++] = 0; /* DSA-REQ */
+	hci->data[hci->length++] = 1; /* Use parameter in this hci */
+	
+	hci->data[hci->length++] = 145 + pSFParam->DL;
+	dsx_oft = hci->length;
+	hci->length += 3;
+
+	add_sf_param(hci, pSFParam);
+	
+	if (pClfrRule || pPHSRule) {
+		hci->data[hci->length++] = pSFParam->CSSpecification + 99; /* cst */
+		cst_oft = hci->length;
+		hci->length += 3;
+		
+		if (pClfrRule)
+			cst_len = add_one_classification_rule(hci, pSFParam, pClfrRule);
+		
+		if (pPHSRule)
+			cst_len += add_one_phs_rule(hci, pSFParam, pPHSRule);
+
+		hci->data[cst_oft] = 0x82;
+		hci->data[cst_oft+1] = (cst_len >> 8) & 0xff;
+		hci->data[cst_oft+2] = cst_len & 0xff;
+		/*sf_hci_put_length(hci->data + cst_oft, cst_len);*/
+	}
+
+	hci->data[dsx_oft] = 0x82;
+	hci->data[dsx_oft+1] = ((hci->length - dsx_oft - 3) >> 8) & 0xff;
+	hci->data[dsx_oft+2] = (hci->length - dsx_oft - 3) & 0xff;
+	/*sf_hci_put_length(hci->data + dsx_oft, hci->length - dsx_oft - 1);*/
+
+	/* Prevent other clients from sending a DSx request */
+	pthread_mutex_lock(&dev->wimax->dev_info.service_flow.dsxlock);
+
+	xprintf(SDK_DBG, "DSA-REQ(len=%d)\n", hci->length);
+	xprintf_hex(SDK_DBG, SDK_LOG_TITLE, hci->data, hci->length);
+
+	sf_send_hci(dev_idx, hci);
+	free(hci);
+
+	gettimeofday(&tv, NULL);
+	timeval2timespec(&tv, &ts);
+	ts.tv_sec += DSX_REQUEST_TIMEOUT;
+	ret = pthread_cond_timedwait(&dev->wimax->dev_info.service_flow.dsx_cond, &dev->wimax->dev_info.service_flow.dsxlock, &ts);
+	if (ret) {
+		xprintf(SDK_ERR, "CmdAddSF Error (pthread_cond_timedwait=%d)\n", ret);
+		pthread_mutex_unlock(&dev->wimax->dev_info.service_flow.dsxlock);
+		cc = -1; //WIMAX_API_RET_FAILED;
+		goto out;
+	}
+	//pthread_cond_wait(&dev->wimax->dev_info.service_flow.dsx_cond, &dev->wimax->dev_info.service_flow.dsxlock);
+
+	/* Figure out the SFID of the newly created one */
+	/* We need another bookkeeping information */
+	if (dev->wimax->dev_info.service_flow.last_sf_event.code != WIMAX_EVT_SERVICE_FLOW_ADDED) 
+		assert(dev->wimax->dev_info.service_flow.last_sf_event.code == WIMAX_EVT_SERVICE_FLOW_ADDED);
+	
+	pSFParam->SFID = dev->wimax->dev_info.service_flow.last_sf_event.sf.sfid;
+	cc = dev->wimax->dev_info.service_flow.last_sf_event.sf.cc;
+	
+	pthread_mutex_unlock(&dev->wimax->dev_info.service_flow.dsxlock);
+
+	xprintf(SDK_INFO, "DSA-REQ: %s\n", wimax_stringify_dsx_cc(cc));
+
+out:
+
+	dm_put_dev(dev_idx);
+	xfunc_out("ret=%d", cc);
+	return cc;
+}
+
+/* Change a service flow */
+
+WIMAX_SF_CC CmdChangeSF(int dev_idx,
+			WIMAX_SF_PARAM_P pSFParam,
+			WIMAX_CLFR_DSC_ACTION CLFRDSCAction,
+			WIMAX_CLFR_RULE_P pClfrRule,
+			WIMAX_PHS_DSC_ACTION PHSDSCAction,
+			WIMAX_PHS_RULE_P pPHSRule)
+{
+#define timeval2timespec(tv,ts) \
+		((ts)->tv_sec = (tv)->tv_sec, (ts)->tv_nsec = (tv)->tv_usec * 1000)
+	
+	device_t *dev;
+	struct timeval tv;
+	struct timespec ts;
+	int ret = 0;
+
+	struct hci *hci;
+	uint16_t cst_len = 0;
+	uint16_t cst_oft, dsx_oft, tmp_oft;
+	WIMAX_SF_CC cc;
+	char buf[2048], *ptr = buf;	
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	if (dev->fsm.m_status != M_CONNECTED) {
+		cc = WIMAX_SF_OTHER;
+		goto out;
+	}
+
+	if (!pSFParam || !find_service_flow(dev_idx, pSFParam->SFID)) {
+		cc = WIMAX_SF_NOT_FOUND;
+		goto out;
+	}
+	
+	hci = (struct hci *)malloc(sizeof(struct hci) + 1024); /* large enough? */
+	if (!hci) {
+		cc = -1; //WIMAX_API_RET_FAILED;
+		goto out;
+	}
+
+	xprintf(SDK_INFO, "CmdChangeSF:");
+	ptr += snprintf(ptr, buf + sizeof(buf)-ptr, "SF={\n");
+	ptr += sprintf_sf_param(ptr, sizeof(buf), pSFParam);
+	if (pClfrRule) {
+		ptr += snprintf(ptr, buf + sizeof(buf)-ptr, "\tClassifierRule={\n");
+		ptr += sprintf_classifier_rule(ptr, buf + sizeof(buf) - ptr, pClfrRule);	
+	}
+	if (pPHSRule) {
+		ptr += snprintf(ptr, buf + sizeof(buf)-ptr, "\tPHSRule={\n");
+		ptr += sprintf_phs_rule(ptr, buf + sizeof(buf) - ptr, pPHSRule);
+	}
+	xprintf(SDK_INFO, "%s\t}\n}", buf);	
+
+	hci->cmd_evt = htons(WIMAX_DSX_REQUEST);
+	hci->length = 0;
+	hci->data[hci->length++] = 1; /* DSC-REQ */
+	hci->data[hci->length++] = 1; /* Use parameter in this hci */
+	
+	hci->data[hci->length++] = 145 + pSFParam->DL;
+	dsx_oft = hci->length;
+	hci->length += 3;
+
+	add_sf_param(hci, pSFParam);
+	
+//	if (pClfrRule || pPHSRule) {
+	if (CLFRDSCAction != DSC_NOP_CLASSIFIER || PHSDSCAction != DSC_NOP_PHS) {
+		hci->data[hci->length++] = pSFParam->CSSpecification + 99; /* cst */
+		cst_oft = hci->length;
+		hci->length += 3;
+		
+		if (pClfrRule) {
+			hci->data[hci->length++] = 1;
+			hci->data[hci->length++] = 1;
+			hci->data[hci->length++] = CLFRDSCAction;
+			cst_len += 3;
+			if (CLFRDSCAction == DSC_DELETE_CLASSIFIER) {
+				hci->data[hci->length++] = 3;
+				tmp_oft = hci->length;
+				hci->length++;
+				append_tlv(hci, 14, 2, pClfrRule->PacketClassifierRuleIndex);
+				hci->data[tmp_oft] = hci->length - tmp_oft -1;
+				cst_len += (2 + hci->data[tmp_oft]);
+			} else 
+				cst_len += add_one_classification_rule(hci, pSFParam, pClfrRule);
+		}
+		/* PHS Rule DSC */
+		// in case of phs_deleteall, pPHSRule may not need.
+		if (PHSDSCAction == DSC_DELETE_ALL_PHS) {
+			hci->data[hci->length++] = 4;
+			hci->data[hci->length++] = 1;
+			hci->data[hci->length++] = PHSDSCAction;
+			cst_len += 3 ;
+			goto phs_done;
+		} 
+		if (pPHSRule) {
+			hci->data[hci->length++] = 4;
+			hci->data[hci->length++] = 1;
+			hci->data[hci->length++] = PHSDSCAction;
+			cst_len += 3;
+			if (PHSDSCAction == DSC_DELETE_PHS) {
+				hci->data[hci->length++] = 6;	// PHS rule filed
+				tmp_oft = hci->length;
+				hci->length++;
+				append_tlv(hci, 1, 1, pPHSRule->PHSI);
+				hci->data[tmp_oft] = hci->length - tmp_oft -1;
+				cst_len += (2 + hci->data[tmp_oft]);
+			} else 
+				cst_len += add_one_phs_rule(hci, pSFParam, pPHSRule);
+		}
+phs_done:
+		hci->data[cst_oft] = 0x82;
+		hci->data[cst_oft+1] = (cst_len >> 8) & 0xff;
+		hci->data[cst_oft+2] = cst_len & 0xff;
+		/* sf_hci_put_length(hci->data + cst_oft, cst_len); */
+	} 
+	
+	hci->data[dsx_oft] = 0x82;
+	hci->data[dsx_oft+1] = ((hci->length - dsx_oft - 3) >> 8) & 0xff;
+	hci->data[dsx_oft+2] = (hci->length - dsx_oft - 3) & 0xff;
+	/* sf_hci_put_length(hci->data + dsx_oft, hci->length - dsx_oft - 1); */
+
+	/* Prevent other clients from sending a DSx request */
+	pthread_mutex_lock(&dev->wimax->dev_info.service_flow.dsxlock);
+
+	xprintf(SDK_DBG, "DSC-REQ(len=%d)\n", hci->length);
+	xprintf_hex(SDK_DBG, SDK_LOG_TITLE, hci->data, hci->length);
+	
+	sf_send_hci(dev_idx, hci);
+	free(hci);
+
+	gettimeofday(&tv, NULL);
+	timeval2timespec(&tv, &ts);
+	ts.tv_sec += DSX_REQUEST_TIMEOUT;
+	ret = pthread_cond_timedwait(&dev->wimax->dev_info.service_flow.dsx_cond, &dev->wimax->dev_info.service_flow.dsxlock, &ts);
+	if (ret) {
+		xprintf(SDK_ERR, "CmdChangeSF Error (pthread_cond_timedwait=%d)\n", ret);
+		pthread_mutex_unlock(&dev->wimax->dev_info.service_flow.dsxlock);
+		cc = -1; //WIMAX_API_RET_FAILED;
+		goto out;
+	}
+	//pthread_cond_wait(&dev->wimax->dev_info.service_flow.dsx_cond, &dev->wimax->dev_info.service_flow.dsxlock);
+	
+	cc = dev->wimax->dev_info.service_flow.last_sf_event.sf.cc;
+	pthread_mutex_unlock(&dev->wimax->dev_info.service_flow.dsxlock);
+
+	xprintf(SDK_INFO, "DSC-REQ: %s\n", wimax_stringify_dsx_cc(cc));
+
+out:
+	dm_put_dev(dev_idx);
+	xfunc_out("ret=%d", cc);
+ 	return cc;
+}
+
+
+/* Delete a service flow */
+
+WIMAX_SF_CC CmdDeleteSF(int dev_idx,
+			WIMAX_SF_PARAM_P pSFParam)
+{
+#define timeval2timespec(tv,ts) \
+		((ts)->tv_sec = (tv)->tv_sec, (ts)->tv_nsec = (tv)->tv_usec * 1000)
+	
+	device_t *dev;
+	struct timeval tv;
+	struct timespec ts;
+	int ret = 0;
+
+	struct hci *hci;
+	WIMAX_SF_CC cc;	
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	if (dev->fsm.m_status != M_CONNECTED) {
+		cc = WIMAX_SF_OTHER;
+		goto out;
+	}
+
+	if (!pSFParam || !find_service_flow(dev_idx, pSFParam->SFID)) {
+		cc = WIMAX_SF_NOT_FOUND;
+		goto out;
+	}
+
+	xprintf(SDK_INFO, "CmdDeleteSF: SFID=%08x", pSFParam->SFID);
+
+	hci = malloc(sizeof(struct hci) + 128);
+	if (!hci) {
+		cc = -1;//WIMAX_API_RET_FAILED;
+		goto out;
+	}
+
+	hci->cmd_evt = htons(WIMAX_DSX_REQUEST);
+	hci->length = 0;
+	hci->data[hci->length++] = 2; /* DSD */
+	hci->data[hci->length++] = 1; /* Use the following parameter */
+
+	/* Start of TLV */
+	hci->data[hci->length++] = 145 + pSFParam->DL;
+	hci->data[hci->length++] = 1 + 1 + 4; /* T(1) + L (1) + V(4) */
+	append_tlv(hci, 1, 4, pSFParam->SFID);
+
+	pthread_mutex_lock(&dev->wimax->dev_info.service_flow.dsxlock);
+
+	xprintf(SDK_DBG, "DSD-REQ(len=%d)\n", hci->length);
+	xprintf_hex(SDK_DBG, SDK_LOG_TITLE, hci->data, hci->length);
+	
+	sf_send_hci(dev_idx, hci);
+	free(hci);
+
+	gettimeofday(&tv, NULL);
+	timeval2timespec(&tv, &ts);
+	ts.tv_sec += DSX_REQUEST_TIMEOUT;
+	ret = pthread_cond_timedwait(&dev->wimax->dev_info.service_flow.dsx_cond, &dev->wimax->dev_info.service_flow.dsxlock, &ts);
+	if (ret) {
+		xprintf(SDK_ERR, "CmdDeleteSF Error (pthread_cond_timedwait=%d)\n", ret);
+		pthread_mutex_unlock(&dev->wimax->dev_info.service_flow.dsxlock);
+		cc = -1; //WIMAX_API_RET_FAILED;
+		goto out;
+	}
+	//pthread_cond_wait(&dev->wimax->dev_info.service_flow.dsx_cond, &dev->wimax->dev_info.service_flow.dsxlock);
+
+	cc = dev->wimax->dev_info.service_flow.last_sf_event.sf.cc;		
+	pthread_mutex_unlock(&dev->wimax->dev_info.service_flow.dsxlock);
+
+	xprintf(SDK_INFO, "DSD-REQ: %s\n", wimax_stringify_dsx_cc(cc));
+
+out:
+	dm_put_dev(dev_idx);
+	xfunc_out("ret=%d", cc);
+	return cc;
+}
+
+
+#define ARRAY_SIZE(x)	sizeof(x)/sizeof(x[0])
+
+struct parse_data {
+	char 		*name;
+	unsigned int		offset;
+	unsigned int 		size;
+	int 		(*parser)(const struct parse_data *data, void *ptr,
+				  int line, const char *value);
+};
+
+
+#define ENDMARKER	{.name = NULL, }
+
+#define SFP(f)		#f, offsetof(struct wimax_sf_param, f), sizeof(((struct wimax_sf_param *)0)->f)
+#define SFP_INT(f)	{SFP(f), parse_int}
+#define SFP_STR(f)	{SFP(f), parse_str}
+#define SFP_FUNC(f)	{SFP(f), parse_##f}
+#define SFP_FUNC1(f, p) {SFP(f), p}
+
+#define CLRP(f)		#f, offsetof(struct wimax_classification_rule, f), sizeof(((struct wimax_classification_rule *)0)->f)
+#define CLR_INT(f)	{CLRP(f), parse_int}
+#define CLR_STR(f)	{CLRP(f), parse_str}
+#define CLR_FUNC(f)	{CLRP(f), parse_##f}
+#define CLR_FUNC1(f, p) {CLRP(f), p}
+
+#define PHSP(f)		#f, offsetof(struct wimax_phs_rule, f), sizeof(((struct wimax_phs_rule *)0)->f)
+#define PHS_INT(f)	{PHSP(f), parse_int}
+#define PHS_STR(f)	{PHSP(f), parse_str}
+
+static int parse_int(const struct parse_data *data,
+		     void *ptr, int line, const char *value)
+{
+	void *dst = ptr + data->offset;
+	int32_t val = strtol(value, NULL, 0);
+
+	switch (data->size) {
+	case 1:
+		*(uint8_t *)dst = (uint8_t) val;
+		break;
+	case 2:
+		put_unaligned_u16(dst, (uint16_t)val);
+		break;
+	case 4:
+		put_unaligned_u32(dst, val);
+		break;
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+static int hex2num(char c)
+{
+	if (c >= '0' && c <= '9')
+		return c - '0';
+	if (c >= 'a' && c <= 'f')
+		return c - 'a' + 10;
+	if (c >= 'A' && c <= 'F')
+		return c - 'A' + 10;
+	return -1;
+}
+
+
+static int hex2byte(const char *hex)
+{
+	int a, b;
+	a = hex2num(*hex++);
+	if (a < 0)
+		return -1;
+	b = hex2num(*hex++);
+	if (b < 0)
+		return -1;
+	return (a << 4) | b;
+}
+
+int hexstr2bin(const char *hex, uint8_t *buf, unsigned int len)
+{
+        unsigned int i;
+        int a;
+        const char *ipos = hex;
+        uint8_t *opos = buf;
+
+        for (i = 0; i < len; i++) {
+                a = hex2byte(ipos);
+                if (a < 0)
+                        return -1;
+                *opos++ = a;
+                ipos += 2;
+        }
+        return 0;
+}
+
+
+static char *parse_string(const char *value, unsigned int *len)
+{
+	if (*value == '"') {
+		char *pos;
+		value++;
+		pos = strrchr(value, '"');
+		if (pos == NULL || pos[1] != '\0')
+			return NULL;
+		*pos = '\0';
+		*len = strlen(value);
+		return strdup(value);
+	} else {
+		uint8_t *str;
+		unsigned int hlen = strlen(value);
+		if (hlen & 1)
+			return NULL;
+		*len = hlen / 2;
+		str = malloc(*len);
+		if (str == NULL)
+			return NULL;
+		if (hexstr2bin(value, str, *len)) {
+			free(str);
+			return NULL;
+		}
+		return (char *) str;
+	}
+}
+
+static int parse_str(const struct parse_data *data,
+		     void *ptr, int line, const char *value)
+{
+	unsigned int res_len;
+	char *dst, *tmp;
+
+	tmp = parse_string(value, &res_len);
+	if (tmp == NULL) {
+		printf("Line %d: failed to parse %s '%s'\n", line, data->name, value);
+		return -1;
+	}
+	
+	dst = (char *)(ptr + data->offset);
+	memcpy(dst, tmp, data->size);
+	free(tmp);
+	return 0;
+}
+
+static int parse_TypeOfDataDeliveryServices(const struct parse_data *data,
+					    void *ptr, int line, const char *value)
+{
+	uint8_t tdds = DATA_SERVICE_BE;
+	struct wimax_sf_param *p = ptr;
+	
+	if (strcmp(value, "UGS") == 0)
+		tdds = DATA_SERVICE_UGS;
+	else if (strcmp(value, "RT-VR") == 0)
+		tdds = DATA_SERVICE_RT_VR;
+	else if (strcmp(value, "NRT-VR") == 0)
+		tdds = DATA_SERVICE_NRT_VR;
+	else if (strcmp(value, "BE") == 0)
+		tdds = DATA_SERVICE_BE;
+	else if (strcmp(value, "ERT-VR") == 0)
+		tdds = DATA_SERVICE_ERT_VR;
+
+	p->TypeOfDataDeliveryServices = tdds;
+
+	return 0;
+}
+
+static int parse_ULGrantSchedulingType(const struct parse_data *data,
+				       void *ptr, int line, const char *value)
+{
+	uint8_t sched = UL_SCHED_TYPE_BE; 
+	struct wimax_sf_param *p = ptr;
+	
+	if (strcmp(value, "UGS") == 0)
+		sched = UL_SCHED_TYPE_UGS;
+	else if (strcmp(value, "nrtPS") == 0)
+		sched = UL_SCHED_TYPE_nrtPS;
+	else if (strcmp(value, "rtPS") == 0)
+		sched = UL_SCHED_TYPE_rtPS;
+	else if (strcmp(value, "BE") == 0)
+		sched = UL_SCHED_TYPE_BE;
+	else if (strcmp(value, "ertPS") == 0)
+		sched = UL_SCHED_TYPE_ertPS;
+
+	p->ULGrantSchedulingType = sched;
+
+	return 0;
+}
+
+static const struct parse_data sf_param_table[] = {
+	SFP_INT(DL),
+	SFP_INT(SFID),
+	SFP_INT(CID),
+	SFP_STR(ServiceClassName),
+	SFP_INT(QosParamSetType),
+	SFP_INT(TrafficPriority),
+	SFP_INT(MaxSustainedTrafficRate),
+	SFP_INT(MaxTrafficBurst),
+	SFP_INT(MinReservedTrafficRate),
+	SFP_INT(MinTolerableRate),
+	SFP_FUNC(ULGrantSchedulingType),
+	SFP_INT(RequestTransmissionPolicy),
+	SFP_INT(ToleratedJitter),
+	SFP_INT(MaxLatency),
+	SFP_INT(FixedLengthSDUIndicator),
+	SFP_INT(SDUSize),
+	SFP_INT(TargetSAID),
+	SFP_INT(ARQEnable),
+	SFP_INT(CSSpecification),
+	SFP_FUNC(TypeOfDataDeliveryServices),
+	SFP_INT(SDUInterArrivalInterval),
+	SFP_INT(TimeBase),
+	SFP_INT(PagingPreference),
+	SFP_INT(TrafficPreferenceIndication),
+	SFP_STR(GlobalServiceClassName),
+	SFP_INT(SNFeedbackEnabled),
+	SFP_INT(FSNSize),
+	SFP_INT(UnsolicitedGrantInterval),
+	SFP_INT(UnsolicitedPollingInterval),
+	SFP_INT(PDUSNExtendedSubheaderForHARQReordering),
+	SFP_INT(HARQServiceFlows),
+	/*ENDMARKER,*/
+};
+
+static int parse_ipv4(const struct parse_data *data,
+		     void *ptr, int line, const char *value)
+{
+	char *pos;
+	struct ipv4_addr am;
+
+	pos = strchr(value, '/');
+	*pos++ = '\0';
+
+	if (!inet_pton(AF_INET, value, &am.address) ||
+	    !inet_pton(AF_INET, pos, &am.mask)) {
+		printf("Lined %d: invalid IPv4 address/mask\n", line);
+		return -1;
+	}
+
+	memcpy(ptr + data->offset, &am, sizeof(am));
+
+	return 0;
+}
+
+static int in_ether(const char *bufp, uint8_t *mac)
+{
+	unsigned char *ptr;
+	char c;
+	const char *orig;
+	int i;
+	unsigned val;
+
+	i = 0;
+	orig = bufp;
+	ptr = mac;
+
+	while ((*bufp != '\0') && (i < 6)) {
+		val = 0;
+		c = *bufp++;
+		if (isdigit(c))
+			val = c - '0';
+		else if (c >= 'a' && c <= 'f')
+			val = c - 'a' + 10;
+		else if (c >= 'A' && c <= 'F')
+			val = c - 'A' + 10;
+		else 
+			return (-1);
+	
+		val <<= 4;
+		c = *bufp;
+		if (isdigit(c))
+			val |= c - '0';
+		else if (c >= 'a' && c <= 'f')
+			val |= c - 'a' + 10;
+		else if (c >= 'A' && c <= 'F')
+			val |= c - 'A' + 10;
+		else if (c == ':' || c == 0)
+			val >>= 4;
+		else 
+			return (-1);
+	
+		if (c != 0)
+			bufp++;
+		*ptr++ = (unsigned char) (val & 0377);
+		i++;
+
+		/* We might get a semicolon here - not required. */
+		if (*bufp == ':') {
+			if (i == 6) 
+				printf("in_ether(%s): trailing : ignored!\n", orig);
+			bufp++;
+		}
+	}
+
+	/* That's it.  Any trailing junk? */
+	if ((i == 6) && (*bufp != '\0')) 
+		return -1;
+
+	return 0;
+}
+
+
+static int parse_ether(const struct parse_data *data,
+		     void *ptr, int line, const char *value)
+{
+	char *mask;
+	int ret;
+
+	mask = strchr(value, '/');
+	if (mask == NULL)
+		return -1;
+
+	*mask++ = '\0';
+	
+	ret = in_ether(value, ptr + data->offset);
+	if (ret < 0)
+		return ret;
+
+	ret = in_ether(mask, ptr + data->offset + 6);
+	return ret;
+}
+
+
+static const struct parse_data classifier_table[] = {
+	CLR_INT(ClassifierRulePriority),
+	CLR_INT(PacketClassifierRuleIndex),
+	
+	CLR_INT(IPTypeOfService.low),
+	CLR_INT(IPTypeOfService.high),
+	CLR_INT(IPTypeOfService.mask),
+
+	CLR_INT(Protocol),
+	
+	CLR_FUNC1(IPv4MaskedSourceAddress, parse_ipv4),
+	CLR_FUNC1(IPv4MaskedDestAddress, parse_ipv4),
+	
+	CLR_INT(ProtocolSourcePort.low),
+	CLR_INT(ProtocolSourcePort.high),
+	
+	CLR_INT(ProtocolDestPort.low),
+	CLR_INT(ProtocolDestPort.high),
+
+	CLR_FUNC1(EthernetDestMACAddress, parse_ether),
+	CLR_FUNC1(EthernetSourceMACAddress, parse_ether),
+
+	CLR_INT(EtherType.type),
+	CLR_INT(EtherType.eprot1),
+	CLR_INT(EtherType.eprot2),
+	
+	CLR_INT(IEEE802_1D_UserPriority.low),
+	CLR_INT(IEEE802_1D_UserPriority.high),
+	
+	CLR_INT(IEEE802_1Q_VLANID),
+
+	CLR_INT(AssociatedPHSI), 
+	/*ENDMARKER,*/
+};
+
+static const struct parse_data phs_table[] = {
+	PHS_INT(PHSI),
+	PHS_INT(PHSS),
+	PHS_STR(PHSM),
+	PHS_STR(PHSF),
+	PHS_INT(PHSV),
+	/*ENDMARKER,*/
+};
+
+static char *get_line(char *s, int size, FILE *stream, int *line,
+		      char **_pos)
+{
+	char *pos, *end, *sstart;
+
+	while (fgets(s, size, stream)) {
+		(*line)++;
+		s[size - 1] = '\0';
+		pos = s;
+
+		/* Skip white space from the beginning of line. */
+		while (*pos == ' ' || *pos == '\t' || *pos == '\r')
+			pos++;
+
+		/* Skip comment lines and empty lines */
+		if (*pos == '#' || *pos == '\n' || *pos == '\0')
+			continue;
+
+		/*
+		 * Remove # comments unless they are within a double quoted
+		 * string.
+		 */
+		sstart = strchr(pos, '"');
+		if (sstart)
+			sstart = strrchr(sstart + 1, '"');
+		if (!sstart)
+			sstart = pos;
+		end = strchr(sstart, '#');
+		if (end)
+			*end-- = '\0';
+		else
+			end = pos + strlen(pos) - 1;
+
+		/* Remove trailing white space. */
+		while (end > pos &&
+		       (*end == '\n' || *end == ' ' || *end == '\t' ||
+			*end == '\r'))
+			*end-- = '\0';
+
+		if (*pos == '\0')
+			continue;
+
+		if (_pos)
+			*_pos = pos;
+		return pos;
+	}
+
+	if (_pos)
+		*_pos = NULL;
+	return NULL;
+}
+
+int parse_sf_param(struct wimax_sf_param *sfp,
+		   const char *var, const char *value, int line)
+{
+	int i, ret = 0;
+	
+	if (sfp == NULL || var == NULL || value == NULL)
+		return -1;
+
+	for (i = 0; i < ARRAY_SIZE(sf_param_table); i++) {
+		const struct parse_data *field = &sf_param_table[i];
+		if (strcasecmp(var, field->name) != 0)
+			continue;
+
+		if (field->parser(field, sfp, line, value)) {
+			if (line) {
+				printf("Line %d: failed to parse %s '%s'\n",
+				       line, var, value);
+			}
+			ret = -1;
+		}
+		break;
+	}
+	if (i == ARRAY_SIZE(sf_param_table)) {
+		if (line) {
+			printf("Line %d: unknown service flow parameter '%s'\n",
+			       line, var);
+		}
+		ret = -1;
+	}
+
+	return ret;
+}
+
+
+
+int parse_classifier(struct wimax_classification_rule *c,
+		     const char *var, const char *value, int line)
+{
+	int i, ret = 0;
+	
+	if (c == NULL || var == NULL || value == NULL)
+		return -1;
+
+	for (i = 0; i < ARRAY_SIZE(classifier_table); i++) {
+		const struct parse_data *field = &classifier_table[i];
+		if (strcasecmp(var, field->name) != 0)
+			continue;
+
+		if (field->parser(field, c, line, value)) {
+			if (line) {
+				printf("Line %d: failed to parse %s '%s'\n",
+				       line, var, value);
+			}
+			ret = -1;
+		}
+		break;
+	}
+	if (i == ARRAY_SIZE(classifier_table)) {
+		if (line) {
+			printf("Line %d: unknown classifier rule '%s'\n",
+			       line, var);
+		}
+		ret = -1;
+	}
+
+	return ret;	
+}
+
+static int read_classifier(struct wimax_classification_rule *c, FILE *f, int *line)
+{
+	int errors = 0, end = 0;
+	char buf[256], *pos, *pos2;
+
+	*c = classifier_rule_init;
+
+	while (get_line(buf, sizeof(buf), f, line, &pos)) {
+		if (strcmp(pos, "}") == 0) {
+			end = 1;
+			break;
+		}
+
+		pos2 = strchr(pos, '=');
+		if (pos2 == NULL) {
+			printf("Line %d: invalid classifier rule line '%s'\n", *line, pos);
+			errors++;
+			continue;
+		}
+		*pos2++ = '\0';
+		if (*pos2 == '"') {
+			if (strchr(pos2+1, '"') == NULL) {
+				printf("Line %d: unterminated string '%s'\n", *line, pos2);
+				errors++;
+				continue;
+			}
+		}
+
+		if (parse_classifier(c, pos, pos2, *line) < 0) {
+			errors++;
+		}			
+	}
+
+	if (!end) {
+		printf("Line %d: classifier rule block was not terminated properly\n", *line);
+		errors++;
+	}
+
+	return (errors? -1: 0);
+}
+
+
+
+int parse_phs(struct wimax_phs_rule *p,
+		     const char *var, const char *value, int line)
+{
+	int i, ret = 0;
+	
+	if (p == NULL || var == NULL || value == NULL)
+		return -1;
+
+	for (i = 0; i < ARRAY_SIZE(phs_table); i++) {
+		const struct parse_data *field = &phs_table[i];
+		if (strcasecmp(var, field->name) != 0)
+			continue;
+		if (field->parser(field, p, line, value)) {
+			if (line) {
+				printf("Line %d: failed to parse %s '%s'\n",
+				       line, var, value);
+			}
+			ret = -1;
+		}
+		break;
+	}
+	if (i == ARRAY_SIZE(phs_table)) {
+		if (line) {
+			printf("Line %d: unknown phs rule '%s'\n",
+			       line, var);
+		}
+		ret = -1;
+	}
+
+	return ret;
+}
+
+static int read_phs(struct wimax_phs_rule *p, FILE *f, int *line)
+{
+	int errors = 0, end = 0;
+	char buf[256], *pos, *pos2;
+
+	*p = phs_rule_init;
+
+	while (get_line(buf, sizeof(buf), f, line, &pos)) {
+		if (strcmp(pos, "}") == 0) {
+			end = 1;
+			break;
+		}
+
+		pos2 = strchr(pos, '=');
+		if (pos2 == NULL) {
+			printf("Line %d: invalid classifier rule line '%s'\n", *line, pos);
+			errors++;
+			continue;
+		}
+		*pos2++ = '\0';
+		if (*pos2 == '"') {
+			if (strchr(pos2+1, '"') == NULL) {
+				printf("Line %d: unterminated string '%s'\n", *line, pos2);
+				errors++;
+				continue;
+			}
+		}
+		
+		if (parse_phs(p, pos, pos2, *line) < 0) {
+			errors++;
+		}			
+	}
+
+	if (!end) {
+		printf("Line %d: classifier rule block was not terminated properly\n", *line);
+		errors++;
+	}
+
+	return (errors? -1: 0);
+	return -1; 
+}
+
+
+static int read_service_flow(struct wimax_sf_param *param, FILE *f, int *line)
+{
+	int errors = 0, end = 0;
+	char buf[256], *pos, *pos2;
+
+	*param = sf_param_init;
+
+	while (get_line(buf, sizeof(buf), f, line, &pos)) {
+		if (strcmp(pos, "}") == 0) {
+			end = 1;
+			break;
+		} else {
+			pos2 = strchr(pos, '=');
+			if (pos2 == NULL) {
+				printf("Line %d: invalid sf parameter line '%s'\n", *line, pos);
+				errors++;
+				continue;
+			}
+			*pos2++ = '\0';
+			if (*pos2 == '"') {
+				if (strchr(pos2+1, '"') == NULL) {
+					printf("Line %d: unterminated string '%s'\n", *line, pos2);
+					errors++;
+					continue;
+				}
+			}
+
+			if (parse_sf_param(param, pos, pos2, *line) < 0) {
+				errors++;
+			}
+		}
+	}
+
+	if (!end) {
+		printf("Line %d: service flow block was not terminated properly\n", *line);
+		errors++;
+	}
+
+	return errors? -1 : 0;
+}
+
+int load_sf(const char *name,
+	    WIMAX_SF_PARAM **sfp,
+	    WIMAX_CLFR_RULE **classifier,
+	    WIMAX_PHS_RULE **phs)
+{
+	FILE *f;
+	char buf[1024], *pos;
+	int line = 0, errors = 0;
+	WIMAX_SF_PARAM *tsfp = *sfp;
+	WIMAX_CLFR_RULE *tclr = *classifier;
+	WIMAX_PHS_RULE *tphs = *phs;
+
+	*sfp = NULL;
+	*classifier = NULL;
+	*phs = NULL;
+
+	f = fopen(name, "r");
+	if (f == NULL)
+		return -1;
+
+	while (get_line(buf, sizeof(buf), f, &line, &pos)) {
+		if (strcmp(pos, "service_flow={") == 0) {
+			if (read_service_flow(tsfp, f, &line) < 0) {
+				*sfp = NULL;
+				errors++;
+				continue;
+			}
+			*sfp = tsfp;
+		} else if (strcmp(pos, "classifier={") == 0) {
+			if (read_classifier(tclr, f, &line) < 0) {
+				*classifier = NULL;
+				errors++;
+				continue;
+			}
+			*classifier = tclr;
+		} else if (strcmp(pos, "phs={") == 0) {
+			if (read_phs(tphs, f, &line) < 0) {
+				*phs = NULL;
+				errors++;
+				continue;
+			}
+			*phs = tphs;
+		}
+	}
+	fclose(f);
+
+	return (errors > 0)? -1: 0;
+}
+
+void sf_init(int dev_idx)
+{
+	device_t *dev;
+
+	xfunc_in();
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return;
+
+	pthread_mutex_init(&dev->wimax->dev_info.service_flow.sfreadlock, NULL);
+	pthread_mutex_init(&dev->wimax->dev_info.service_flow.sfwritelock, NULL);
+	pthread_mutex_init(&dev->wimax->dev_info.service_flow.dsxlock, NULL);
+	pthread_cond_init(&dev->wimax->dev_info.service_flow.dsx_cond, NULL);
+
+	dm_put_dev(dev_idx);
+	xfunc_out();
+}
+
+void sf_deinit(int dev_idx)
+{
+	device_t *dev;
+
+	xfunc_in();
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return;
+
+	pthread_mutex_destroy(&dev->wimax->dev_info.service_flow.sfreadlock);
+	pthread_mutex_destroy(&dev->wimax->dev_info.service_flow.sfwritelock);
+	pthread_mutex_destroy(&dev->wimax->dev_info.service_flow.dsxlock);
+	pthread_cond_destroy(&dev->wimax->dev_info.service_flow.dsx_cond);
+
+	dm_put_dev(dev_idx);
+	xfunc_out();
+}
+
diff --git a/sdk/sf.h b/sdk/sf.h
new file mode 100644
index 0000000..e37b716
--- /dev/null
+++ b/sdk/sf.h
@@ -0,0 +1,49 @@
+// 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.
+
+#if !defined(SERVICE_FLOW_H_20100827) && defined(CONFIG_ENABLE_SERVICE_FLOW)
+#define SERVICE_FLOW_H_20100827
+
+#include "gcttype.h"
+
+typedef struct wm_service_flow_s {
+	WIMAX_SERVICE_FLOW		sf[WIMAX_MAX_SERVICE_FLOW];
+	pthread_mutex_t	sfreadlock;
+	pthread_mutex_t	sfwritelock;
+	pthread_mutex_t	dsxlock;
+	pthread_cond_t dsx_cond;
+	WIMAX_SF_EVENT last_sf_event;
+} wm_service_flow_t;
+
+void sf_init(int dev_idx);
+void sf_deinit(int dev_idx);
+void BeginSFRead(int dev_idx);
+void EndSFRead(int dev_idx);
+WIMAX_SERVICE_FLOW *GetNextSF(int dev_idx,
+		      WIMAX_SERVICE_FLOW *pSF,
+		      UINT8 Direction);
+WIMAX_SERVICE_FLOW *GetServiceFlow(int dev_idx,
+			   UINT32 SFID);
+WIMAX_CLFR_RULE *GetNextClfrRule(WIMAX_SERVICE_FLOW *pSF,
+			 WIMAX_CLFR_RULE *pCLFRRule);
+WIMAX_CLFR_RULE *GetClfrRule(WIMAX_SERVICE_FLOW *pSF,
+		     UINT16 PacketClassfierRuleIndex);
+WIMAX_PHS_RULE *GetNextPHSRule(WIMAX_SERVICE_FLOW *pSF,
+		       WIMAX_PHS_RULE *pPHSRule);
+WIMAX_PHS_RULE *GetPHSRule(WIMAX_SERVICE_FLOW *pSF,
+		   UINT8 PHSI);
+WIMAX_SF_CC CmdAddSF(int dev_idx,
+	     WIMAX_SF_PARAM_P pSFParam,
+	     WIMAX_CLFR_RULE_P pClfrRule,
+	     WIMAX_PHS_RULE_P pPHSRule);
+WIMAX_SF_CC CmdChangeSF(int dev_idx,
+		WIMAX_SF_PARAM_P pSFParam,
+		WIMAX_CLFR_DSC_ACTION CLFRDSCAction,
+		WIMAX_CLFR_RULE_P pClfrRule,
+		WIMAX_PHS_DSC_ACTION PHSDSCAction,
+		WIMAX_PHS_RULE_P pPHSRule);
+WIMAX_SF_CC CmdDeleteSF(int dev_idx,
+		WIMAX_SF_PARAM_P pSFParam);
+#endif
+ 
diff --git a/sdk/timer.c b/sdk/timer.c
new file mode 100644
index 0000000..8e4953e
--- /dev/null
+++ b/sdk/timer.c
@@ -0,0 +1,447 @@
+// 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 <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "timer.h"
+
+#if 1
+#include "log.h"
+#define timer_func_in(fmt, args...)			xfunc_in(fmt, ## args)
+#define timer_func_out(fmt, args...)		xfunc_out(fmt, ## args)
+#define timer_iprintf(fmt, args...)			xprintf(SDK_INFO, fmt, ## args)
+#define timer_dprintf(fmt, args...)			xprintf(SDK_DBG, fmt, ## args)
+#define timer_eprintf(fmt, args...)			xprintf(SDK_ERR, fmt, ## args)
+#define timer_std_eprintf(fmt, args...)		xprintf(SDK_STD_ERR, fmt, ## args)
+#else
+#define timer_func_in(fmt, args...)			fprintf(stdout, "+%s " fmt "\n", __FUNCTION__, ## args)
+#define timer_func_out(fmt, args...)		fprintf(stdout, "-%s " fmt "\n", __FUNCTION__, ## args)
+#define timer_iprintf(fmt, args...)			fprintf(stdout, fmt, ## args)
+#define timer_dprintf(fmt, args...)			fprintf(stdout, fmt, ## args)
+#define timer_eprintf(fmt, args...)			fprintf(stderr, "%s " fmt, __FUNCTION__, ## args)
+#define timer_std_eprintf(fmt, args...)		fprintf(stderr, "%s err=%s(%d):" fmt,\
+											__FUNCTION__, strerror(errno), errno, ## args)
+#endif
+
+#define CREATED_MASK		0x54494D45UL
+
+#if defined(PTHREAD_TIMER)
+//#define TIMER_ASSERT
+
+typedef struct pthread_timer_s {
+	unsigned		tt_inited;
+	pthread_t 		tt_thread;
+	pthread_mutex_t tt_lock;
+	pthread_cond_t 	tt_cond;
+
+	struct list_head	tt_head;
+	timer_obj_t			*tt_active;
+	
+} pthread_timer_t;
+
+static pthread_timer_t pthread_timer;
+
+static struct timespec *get_timespec_ms(struct timespec *ts, int timeout_ms)
+{
+	#define nsec_per_sec	(1000*1000*1000)
+	#define ps_timeval2timespec(tv,ts)	\
+		((ts)->tv_sec = (tv)->tv_sec, (ts)->tv_nsec = (tv)->tv_usec * 1000)
+	struct timeval tv;
+	int sec, nsec;
+
+	sec = timeout_ms/1000;
+	nsec = (timeout_ms%1000) * 1000/*usec*/ * 1000/*nsec*/;
+
+	gettimeofday(&tv, NULL);
+	ps_timeval2timespec(&tv, ts);
+	ts->tv_sec += sec;
+	ts->tv_nsec += nsec;
+
+	if (ts->tv_nsec >= nsec_per_sec) {
+		ts->tv_sec++;
+		ts->tv_nsec -= nsec_per_sec;
+	}
+	return ts;
+}
+
+static struct timespec *cmp_earlier_timespec(struct timespec *ts1, struct timespec *ts2)
+{
+	if (ts1->tv_sec == ts2->tv_sec) {
+		if (ts1->tv_nsec < ts2->tv_nsec)
+			return ts1;
+	}
+	else if (ts1->tv_sec < ts2->tv_sec)
+		return ts1;
+	return ts2;
+}
+
+#if defined(TIMER_ASSERT)
+static void time_assert(struct timespec *ts)
+{
+	struct timespec curr_ts;
+
+	get_timespec_ms(&curr_ts, 0);
+
+	assert(cmp_earlier_timespec(&curr_ts, ts) == ts);
+}
+#endif
+
+static void *timer_thread(void *thr_data)
+{
+	pthread_timer_t *ptt = &pthread_timer;
+	struct list_head *head = &ptt->tt_head;
+	timer_obj_t *to;
+	void *data;
+	void (*callback)(void *data);
+	int ret;
+
+	timer_func_in();
+
+	while (1) {
+		pthread_mutex_lock(&ptt->tt_lock);
+
+		/*
+		start_timer is called, cond-lock is released,
+		but at that time,
+		if stop_timer is called before wake up cond-wait, the list becomes empty.
+		Thus, we use while loop instead of if.
+		*/
+		while (list_empty(head))
+			ret = pthread_cond_wait(&ptt->tt_cond, &ptt->tt_lock);
+
+		to = list_entry(head->next, timer_obj_t, to_list);
+		list_del_init(&to->to_list);
+
+		ptt->tt_active = to;
+		ret = pthread_cond_timedwait(&ptt->tt_cond, &ptt->tt_lock, &to->to_ts);
+		ptt->tt_active = NULL;
+		if (ret == ETIMEDOUT && to->to_active) {
+			#if defined(TIMER_ASSERT)
+			time_assert(&to->to_ts);
+			#endif
+			callback = to->to_callback;
+			data = to->to_data;
+			pthread_mutex_lock(&to->to_lock);
+		}
+		else
+			callback = NULL;
+		pthread_mutex_unlock(&ptt->tt_lock);
+
+		if (callback) {
+			timer_dprintf("+timer(%p) callback\n", to);
+			callback(data);
+			timer_dprintf("-timer callback\n");
+			pthread_mutex_unlock(&to->to_lock);
+		}
+	}
+
+	timer_func_out();
+	return NULL;
+}
+
+int init_timer(timer_obj_t *timer, void (*callback)(void *), void *data)
+{
+	pthread_timer_t *ptt = &pthread_timer;
+
+	if (!ptt->tt_inited) {
+		timer_eprintf("Timer module hasn't been initialized!!\n");
+		return -1;
+	}
+
+	timer_func_in("timer=%p, callback=%p, data=%p", timer, callback, data);
+
+	if (!timer || !callback || !data) {
+		timer_eprintf("Invalid parameter\n");
+		return -1;
+	}
+
+	pthread_mutex_init(&timer->to_lock, NULL);
+	INIT_LIST_HEAD(&timer->to_list);
+	timer->to_callback = callback;
+	timer->to_data = data;
+	timer->to_active = 0;
+	timer->to_created = CREATED_MASK;
+
+	timer_func_out();
+	return 0;
+}
+
+int start_timer(timer_obj_t *timer, int expire_milisec)
+{
+	pthread_timer_t *ptt = &pthread_timer;
+	struct list_head *head = &ptt->tt_head;
+	timer_obj_t *pos;
+	struct timespec ts;
+	int ret = 0, inserted = 0;
+
+	if (!ptt->tt_inited) {
+		timer_eprintf("Timer module hasn't been initialized!!\n");
+		return -1;
+	}
+
+	timer_func_in("timer=%p, expire_milisec=%d", timer, expire_milisec);
+
+	get_timespec_ms(&ts, expire_milisec);
+
+	pthread_mutex_lock(&ptt->tt_lock);
+	if (timer->to_created != CREATED_MASK) {
+		timer_eprintf("The timer was not to_created or deleted.\n");
+		goto out;
+	}
+	if (pthread_self() != ptt->tt_thread)
+		pthread_mutex_lock(&timer->to_lock);
+
+	memcpy(&timer->to_ts, &ts, sizeof(ts));
+	timer->to_active = 1;
+	timer->to_caller = __builtin_return_address(0);
+
+	if (list_empty(head))
+		list_add(&timer->to_list, head);
+	else {
+		list_for_each_entry(pos, head, to_list) {
+			if (pos != timer) {
+				if (cmp_earlier_timespec(&timer->to_ts, &pos->to_ts) == &timer->to_ts) {
+					if (list_empty(&timer->to_list))	/*It isn't in list*/
+						list_add(&timer->to_list, &pos->to_list);
+					else
+						list_move(&timer->to_list, &pos->to_list);
+					inserted = 1;
+					break;
+				}
+			}
+		}
+
+		if (!inserted) {
+			if (list_empty(&timer->to_list))	/*It isn't in list*/
+				list_add_tail(&timer->to_list, head);
+			else
+				list_move_tail(&timer->to_list, head);
+		}
+	}
+	
+	assert(!list_empty(&timer->to_list));
+
+	if (ptt->tt_active) {
+		if (ptt->tt_active == timer)
+			pthread_cond_signal(&ptt->tt_cond);
+		else if (list_entry(head->next, timer_obj_t, to_list) == timer) {/*is head?*/
+			if (cmp_earlier_timespec(&timer->to_ts, &ptt->tt_active->to_ts)
+				== &timer->to_ts) {
+				list_add(&ptt->tt_active->to_list, &timer->to_list);
+				pthread_cond_signal(&ptt->tt_cond);
+			}
+		}
+	}
+	else if (list_entry(head->next, timer_obj_t, to_list) == timer) /*is head?*/
+		pthread_cond_signal(&ptt->tt_cond);
+
+	if (pthread_self() != ptt->tt_thread)
+		pthread_mutex_unlock(&timer->to_lock);
+out:
+	pthread_mutex_unlock(&ptt->tt_lock);
+	timer_func_out("ret=%d", ret);
+	return ret;
+}
+
+int stop_timer(timer_obj_t *timer)
+{
+	pthread_timer_t *ptt = &pthread_timer;
+	int ret = 0;
+
+	if (!ptt->tt_inited) {
+		timer_eprintf("Timer module hasn't been initialized!!\n");
+		return -1;
+	}
+
+	timer_func_in("timer=%p", timer);
+
+	pthread_mutex_lock(&ptt->tt_lock);
+	if (timer->to_created != CREATED_MASK) {
+		timer_iprintf("The timer was not to_created or deleted.\n");
+		goto out;
+	}
+	if (pthread_self() != ptt->tt_thread)
+		pthread_mutex_lock(&timer->to_lock);
+
+	timer->to_active = 0;
+
+	if (ptt->tt_active == timer)
+		pthread_cond_signal(&ptt->tt_cond);
+	else
+		list_del_init(&timer->to_list);
+
+	if (pthread_self() != ptt->tt_thread)
+		pthread_mutex_unlock(&timer->to_lock);
+out:
+	pthread_mutex_unlock(&ptt->tt_lock);
+	timer_func_out("ret=%d", ret);
+	return ret;
+}
+
+int del_timer(timer_obj_t *timer)
+{
+	int ret = 0;
+
+	timer_func_in("timer=%p", timer);
+
+	ret = stop_timer(timer);
+	timer->to_created = 0;
+
+	timer_func_out("ret=%d", ret);
+	return ret;
+}
+
+int timer_module_init(void)
+{
+	pthread_timer_t *ptt = &pthread_timer;
+
+	timer_func_in();
+
+	INIT_LIST_HEAD(&ptt->tt_head);
+
+	pthread_mutex_init(&ptt->tt_lock, NULL);
+	pthread_cond_init(&ptt->tt_cond, NULL);
+	ptt->tt_inited = 1;
+
+	pthread_create(&ptt->tt_thread, NULL, timer_thread, (void *) NULL);
+	
+	timer_func_out();
+	return 0;
+}
+
+void timer_module_deinit(void)
+{
+	pthread_timer_t *ptt = &pthread_timer;
+	pthread_t thread;
+
+	timer_func_in();
+	
+	if ((thread = ptt->tt_thread)) {
+		ptt->tt_thread = (pthread_t) NULL;
+		pthread_cancel(thread);
+		pthread_join(thread, NULL);
+	}
+
+	pthread_mutex_destroy(&ptt->tt_lock);
+	pthread_cond_destroy(&ptt->tt_cond);
+	ptt->tt_inited = 0;
+
+	timer_func_out();
+}
+#else
+#include <signal.h>
+
+#define SIGNO_TIMER			SIGRTMIN
+
+static void timer_callback(int signum, siginfo_t *si, void *sv)
+{
+	timer_obj_t *timer = si->_sifields._rt.si_sigval.sival_ptr;
+	void (*callback)(void *data) = timer->to_callback;
+
+	assert(signum == SIGNO_TIMER);
+
+	timer_func_in();
+	if (callback) {
+		timer_dprintf("+timer callback\n");
+		callback(timer->to_data);
+		timer_dprintf("-timer callback\n");
+	}
+	timer_func_out();
+}
+
+int init_timer(timer_obj_t *timer, void (*callback)(void *), void *data)
+{
+	struct sigaction sa_rt;
+	struct sigevent sigev;
+
+	timer_func_in("timer=%p, callback=%p, data=%p\n", timer, callback, data);
+
+	if (!timer || !callback || !data) {
+		timer_eprintf("Invalid parameter\n");
+		return -1;
+	}
+
+	memset(&sa_rt, 0, sizeof(sa_rt));
+	sigemptyset(&sa_rt.sa_mask);
+	sa_rt.sa_sigaction = timer_callback;
+	sa_rt.sa_flags = SA_SIGINFO | SA_RESTART;
+
+	if (sigaction(SIGNO_TIMER, &sa_rt, NULL) == -1) {
+		timer_std_eprintf("sigaction\n");
+		return -1;
+	}
+
+	timer->to_callback = callback;
+	timer->to_data = data;
+	memset(&sigev, 0, sizeof(sigev));
+	sigev.sigev_value.sival_ptr = timer;
+	sigev.sigev_notify = SIGEV_SIGNAL; /* notification with signal */
+	sigev.sigev_signo = SIGNO_TIMER;
+
+	/* create timer */
+	if (timer_create(CLOCK_REALTIME, &sigev, (timer_t *)&timer->to_id) < 0) {
+		timer_std_eprintf("timer_create\n");
+		return -1;
+	}
+
+	timer->to_created = CREATED_MASK;
+	timer_func_out("id=%p", timer->to_id);
+	return 0;
+}
+
+int start_timer(timer_obj_t *timer, int expire_milisec)
+{
+	struct itimerspec rt_itspec;
+	int second, nano_sec;
+	int ret = 0;
+
+	timer_func_in("timer=%p, expire_milisec=%d", timer, expire_milisec);
+
+	if (timer->to_created != CREATED_MASK) {
+		timer_iprintf("The timer was not to_created or deleted.\n");
+		goto out;
+	}
+
+	/* interval timer setting */
+	second = expire_milisec/1000;
+	nano_sec = (expire_milisec%1000)*1000/*us*/*1000/*ns*/;
+	rt_itspec.it_value.tv_sec = second;
+	rt_itspec.it_value.tv_nsec = nano_sec;
+	/*We do not repeat timer.*/
+	rt_itspec.it_interval.tv_sec = 0;
+	rt_itspec.it_interval.tv_nsec = 0;
+
+	if (timer_settime((timer_t)timer->to_id, 0, &rt_itspec, NULL) < 0) {
+		timer_std_eprintf("timer_settime(%p)\n", timer->to_id);
+		timer_delete((timer_t)timer->to_id);
+		ret = -1;
+	}
+out:
+	timer_func_out("ret=%d", ret);
+	return ret;
+}
+
+int del_timer(timer_obj_t *timer)
+{
+	int ret = 0;
+
+	timer_func_in("timer=%p, id=%p", timer, timer->to_id);
+
+	if (timer->to_created != CREATED_MASK) {
+		timer_eprintf("Invalid timer parameter\n");
+		ret = -1;
+	}
+	else if (timer->to_id) {
+		timer->to_created = 0;
+		ret = timer_delete((timer_t) timer->to_id);
+	}
+
+	timer_func_out("ret=%d", ret);
+	return ret;
+}
+#endif
+
diff --git a/sdk/timer.h b/sdk/timer.h
new file mode 100644
index 0000000..4f79437
--- /dev/null
+++ b/sdk/timer.h
@@ -0,0 +1,101 @@
+// 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.
+
+#if !defined(TIMER_H_07282008)
+#define TIMER_H_07282008
+#include <pthread.h>
+#include <sys/time.h>
+
+#define PTHREAD_TIMER
+
+#if defined(PTHREAD_TIMER)
+#include "list.h"
+
+typedef struct timer_obj_s {
+	struct list_head	to_list;
+	unsigned			to_created;
+	pthread_mutex_t		to_lock;
+	struct timespec		to_ts;
+	int					to_active;
+
+	void *to_data;
+	void (*to_callback)(void *data);
+
+	/*debug info*/
+	void *to_caller;	
+} timer_obj_t;
+#else
+typedef struct timer_obj_s {
+	unsigned to_created;
+	void *to_id;
+	void *to_data;
+	void (*to_callback)(void *data);
+	
+} timer_obj_t;
+#endif
+
+static inline const char *get_cur_time(void)
+{
+	static char buf[64];
+	time_t t;
+	struct tm *tm;
+	struct timeval tv;
+
+	time(&t);
+	tm = localtime(&t);
+	gettimeofday(&tv, NULL);
+
+	sprintf(buf, "%02d:%02d:%02d:%03d",
+		tm->tm_hour, tm->tm_min, tm->tm_sec, (int)(tv.tv_usec/1000));
+	return buf;
+}
+
+static inline const char *get_date(time_t *t)
+{
+	static char buf[64];
+	struct tm *tm;
+	
+	tm = localtime(t);
+	sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d",
+		tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+	return buf;
+}
+
+static inline const char *get_cur_date(void)
+{
+	time_t t;
+
+	time(&t);
+	return get_date(&t);
+}
+
+#define time2ms(time_ptr)	(((time_ptr)->tv_sec * 1000) + ((time_ptr)->tv_usec / 1000))
+
+static inline int gettimemsofday(void)
+{
+	struct timeval time;
+
+	gettimeofday(&time, NULL);
+	return time2ms(&time);
+}
+
+#if defined(PTHREAD_TIMER)
+int timer_module_init(void);
+void timer_module_deinit(void);
+#else
+#define timer_module_init()
+#define timer_module_deinit()
+#endif
+
+int init_timer(timer_obj_t *timer, void (*callback)(void *), void *data);
+int start_timer(timer_obj_t *timer, int expire_milisec);
+#if defined(PTHREAD_TIMER)
+int stop_timer(timer_obj_t *timer);
+#else
+#define stop_timer(timer)	start_timer(timer, 0)
+#endif
+int del_timer(timer_obj_t *timer);
+
+#endif
+
diff --git a/sdk/wimax.c b/sdk/wimax.c
new file mode 100644
index 0000000..4919992
--- /dev/null
+++ b/sdk/wimax.c
@@ -0,0 +1,2506 @@
+// 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 "global.h"
+#include "gcttype.h"
+#include "wimax.h"
+#include "nds.h"
+#include "error.h"
+#include "device.h"
+#include "io.h"
+#include "hci.h"
+#include "sdk.h"
+#include "log.h"
+
+
+static void wm_scan_timer_callback(void *data);
+static void wm_clean_subscription(struct wimax_s *wm);
+static int get_neighbor_info(u8 *bsid, u8 *buf, int len,
+	wm_bs_neigh_t *list, int *list_cnt);
+
+static void wm_setup_device(int dev_idx)
+{
+	device_t *dev;
+	int i;
+
+	xfunc_in("dev=%d", dev_idx);
+	if (!(dev = dm_get_dev(dev_idx)))
+		return;
+
+	dev->wimax = (wimax_t *) sdk_malloc(sizeof(wimax_t));
+	memset(dev->wimax, 0, sizeof(wimax_t));
+
+	for (i = 0; i < WM_USING_LOCK_ENTRIES; i++)
+		pthread_mutex_init(&dev->wimax->using_lock[i], NULL);
+	pthread_mutex_init(&dev->wimax->fsm_lock, NULL);
+
+	dm_put_dev(dev_idx);
+	xfunc_out();
+}
+
+void wm_cleanup_device(int dev_idx)
+{
+	device_t *dev;
+	int i;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return;
+	if (dev->wimax) {
+		for (i = 0; i < WM_USING_LOCK_ENTRIES; i++)
+			wm_in_wimax(dev->wimax, i);
+		nds_deinit(dev_idx);
+		wm_clean_subscription(dev->wimax);
+
+		for (i = 0; i < WM_USING_LOCK_ENTRIES; i++)
+			pthread_mutex_destroy(&dev->wimax->using_lock[i]);
+		pthread_mutex_destroy(&dev->wimax->fsm_lock);
+
+		sdk_free(dev->wimax);
+		dev->wimax = NULL;
+	}
+	dm_put_dev(dev_idx);
+	xfunc_out();
+}
+
+void wm_open_device(int dev_idx)
+{
+	xfunc_in("dev=%d", dev_idx);
+
+	wm_setup_device(dev_idx);
+
+	nds_init(dev_idx);
+
+	dm_put_dev(dev_idx);
+	xfunc_out();
+}
+
+int wm_set_scan_type(int dev_idx, wimax_scan_type_t type)
+{
+	device_t *dev;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	dev->wimax->scan.type = type;
+	dm_put_dev(dev_idx);
+	return 0;
+}
+
+static int wm_set_scan_interval(int dev_idx, u32 interval_sec)
+{
+	device_t *dev;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	dev->wimax->scan.scan_interval_sec = interval_sec;
+	dm_put_dev(dev_idx);
+	return 0;
+}
+
+void wm_init_scan(int dev_idx)
+{
+	device_t *dev;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return;
+
+	init_timer(&dev->wimax->scan.timer, wm_scan_timer_callback, (void *)dev_idx);
+
+	wm_set_scan_interval(dev_idx, WM_DEFAULT_SCAN_INTERVAL_SEC);
+	wm_set_scan_type(dev_idx, wm_scan_all_subscriptions);
+
+	dm_put_dev(dev_idx);
+	xfunc_out();
+}
+
+void wm_deinit_scan(int dev_idx)
+{
+	device_t *dev;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return;
+
+	del_timer(&dev->wimax->scan.timer);
+	dm_put_dev(dev_idx);
+	xfunc_out();
+}
+
+void wm_close_device(int dev_idx)
+{
+	xfunc_in("dev=%d", dev_idx);
+
+	wm_cleanup_device(dev_idx);
+	xfunc_out();
+	dm_put_dev(dev_idx);
+}
+
+int wm_update_device_info(int dev_idx, tlv_t *tlv, int nr_tlv)
+{
+	device_t *dev;
+	wimax_t *wm;
+	wm_rev_info_t *revi;
+	u8 buf[HCI_MAX_PACKET];
+	u8 T;
+	u16 L;
+	u8 *V;
+	int ret, i, lmask = SDK_DBG;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	assert(dev->wimax->subs_list.head.prev && dev->wimax->subs_list.head.next);
+	wm = dev->wimax;
+	revi = &dev->wimax->dev_info.revision;
+	
+	ret = hci_req_getinfo(dev_idx, buf, tlv, nr_tlv);
+	if (ret < 0)
+		goto out;
+
+	for (i = 0; i < nr_tlv; i++) {
+		T = tlv[i].T;
+		L = tlv[i].L;
+		V = tlv[i].V;
+		switch (T) {
+			case TLV_T(T_MAX_SUBSCRIPTION):
+				wm->dev_info.max_subs_supported = *V;
+				xprintf(lmask, "T_MAX_SUBSCRIPTION=%d\n", *V);
+				break;
+			case TLV_T(T_MAX_SF):
+				wm->dev_info.max_service_flow_supported = *V;
+				xprintf(lmask, "T_MAX_SF=%d\n", *V);
+				break;
+			case TLV_T(T_PHY_TYPE):
+				wm->dev_info.phy_type = *V;
+				xprintf(lmask, "T_PHY_TYPE=%d\n", *V);
+				break;
+			case TLV_T(T_PKM):
+				wm->dev_info.pkm_support.pkm_support = *V;
+				xprintf(lmask, "T_PKM=%d\n", *V);
+				break;
+			case TLV_T(T_AUTH_POLICY):
+				wm->dev_info.auth_support.auth_policy_support = *V;
+				xprintf(lmask, "T_AUTH_POLICY=%d\n", *V);
+				break;
+			case TLV_T(T_CS_TYPE):
+				wm->dev_info.cs_type_supported.supported_cs = U82U16(V);
+				xprintf(lmask, "T_CS_TYPE=%d\n", U82U16(V));
+				break;
+			case TLV_T(T_VENDOR_NAME):
+				memcpy(&wm->dev_info.vendor_name, V, L);
+				wm->dev_info.vendor_name[L] = 0;
+				xprintf(lmask, "T_VENDOR_NAME=%s\n", &wm->dev_info.vendor_name);
+				break;
+			case TLV_T(T_MOD_NAME):
+				memcpy(&wm->dev_info.model_name, V, L);
+				wm->dev_info.model_name[L] = 0;
+				xprintf(lmask, "T_MOD_NAME=%s\n", &wm->dev_info.model_name);
+				break;
+			case TLV_T(T_SUBSCRIPTION_LIST):
+				xprintf(lmask, "T_SUBSCRIPTION_LIST: L=%d\n", L);
+				ret = wm_update_subscription(dev_idx, V, L);
+				break;
+			case TLV_T(T_MAC_ADDRESS):
+				memcpy(&wm->dev_info.device_mac, V, L);
+				xprintf(lmask, "T_MAC_ADDRESS=%02x:%02x:%02x:%02x:%02x:%02x\n",
+					V[0],V[1],V[2],V[3],V[4],V[5]);
+				break;
+			case TLV_T(T_BOOTLOAD_VER):
+				memcpy(&revi->bl_ver, V, TLV_L(T_BOOTLOAD_VER));
+				xprintf(SDK_INFO, "BL: %d.%d.%d.%d\n", V[0], V[1], V[2], V[3]);
+				break;
+			case TLV_T(T_RELEASE_NUMBER):
+				memcpy(&revi->rel_ver, V, TLV_L(T_RELEASE_NUMBER));
+				xprintf(SDK_INFO, "REL: %d.%d.%d.%d\n", V[0], V[1], V[2], V[3]);
+				break;
+			default:
+				xprintf(SDK_ERR, "Unknown Get-Info type(0x%02x)\n", T);
+				ret = -1;
+				goto out;
+		}
+	}
+
+out:
+	dm_put_dev(dev_idx);
+	xfunc_out();
+	return ret;
+}
+
+static int wm_get_mac_rev_info(int dev_idx)
+{
+	device_t *dev;
+	wm_rev_info_t *revi;
+	u8 buf[HCI_MAX_PACKET];
+	tlv_t tlv[4];
+	u8 T;
+	u16 L;
+	u8 *V;
+	int ret, i, pos = 0, tmp, lmask = SDK_INFO;
+
+	xfunc_in();
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	revi = &dev->wimax->dev_info.revision;
+
+	tlv[pos++].T = TLV_T(T_FW_REVISION);
+	tlv[pos++].T = TLV_T(T_PHY_HW_REVISION);
+	tlv[pos++].T = TLV_T(T_CAPABILITY);
+
+	assert(pos <= numof_array(tlv));
+
+	ret = hci_req_getinfo(dev_idx, buf, tlv, pos);
+
+	if (ret < 0) {
+		if (-ETIMEDOUT == ret) {
+			xprintf(SDK_NOTICE, "MAC GetInfo Timeout\n");	
+			ret = 0;
+			goto out;
+		}
+		
+		xprintf(SDK_ERR, "MAC GetInfo Error\n");
+		goto out;
+	}
+
+	for (i = 0; i < pos; i++) {
+		T = tlv[i].T;
+		L = tlv[i].L;
+		V = tlv[i].V;
+		switch (T) {
+			case TLV_T(T_CAPABILITY):
+				memcpy(&tmp, V, TLV_L(T_CAPABILITY));
+				xprintf(lmask, "T_CAPABILITY=0x%08X\n", DB2H(tmp));
+				break;
+			case TLV_T(T_FW_REVISION):
+				memcpy(&revi->fw_ver, V, TLV_L(T_FW_REVISION));
+				xprintf(lmask, "T_FW_REVISION=0x%08X\n", revi->fw_ver);
+				break;
+			case TLV_T(T_PHY_HW_REVISION):
+				memcpy(&revi->phy_hw_ver, V, TLV_L(T_PHY_HW_REVISION));
+				xprintf(lmask, "T_PHY_HW_REVISION=0x%08X\n", revi->phy_hw_ver);
+				break;
+			default:
+				xprintf(SDK_ERR, "Unknown Get-Info type(0x%02x)\n", T);
+				ret = -1;
+				goto out;
+		}
+	}
+out:
+	xfunc_out("ret=%d", ret);
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+int wm_init_device_info(int dev_idx)
+{
+	tlv_t tlv[16];
+	int ret, pos = 0;
+
+	tlv[pos++].T = TLV_T(T_MAX_SUBSCRIPTION);
+	tlv[pos++].T = TLV_T(T_MAX_SF);
+	tlv[pos++].T = TLV_T(T_PHY_TYPE);
+	tlv[pos++].T = TLV_T(T_PKM);
+	tlv[pos++].T = TLV_T(T_AUTH_POLICY);
+	tlv[pos++].T = TLV_T(T_CS_TYPE);
+	tlv[pos++].T = TLV_T(T_VENDOR_NAME);
+	tlv[pos++].T = TLV_T(T_MOD_NAME);
+	tlv[pos++].T = TLV_T(T_SUBSCRIPTION_LIST);
+	tlv[pos++].T = TLV_T(T_MAC_ADDRESS);
+	tlv[pos++].T = TLV_T(T_BOOTLOAD_VER);
+	tlv[pos++].T = TLV_T(T_RELEASE_NUMBER);
+
+	assert(pos <= numof_array(tlv));
+
+	if ((ret = wm_update_device_info(dev_idx, tlv, pos)) < 0)
+		return -1;
+
+	ret = wm_get_mac_rev_info(dev_idx);
+
+	return ret;
+}
+
+static bool compare_nspid(wm_nsp_identifier_t *s1, wm_nsp_identifier_t *s2)
+{
+	if (!memcmp(s1->id, s2->id, NSP_ID_SIZE)
+		#if 0
+		&& 	!strcasecmp((char *)s1->name, (char *)s2->name)
+		#endif
+	)
+		return TRUE;
+	return FALSE;
+}
+
+static int reset_selected_subsctiption(int dev_idx, wm_nsp_identifier_t *hnspid)
+{
+	device_t *dev;
+	wimax_t *wm;
+	struct list_head *head;
+	wm_subscription_info_t *ss_info;
+	int ret = 0;
+
+	xfunc_in();
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	wm = dev->wimax;
+
+	xprintf(SDK_DBG, "OLD: H-NSP-ID %02X%02X%02X(%s)\n",
+		hnspid->id[0], hnspid->id[1], hnspid->id[2], hnspid->name);
+	/*Look up new subscription.*/
+	pthread_mutex_lock(&wm->subs_list.lock);
+	head = &wm->subs_list.head;
+	wm->scan.selected_subs = NULL;
+	list_for_each_entry(ss_info, head, list) {
+		xprintf(SDK_DBG, "NEW: H-NSP-ID %02X%02X%02X(%s)\n",
+			ss_info->subscription_id.hnspid.id[0],
+			ss_info->subscription_id.hnspid.id[1],
+			ss_info->subscription_id.hnspid.id[2],
+			ss_info->subscription_id.hnspid.name);
+		if (compare_nspid(hnspid, &ss_info->subscription_id.hnspid)) {
+			wm->scan.selected_subs = ss_info;
+			break;
+		}
+	}
+	if (!wm->scan.selected_subs) {
+		wm->scan.selected_subs = list_entry(head->next, wm_subscription_info_t, list);
+		xprintf(SDK_DBG, "First subscription list has been set(%s:%s)\n",
+			wm->scan.selected_subs->subscription_id.user_hnai,
+			wm->scan.selected_subs->subscription_id.hnspid.name);
+	}
+	pthread_mutex_unlock(&wm->subs_list.lock);
+
+	dm_put_dev(dev_idx);
+	xfunc_out("ret=%d", ret);
+	return 0;
+}
+
+int wm_sync_subscription(int dev_idx)
+{
+	device_t *dev;
+	wimax_t *wm;
+	wm_nsp_identifier_t hnspid;
+	tlv_t tlv[1];
+	int ret, pos = 0;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+	wm = dev->wimax;
+
+	if (wm->scan.selected_subs)
+		memcpy(&hnspid, &wm->scan.selected_subs->subscription_id.hnspid, sizeof(hnspid));
+	else
+		memset(&hnspid, 0, sizeof(hnspid));
+
+	tlv[pos++].T = TLV_T(T_SUBSCRIPTION_LIST);
+
+	if (!(ret = wm_update_device_info(dev_idx, tlv, pos)))
+		ret = reset_selected_subsctiption(dev_idx, &hnspid);
+
+	return ret;
+}
+
+int wm_active_scan_interval(int dev_idx, u32 interval_sec)
+{
+	device_t *dev;
+
+	xfunc_in("interval_sec=%d", interval_sec);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	if (interval_sec)
+		start_timer(&dev->wimax->scan.timer, interval_sec*1000);
+	else
+		stop_timer(&dev->wimax->scan.timer);
+
+	wm_set_scan_interval(dev_idx, interval_sec);
+	xfunc_out();
+	dm_put_dev(dev_idx);
+	return 0;
+}
+
+int wm_req_scan(int dev_idx)
+{
+	device_t *dev;
+	wimax_t *wm;
+	wm_subscription_info_t *ss_info;
+	u8 scan_type;
+	u8 *home_nsp_id = NULL, *usr_home_nai = NULL;
+	int ret = 0;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+	wm = dev->wimax;
+
+	xfunc_in("m_s=%d, c_s=%d", dev->fsm.m_status, dev->fsm.c_status);
+
+	if (dev->fsm.m_status != M_OPEN_ON && dev->fsm.m_status != M_SCAN)
+		goto out;
+
+	switch (dev->wimax->scan.type) {
+		case wm_scan_all_channels:
+			scan_type = W_SCAN_ALL_CHANNEL;
+			break;
+		case wm_scan_all_subscriptions:
+			scan_type = W_SCAN_ALL_SUBSCRIPTION;
+			break;
+		case wm_scan_curr_subscription:
+			scan_type = W_SCAN_SPECIFIED_SUBSCRIPTION;
+			if (!(ss_info = dev->wimax->scan.selected_subs)) {
+				xprintf(SDK_DBG, "There is no selected subscription.");
+				ret = -EAGAIN;
+				goto out;
+			}
+			home_nsp_id = ss_info->subscription_id.hnspid.id;
+			usr_home_nai = ss_info->subscription_id.user_hnai;
+			xprintf(SDK_INFO, "[%d] H_NSPID=0x%08X, H_NAI=%s\n",
+				dev_idx, U82U24(home_nsp_id), usr_home_nai);
+			break;
+		default:
+			xprintf(SDK_ERR, "[%d] Unknown scan type(%d)\n",
+				dev_idx, dev->wimax->scan.type);
+			ret = -1;
+			goto out;
+	}
+
+	if ((ret = sdk_set_status(NULL, dev_idx, M_SCAN, C_INIT)) < 0)
+		goto out;
+
+	ret = nds_req_scan(dev_idx, scan_type, home_nsp_id, usr_home_nai);
+	dev->wimax->scan.last_scan_ms = (unsigned int)gettimemsofday();
+out:
+	dm_put_dev(dev_idx);
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int wm_net_search_scan(int dev_idx, wimax_scan_type_t scantype)
+{
+	device_t *dev;
+	wimax_t *wm;
+	wm_scan_t *scan;
+	int m_status, c_status;
+	int ret;
+
+	xfunc_in("scantype=%d", scantype);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+	wm = dev->wimax;
+
+	wm_active_scan_interval(dev_idx, 0);
+
+	ret = wm_set_scan_type(dev_idx, scantype);
+
+	scan = &dev->wimax->scan;
+
+	sdk_get_status(NULL, dev_idx, &m_status, &c_status);
+	switch (m_status) {
+		case M_SCAN:
+			ret = start_timer(&scan->timer, 500);
+			break;
+		case M_OPEN_ON:
+			pthread_mutex_lock(&wm->fsm_lock);
+			ret = wm_req_scan(dev_idx);
+			pthread_mutex_unlock(&wm->fsm_lock);
+			break;
+		default:
+			xprintf(SDK_ERR, "Invalid Connection Status(%d)!\n", m_status);
+			ret = -1;
+	}
+
+	dm_put_dev(dev_idx);
+	xfunc_out();
+	return ret;
+}
+
+int wm_cancel_scan(int dev_idx)
+{
+	int ret;
+
+	if (!sdk_get_rw_handle())
+		return 0;
+
+	ret = hci_send(dev_idx, WIMAX_SCAN_CANCEL, NULL, 0);
+	if (!ret) {
+		xprintf(SDK_STD_ERR, "[%d] hci_send(%d)\n", dev_idx, ret);
+		ret = sdk_set_errno(ERR_STD);
+	}
+	return ret;
+}
+
+void wm_clean_scan_info(int dev_idx)
+{
+	device_t *dev;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return;
+
+	nds_clean_scan_list(dev->wimax);
+	dm_put_dev(dev_idx);
+}
+
+static void wm_scan_timer_callback(void *data)
+{
+	int dev_idx = (int) data;
+	device_t *dev;
+	wm_scan_t *scan;
+	int m_status, c_status;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	scan = &dev->wimax->scan;
+
+	if (dev && dev->inserted && dev->open_cnt) {
+		sdk_get_status(NULL, dev_idx, &m_status, &c_status);
+		if (m_status == M_SCAN) {
+			xprintf(SDK_DBG, "m_status=%d, c_status=%d\n", m_status, c_status);
+			start_timer(&scan->timer, 500);
+			goto out;
+		}
+		if (m_status == M_OPEN_ON && wm_req_scan(dev_idx) == -EAGAIN) {
+			xprintf(SDK_DBG, "wm_req_scan EAGAIN %d sec.\n", scan->scan_interval_sec);
+			wm_req_interval_scan(dev_idx, scan->scan_interval_sec*1000);
+		}
+	}
+out:
+	xfunc_out();
+	dm_put_dev(dev_idx);
+}
+
+int wm_req_interval_scan(int dev_idx, int interval_milisec)
+{
+	device_t *dev;
+	wm_scan_t *scan;
+	int elapsed_ms, interval_sec;
+	int ret = 0;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	xfunc_in("dev=%d, ms=%d", dev_idx, interval_milisec);
+	if (dev->a_status == AM_Close) {
+		xprintf(SDK_DBG, "SDK is in closing\n");
+		goto out;
+	}
+	
+	scan = &dev->wimax->scan;
+	interval_sec = scan->scan_interval_sec;
+
+	if (interval_sec == 0) {
+		xprintf(SDK_DBG, "interval_ms is 0\n");
+		goto out;
+	}
+
+	if (interval_milisec > 0) {
+		ret = start_timer(&scan->timer, interval_milisec);
+		goto out;
+	}
+
+	interval_milisec = interval_sec*1000;
+
+	elapsed_ms = (unsigned int)gettimemsofday() - scan->last_scan_ms;
+	if (elapsed_ms < interval_milisec)
+		ret = start_timer(&scan->timer, interval_milisec-elapsed_ms);
+	else
+		ret = wm_req_scan(dev_idx);
+out:
+	xfunc_out("ret=%d", ret);
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+void wm_clean_subscription(struct wimax_s *wm)
+{
+	wm_subscription_info_t *ss_info, *tmp;
+	struct list_head *head = &wm->subs_list.head;
+	nsp_list_data_t *nsp_data, *tmp2;
+	nap_list_data_t *nap_data, *tmp3;
+
+	pthread_mutex_lock(&wm->subs_list.lock);
+	list_for_each_entry_safe(ss_info, tmp, head, list) {
+		xprintf(SDK_DBG, "Clean user_hnai=%s\n", 
+			ss_info->subscription_id.user_hnai);
+		list_for_each_entry_safe(nsp_data, tmp2, &ss_info->nsp_data_head, list) {
+			list_del(&nsp_data->list);
+			sdk_free(nsp_data);
+		}
+		INIT_LIST_HEAD(&ss_info->nap_data_head);
+
+		list_for_each_entry_safe(nap_data, tmp3, &ss_info->nap_data_head, list) {
+			list_del(&nap_data->list);
+			sdk_free(nap_data);
+		}
+		INIT_LIST_HEAD(&ss_info->nap_data_head);
+
+		list_del(&ss_info->list);
+			sdk_free(ss_info);
+	}
+	INIT_LIST2(&wm->subs_list);
+	pthread_mutex_unlock(&wm->subs_list.lock);
+}
+
+int wm_update_subscription(int dev_idx, u8 *buf, int len)
+{
+	device_t *dev;
+	struct wimax_s *wm;
+	wm_subscription_info_t *ss_info;
+	u8 subs_idx = 1;
+	struct list_head *head;
+	nsp_list_data_t *nsp_data;
+	nap_list_data_t *nap_data;
+	u8 T, diff_T, *V;
+	u16 L;
+	u16 flag;
+	int pos = 0, getn, ret = 0;
+	int lmask = SDK_INFO;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	wm = dev->wimax;
+	head = &wm->subs_list.head;
+
+	assert(head->prev && head->next);
+
+	xfunc_in("dev=%d, len=%d", dev_idx, len);
+	
+	wm_clean_subscription(wm);
+
+	pthread_mutex_lock(&wm->subs_list.lock);
+	
+	while (pos < len) {
+		ss_info = (wm_subscription_info_t *) sdk_malloc(sizeof(wm_subscription_info_t));
+		ss_info->idx = subs_idx++;
+
+		pos += hci_get_tlv(&buf[pos], &T, &L, &V);
+		if (T != (diff_T=TLV_T(T_H_NSPID))) goto diff_type;
+		memcpy(&ss_info->subscription_id.hnspid.id, V, TLV_L(T_H_NSPID));
+		xprintf(lmask, "T_H_NSPID=0x%08X\n", U82U24(V));
+
+		pos += hci_get_tlv(&buf[pos], &T, &L, &V);
+		if (T != (diff_T=TLV_T(T_NSP_NAME))) goto diff_type;
+		memcpy(ss_info->subscription_id.hnspid.name, V, L);
+		ss_info->subscription_id.hnspid.name[L] = 0;
+		xprintf(lmask, "Operator Name=%s\n", ss_info->subscription_id.hnspid.name);
+
+		pos += hci_get_tlv(&buf[pos], &T, &L, &V);
+		if (T != (diff_T=TLV_T(T_SUBSCRIPTION_NAME))) goto diff_type;
+		memcpy(&ss_info->subscription_id.user_hnai, V, L);
+		ss_info->subscription_id.user_hnai[L] = 0;
+		xprintf(lmask, "Subscription Name=%s\n", ss_info->subscription_id.user_hnai);
+
+		xprintf(SDK_INFO, "[%d] H_NSPID=0x%08X, H_NSPNAME=%s, H_NAI=%s\n",
+			dev_idx, 
+			U82U24(ss_info->subscription_id.hnspid.id),
+			&ss_info->subscription_id.hnspid.name,
+			&ss_info->subscription_id.user_hnai);
+
+		pos += hci_get_tlv(&buf[pos], &T, &L, &V);
+		if (T != (diff_T=TLV_T(T_SUBSCRIPTION_FLAG))) goto diff_type;
+		memcpy(&flag, V, TLV_L(T_SUBSCRIPTION_FLAG));
+		flag = B2H(flag);
+		if (flag & 0x0001 )
+			ss_info->auto_selection = TRUE;
+		if (flag & 0x0002 )
+			ss_info->auto_selection_configurable = TRUE;
+		if (flag & 0x0004 )
+			ss_info->auto_connect_at_home = TRUE;
+		if (flag & 0x0008 )
+			ss_info->auto_connect_when_roam = TRUE;
+		if (flag & 0x0010 )
+			ss_info->subs_locked = TRUE;
+		if (flag & 0x0020 )
+			ss_info->activated = TRUE;
+
+		INIT_LIST_HEAD(&ss_info->nsp_data_head);
+		do {
+			getn = hci_get_tlv(&buf[pos], &T, &L, &V);
+			if (T != TLV_T(T_V_NSPID))
+				break;
+			pos += getn;
+			nsp_data = (nsp_list_data_t *) sdk_malloc(sizeof(nsp_list_data_t));
+			memcpy(&nsp_data->NspIdentifier.id, V, TLV_L(T_V_NSPID));
+			xprintf(lmask, "T_V_NSPID=0x%08X\n", U82U24(V));
+
+			pos += hci_get_tlv(&buf[pos], &T, &L, &V);
+			if (T != (diff_T=TLV_T(T_NSP_NAME))) goto diff_type;
+			memcpy(&nsp_data->NspIdentifier.name, V, L);
+			nsp_data->NspIdentifier.name[L] = 0;
+			xprintf(SDK_INFO, "name=%s\n", &nsp_data->NspIdentifier.name);
+
+			list_add_tail(&nsp_data->list, &ss_info->nsp_data_head);
+		} while(pos < len);
+
+		INIT_LIST_HEAD(&ss_info->nap_data_head);
+		do {
+			getn = hci_get_tlv(&buf[pos], &T, &L, &V);
+			if (T != TLV_T(T_NAP_ID))
+				break;
+			pos += getn;
+			nap_data = (nap_list_data_t *) sdk_malloc(sizeof(nap_list_data_t));
+			memcpy(&nap_data->nap_id.id, V, TLV_L(T_NAP_ID));
+			xprintf(lmask, "T_NAP_ID=0x%08X\n", U82U24(V));
+
+			list_add_tail(&nap_data->list, &ss_info->nap_data_head);
+		} while(pos < len);
+
+		list_add_tail(&ss_info->list, head);
+		wm->subs_list.cnt++;
+	}
+
+	pthread_mutex_unlock(&wm->subs_list.lock);
+	
+	xfunc_out();
+	dm_put_dev(dev_idx);
+	return ret;
+
+diff_type:
+	pthread_mutex_unlock(&wm->subs_list.lock);
+	xprintf(SDK_ERR, "[%d] Diff type(0x%02X != 0x%02X\n", dev_idx, T, diff_T);
+	dm_put_dev(dev_idx);
+	return -1;
+}
+
+wm_subscription_info_t *wm_get_subscription(int dev_idx, u8 subs_idx, u8 *hnspid)
+{
+	device_t *dev;
+	wimax_t *wm;
+	struct list_head *head;
+	wm_subscription_info_t *ss_info, *ret_d_ss_info = NULL;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return NULL;
+
+	wm = dev->wimax;
+	head = &wm->subs_list.head;
+
+	xfunc_in("H_NSP_ID=0x%08X", U82U24(hnspid));
+
+	pthread_mutex_lock(&wm->subs_list.lock);
+	list_for_each_entry(ss_info, head, list) {
+		if (subs_idx && ss_info->idx != subs_idx)
+			continue;
+		if (!memcmp(ss_info->subscription_id.hnspid.id, hnspid, NSP_ID_SIZE)) {
+			ret_d_ss_info = ss_info;
+			break;
+		}
+	}
+	pthread_mutex_unlock(&wm->subs_list.lock);
+
+	if (ret_d_ss_info == NULL) {
+		xprintf(SDK_ERR, "[%d] H_NSP_ID(0x%08X) is not found\n", dev_idx, U82U24(hnspid));
+		sdk_set_errno(ERR_NO_NSPID);
+	}
+	xfunc_out();
+	dm_put_dev(dev_idx);
+	return ret_d_ss_info;
+}
+
+wm_subscription_info_t *wm_get_activated_subs(int dev_idx)
+{
+	device_t *dev;
+	wimax_t *wm;
+	struct list_head *head;
+	wm_subscription_info_t *ss_info, *ret_d_ss_info = NULL;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return NULL;
+	xfunc_in();
+
+	wm = dev->wimax;
+	head = &wm->subs_list.head;
+
+	pthread_mutex_lock(&wm->subs_list.lock);
+	list_for_each_entry(ss_info, head, list) {
+		if (ss_info->activated) {
+			ret_d_ss_info = ss_info;
+			break;
+		}
+	}
+	pthread_mutex_unlock(&wm->subs_list.lock);
+
+	xfunc_out();
+	dm_put_dev(dev_idx);
+	return ret_d_ss_info;
+}
+
+int wm_combine_level(int dev_idx, int c0, int c1)
+{
+	device_t *dev;
+	u32 fw_mac_ver;
+	int max, diff, offset;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+	fw_mac_ver = DB2H(dev->wimax->dev_info.revision.fw_ver);
+
+	if (c0 > c1) {
+		max = c0;
+		diff = c0 - c1;
+	}
+	else {
+		max = c1;
+		diff = c1 - c0;
+	}
+
+	if (fw_mac_ver < 0x01090104/*1.9.1.4*/) {
+		/*floor*/
+		if (diff >= 6) offset = 0;
+		else if (diff >= 3)  offset = 1;
+		else if (diff >= 1)  offset = 2;
+		else     offset = 3; 
+	}
+	else {
+		/*round*/
+		if (diff >= 10) offset = 0;
+		else if (diff >= 4)  offset = 1;
+		else if (diff >= 2)  offset = 2;
+		else     offset = 3; 
+	}
+
+	max += offset;
+	dm_put_dev(dev_idx);
+	return max;
+}
+
+u8 wm_convert_txpower(int txpower)
+{
+	u8 ret_txpower;
+	
+	if (txpower <= -168)
+		ret_txpower = 0x00;
+#if 0
+	else if (txpower >= 87)
+		ret_txpower = 0xff;
+#endif
+	else
+		ret_txpower = (u8)(txpower+168);
+	
+	return ret_txpower;
+}
+
+u8 wm_convert_cinr(s8 cinr)
+{
+	u8 ret_cinr = 0;
+
+	if (cinr <= -10)
+		ret_cinr = 0x00;
+#if 0
+	else if (cinr >= 53)
+		ret_cinr = 0x3F;
+#endif
+	else
+		ret_cinr = (char)(cinr+10);
+
+	return ret_cinr;
+}
+
+u8 wm_convert_rssi(s8 rssi)
+{
+	u8 ret_rssi = 0;
+
+	if (rssi <= -123)
+		ret_rssi = 0x00;
+#if 0
+	else if (rssi >= -40)
+		ret_rssi = 0x53;
+#endif
+	else
+		ret_rssi = (char)(123+rssi);
+
+	return ret_rssi;
+}
+
+int wm_get_network_type(struct wimax_s *wm, u8 *nspid)
+{
+	struct list_head *head = &wm->subs_list.head;
+	wm_subscription_info_t *ss_info;
+	nsp_list_data_t *nsp_data;
+	nap_list_data_t *nap_data;
+	int net_type = WIMAX_API_UNKNOWN;
+
+	xfunc_in("NSPID=0x%02X%02X%02X", nspid[0], nspid[1], nspid[2]);
+
+	pthread_mutex_lock(&wm->subs_list.lock);
+	list_for_each_entry(ss_info, head, list) {
+		if (!memcmp(ss_info->subscription_id.hnspid.id, nspid, NSP_ID_SIZE)) {
+			net_type = WIMAX_API_HOME;
+			goto out;
+		}
+
+		list_for_each_entry(nsp_data, &ss_info->nsp_data_head, list) {
+			if (!memcmp(nsp_data->NspIdentifier.id, nspid, NSP_ID_SIZE)) {
+				net_type = WIMAX_API_ROAMING_PARTNER;
+				goto out;
+			}
+		}
+
+		list_for_each_entry(nap_data, &ss_info->nap_data_head, list) {
+			if (!memcmp(nap_data->nap_id.id, nspid, NAP_ID_SIZE)) {
+				net_type = WIMAX_API_PARTNER;
+				goto out;
+			}
+		}
+	}
+out:
+	pthread_mutex_unlock(&wm->subs_list.lock);
+	xfunc_out();
+	return net_type;
+}
+
+struct wm_nsp_s *wm_lookup_nsp_by_name(struct wimax_s *wm, u8 *nsp_name)
+{
+	struct list_head *head = &wm->scan_list.head;
+	wm_nsp_t *nsp, *rnsp = NULL;
+
+	pthread_mutex_lock(&wm->scan_list.lock);
+	list_for_each_entry(nsp, head, list) {
+		if (!strcmp((char *)nsp->name, (char *)nsp_name))
+			rnsp = nsp;
+	}
+	pthread_mutex_unlock(&wm->scan_list.lock);
+	return rnsp;
+}
+
+struct wm_nsp_s *wm_lookup_nsp_by_id(struct wimax_s *wm, u8 *nspid)
+{
+	struct list_head *head = &wm->scan_list.head;
+	wm_nsp_t *nsp, *rnsp = NULL;
+
+	pthread_mutex_lock(&wm->scan_list.lock);
+	list_for_each_entry(nsp, head, list) {
+		if (nsp->id == U82U24(nspid))
+			rnsp = nsp;
+	}
+	pthread_mutex_unlock(&wm->scan_list.lock);
+	return rnsp;
+}
+
+int wm_connect_network(int dev_idx, u8 *hnspid, u8 *vnspid)
+{
+	device_t *dev;
+	wimax_t *wm;
+	u8 param[HCI_MAX_PARAM];
+	u8 *usr_hnai = NULL;
+	int usr_hnai_len = 0;
+	int len = 0, ret = 0;
+	int lmask = SDK_DBG;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	wm = dev->wimax;
+	if (wm->scan.selected_subs) {
+		usr_hnai = wm->scan.selected_subs->subscription_id.user_hnai;
+		usr_hnai_len = strlen((char *)usr_hnai) + 1/*null*/;
+	}
+
+	stop_timer(&wm->scan.timer);
+
+	xprintf(lmask, "H_NSPID=0x%06X, V_NSPID=0x%06X\n", U82U24(hnspid), U82U24(vnspid));
+	len += hci_set_tlv(&param[len], TLV_T(T_H_NSPID), TLV_L(T_H_NSPID), hnspid);
+	len += hci_set_tlv(&param[len], TLV_T(T_V_NSPID), TLV_L(T_V_NSPID), vnspid);
+	if (E_EAP_TLS_ENABLED(dev) && usr_hnai) {
+		len += hci_set_tlv(&param[len], TLV_T(T_SUBSCRIPTION_NAME), usr_hnai_len, usr_hnai);
+		xprintf(lmask, "SUBSCRIPTION_NAME=%s\n", usr_hnai);
+	}
+
+	pthread_mutex_lock(&wm->fsm_lock);
+	if ((ret = sdk_set_status(NULL, dev_idx, M_CONNECTING, C_CONNSTART)) < 0) {
+		pthread_mutex_unlock(&wm->fsm_lock);
+		goto out;
+	}
+
+	wm->conn.hnspid = U82U24(hnspid);
+	wm->conn.vnspid = U82U24(vnspid);
+	if ((ret = hci_send(dev_idx, WIMAX_CONNECT, param, len)) == len)
+		ret = 0;
+	else {
+		sdk_set_status(NULL, dev_idx, M_OPEN_ON, C_INIT);
+		ret = -1;
+	}
+	pthread_mutex_unlock(&wm->fsm_lock);
+out:
+	xfunc_out("ret=%d", ret);
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+int wm_re_connect_network(int dev_idx)
+{
+	device_t *dev;
+	wimax_t *wm;
+	u8 *selected_hnsp_id;
+	u8 *selected_vnsp_id;
+	int ret = -1;
+
+	xfunc_in();
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	wm = dev->wimax;
+
+	if (wm->scan.selected_subs) {
+		selected_hnsp_id = wm->scan.selected_subs->subscription_id.hnspid.id;
+		selected_vnsp_id = wm->asso_start.net_id.nsp.id;
+
+		ret = wm_connect_network(dev_idx, selected_hnsp_id, selected_vnsp_id);
+	}
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int wm_cr801_re_connect(int dev_idx)
+{
+	device_t *dev;
+	wimax_t *wm;
+	u8 type = 0;
+	int ret = 0;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	wm = dev->wimax;
+
+	if (!wm->dev_info.eapp.cr801_server_reject_cnt || 
+		wm->dev_info.eapp.cr801_server_reject_cnt > CR801_SERVER_REJECT_LIMIT)
+		goto out;
+
+	xprintf(SDK_DBG, "cr801_server_reject_cnt=%d\n",
+		wm->dev_info.eapp.cr801_server_reject_cnt);
+
+	type = wm->dev_info.eapp.type;
+	if (wm->dev_info.eapp.cr801_server_reject_cnt == CR801_SERVER_REJECT_LIMIT) {
+		wm->dev_info.eapp.cr801_mode = CR801_TLS;
+		wm->dev_info.eapp.type = W_EAP_TLS;
+		wm_set_eap(dev_idx, TRUE);
+	}
+
+	ret = wm_re_connect_network(dev_idx);
+	wm->dev_info.eapp.type = type;
+out:
+	dm_put_dev(dev_idx);
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int wm_get_dhcp_info(int dev_idx)
+{
+	device_t *dev;
+	wimax_t *wm;
+	int ret = 0;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	wm = dev->wimax;
+	
+	ret = net_get_dhcp_info(dev_idx, &wm->dev_info.dhcp_info);
+	dm_put_dev(dev_idx);
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int wm_disconnect_network(int dev_idx, int timeout_sec)
+{
+	int ret;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (timeout_sec) {
+		ret = hci_send_wait(dev_idx, WIMAX_NET_DISCONN, NULL, 0,
+			WIMAX_DISCONN_IND, NULL, 0, 0, HCI_INDICATION, timeout_sec);
+		if (ret > 0) ret = 0;
+	}
+	else
+		ret = hci_send(dev_idx, WIMAX_NET_DISCONN, NULL, 0);
+	
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int wm_get_rf_state(int dev_idx, rf_stat_t *rf_stat)
+{
+	u8 buf[HCI_MAX_PACKET];
+	tlv_t tlv;
+	int ret;
+
+	tlv.T = TLV_T(T_RADIO_STATE);
+	ret = hci_req_getinfo(dev_idx, buf, &tlv, 1);
+	if (!ret)
+		*rf_stat = *tlv.V;
+	
+	xprintf(SDK_DBG, "ret=%d, rf_stat=%d\n", ret, !ret ? *tlv.V : -1);
+	return ret;
+}
+
+int wm_set_rf_state(int dev_idx, rf_stat_t rf_stat, int timeout_sec)
+{
+	device_t *dev;
+	u16 cmd;
+	int ret;
+
+	xfunc_in("dev=%d, %s", dev_idx, rf_stat==rf_on ? "On" : "Off");
+	
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	if (rf_stat == rf_on)
+		cmd = WIMAX_RADIO_ON;
+	else {
+		cmd = WIMAX_RADIO_OFF;
+		wm_set_scan_interval(dev_idx, WM_DEFAULT_SCAN_INTERVAL_SEC);
+		wm_set_scan_type(dev_idx, wm_scan_all_subscriptions);
+	}
+
+	cmd = rf_stat==rf_on ? WIMAX_RADIO_ON : WIMAX_RADIO_OFF;
+
+	if (timeout_sec) {
+		ret = hci_send_wait(dev_idx, cmd, NULL, 0,
+			WIMAX_RADIO_STATE_IND, NULL, 0, 0, HCI_INDICATION, timeout_sec);
+		if (ret > 0) ret = 0;
+	}
+	else
+		ret = hci_send(dev_idx, cmd, NULL, 0);
+
+	xfunc_out("ret=%d", ret);
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+int wm_set_capability(int dev_idx, u32 capability)
+{
+	device_t *dev;
+	hci_set_arm_capability_t cap = {0};
+	u32 fw_cap = 0;
+	int ret = 0, len = sizeof(cap);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (capability == DEFAULT_CAPABILITY) {
+		cap.capability = W_CAPABILITY_ENC_XML;
+		if (SDK_USE_EEAP) {
+			cap.capability |= W_CAPABILITY_E_EAP_TLS;
+			cap.capability |= W_CAPABILITY_E_EAP_AKA;
+		}
+		cap.capability |= W_CAPABILITY_CAPL_INFO;
+	}
+	else
+		cap.capability = capability;
+
+	cap.capability = DH2B(cap.capability);
+	ret = hci_send_wait(dev_idx, WIMAX_ARM_CAPABILITY, (u8 *)&cap, len,
+		WIMAX_ARM_CAPABILITY_RESULT, &fw_cap, sizeof(fw_cap), 0, 0, 5);
+	if (len == ret)
+		ret = wm_report_capability(dev_idx, (u8 *)&fw_cap, sizeof(fw_cap));
+	else {
+		if (ret == - ETIMEDOUT) {
+			xprintf(SDK_NOTICE, "ARM Capability HCI is not supported!!\n");
+			ret = 0;
+		}
+		else {
+			xprintf(SDK_STD_ERR, "[%d] hci_send(%d!=%d)\n", dev_idx, len, ret);
+			ret = -1;
+		}
+	}
+	
+	xfunc_out("ret=%d", ret);
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+int wm_report_capability(int dev_idx, u8 *buf, int len)
+{
+	device_t *dev;
+	int ret = 0;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	memcpy(&dev->capability, buf, sizeof(dev->capability));
+	dev->capability = DB2H(dev->capability);
+	xprintf(SDK_INFO, "ARM Capability=0x%08x\n", dev->capability);
+	
+	dm_put_dev(dev_idx);
+	xfunc_out();
+	return ret;
+}
+
+int wm_set_eap(int dev_idx, bool enable)
+{
+	device_t *dev;
+	wm_eap_param_t *eapp;
+	u8 buf[HCI_MAX_PARAM];
+	u8 *pos = buf;
+	u8 enable_auth;
+	time_t t;
+	u8 eap_param = V_PARAM_NV;
+	u8 T, *V;
+	u16 L;
+	int len, ret = 0, lmask = SDK_DBG;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	eapp = &dev->wimax->dev_info.eapp;
+
+	xfunc_in("type=%d, %s", eapp->type, enable ? "On":"Off");
+
+	if (enable) {
+		if (IS_EAP_TLS(eapp->type)) {
+			if (!SDK_USE_EEAP) {
+				if (!E_EAP_TLS_ENABLED(dev))
+					xprintf(SDK_ERR, "Embedded EAP TLS were disabled by CM whereas FW supports it!\n");
+				else
+					xprintf(SDK_ERR, "Both of Host/Embedded EAP TLS were disabled!\n");
+				ret = -1;
+				goto out;
+			}
+			else if (!E_EAP_TLS_ENABLED(dev)) {
+				xprintf(SDK_ERR, "Embedded EAP TLS is NOT supported!\n");
+				ret = -1;
+				goto out;
+			}
+		}
+		if (eapp->type == W_EAP_AKA && SDK_USE_EEAP && !E_EAP_AKA_ENABLED(dev)) {
+			xprintf(SDK_ERR, "Embedded EAP AKA is NOT supported!\n");
+			ret = -1;
+			goto out;
+		}
+		enable_auth = 1;
+	}
+	else
+		enable_auth = 0;
+
+	T = TLV_T(T_ENABLE_AUTH);
+	L = TLV_L(T_ENABLE_AUTH);
+	V = &enable_auth;
+	pos += hci_set_tlv(pos, T, L, V);
+
+	if (E_EAP_TLS_ENABLED(dev)) {
+		time(&t);
+		xprintf(lmask, "RTC=0x%08x\n", t);
+		t = DH2B(t);
+		T = TLV_T(T_RTC_TIME);
+		L = TLV_L(T_RTC_TIME);
+		V = (u8 *) &t;
+		pos += hci_set_tlv(pos, T, L, V);
+	}
+			
+	len = pos - buf;
+	assert(len < HCI_MAX_PARAM);
+	ret = hci_send(dev_idx, WIMAX_SET_INFO, buf, len);
+	if (len == ret)
+		ret = 0;
+	else {
+		xprintf(SDK_STD_ERR, "[%d] hci_send(%d!=%d)\n", dev_idx, len, ret);
+		ret = -1;
+	}
+	
+	if (enable && E_EAP_TLS_ENABLED(dev) && IS_EAP_TLS(eapp->type)) {
+		hci_set_eap_info_t *sei = (hci_set_eap_info_t *) buf;
+
+		sei->type = eapp->type;
+		sei->frag_size = H2B(eapp->frag_size);
+		sei->use_delimiter = eapp->use_delimiter;
+		pos = sei->tlv;
+
+		T = TLV_T(T_DEV_CERT_NULL);
+		L = TLV_L(T_DEV_CERT_NULL);
+		V = (u8 *) &eapp->dev_cert_null;
+		pos += hci_set_tlv(pos, T, L, V);
+
+		T = TLV_T(T_CA_CERT_NULL);
+		L = TLV_L(T_CA_CERT_NULL);
+		V = (u8 *) &eapp->ca_cert_null;
+		pos += hci_set_tlv(pos, T, L, V);
+
+		if (eapp->cr801_enabled) {
+			T = TLV_T(T_CR801_MODE);
+			L = TLV_L(T_CR801_MODE);
+			V = (u8 *) &eapp->cr801_mode;
+			pos += hci_set_tlv(pos, T, L, V);
+		}
+
+		if (!eapp->use_nv_info) {
+			if (strlen(eapp->userid)) {
+				if (eap_param == V_PARAM_XML)
+					T = T_EAP_FORCE(TLV_T(T_USER_ID));
+				else {
+					T = TLV_T(T_USER_ID);
+					eap_param = V_PARAM_USER;
+				}
+				L = strlen(eapp->userid) + 1/*null*/;
+				V = (u8 *) eapp->userid;
+				pos += hci_set_tlv(pos, T, L, V);
+				xprintf(lmask, "userid=%s\n", eapp->userid);
+			}
+			if (strlen(eapp->userid_pwd)) {
+				if (eap_param == V_PARAM_XML)
+					T = T_EAP_FORCE(TLV_T(T_USER_PASSWD));
+				else {
+					T = TLV_T(T_USER_PASSWD);
+					eap_param = V_PARAM_USER;
+				}
+				L = strlen(eapp->userid_pwd) + 1/*null*/;
+				V = (u8 *) eapp->userid_pwd;
+				pos += hci_set_tlv(pos, T, L, V);
+				xprintf(lmask, "userid_pwd=%s\n", eapp->userid_pwd);
+			}
+			if (strlen(eapp->anony_id)) {
+				if (eap_param == V_PARAM_XML)
+					T = T_EAP_FORCE(TLV_T(T_ANONYMOUS_ID));
+				else {
+					T = TLV_T(T_ANONYMOUS_ID);
+					eap_param = V_PARAM_USER;
+				}
+				L = strlen(eapp->anony_id) + 1/*null*/;
+				V = (u8 *) eapp->anony_id;
+				pos += hci_set_tlv(pos, T, L, V);
+				xprintf(lmask, "anony_id=%s\n", eapp->anony_id);
+			}
+			if (strlen(eapp->pri_key_pwd)) {
+				if (eap_param == V_PARAM_XML)
+					T = T_EAP_FORCE(TLV_T(T_PRIV_KEY_PASSWD));
+				else {
+					T = TLV_T(T_PRIV_KEY_PASSWD);
+					eap_param = V_PARAM_USER;
+				}
+				L = strlen(eapp->pri_key_pwd) + 1/*null*/;
+				V = (u8 *) eapp->pri_key_pwd;
+				pos += hci_set_tlv(pos, T, L, V);
+				xprintf(lmask, "pri_key_pwd=%s\n", eapp->pri_key_pwd);
+			}
+		}
+		
+		T = TLV_T(T_EAP_PARAM);
+		L = TLV_L(T_EAP_PARAM);
+		V = &eap_param;
+		pos += hci_set_tlv(pos, T, L, V);
+		xprintf(lmask, "eap_param=%d\n", eap_param);
+
+		T = TLV_T(T_EAP_DEBUG_ON);
+		L = TLV_L(T_EAP_DEBUG_ON);
+		V = (u8 *) &eapp->log_enabled;
+		pos += hci_set_tlv(pos, T, L, V);
+		xprintf(lmask, "eap_debug=%d\n", eapp->log_enabled);
+
+		T = TLV_T(T_EAP_RESUMPTION_OFF);
+		L = TLV_L(T_EAP_RESUMPTION_OFF);
+		V = (u8 *) &eapp->disable_resumptoin;
+		pos += hci_set_tlv(pos, T, L, V);
+		xprintf(lmask, "disable_resumptoin=%d\n", eapp->disable_resumptoin);
+
+		T = TLV_T(T_EAP_SESSIONTICKET_OFF);
+		L = TLV_L(T_EAP_SESSIONTICKET_OFF);
+		V = (u8 *) &eapp->disable_sessionticket;
+		pos += hci_set_tlv(pos, T, L, V);
+		xprintf(lmask, "disable_sessionticket=%d\n", eapp->disable_sessionticket);
+
+		if ((L = strlen(eapp->decoration[DECORATION_IDX1])) != 0) {
+			T = TLV_T(T_EAP_DECORATION);
+			V = (u8 *) eapp->decoration[DECORATION_IDX1];
+			pos += hci_set_tlv(pos, T, L, V);
+			xprintf(lmask, "decoration=%d\n", eapp->decoration[DECORATION_IDX1]);
+		}
+
+		#if 0
+		{
+			u32 rand_seed = 0x12345678;
+			rand_seed = DH2B(rand_seed);
+			T = TLV_T(T_EAP_RAND_SEED);
+			L = TLV_L(T_EAP_RAND_SEED);
+			V = (u8 *) &rand_seed;
+			pos += hci_set_tlv(pos, T, L, V);
+			xprintf(lmask, "Set random seed: 0x%08x\n", DH2B(rand_seed));
+		}
+		#endif
+	
+		len = pos - buf;
+		assert(len < HCI_MAX_PARAM);
+		if (eapp->cr801_enabled &&  eapp->cr801_mode == CR801_TLS)
+			ret = hci_send(dev_idx, WIMAX_SET_EAP_INFO, buf, len);
+		else {
+			ret = hci_send_wait(dev_idx, WIMAX_SET_EAP_INFO, buf, len,
+				WIMAX_SET_EAP_INFO_RESULT, buf, sizeof(buf), 0, 0, 3);
+			if (ret > 0) {
+				hci_set_eap_info_result_t *seir = (hci_set_eap_info_result_t *) buf;
+				ret = DB2H(seir->code);
+				if (ret)
+					xprintf(SDK_STD_ERR, "[%d] Set-EAP-Info-Result=%d\n", dev_idx, ret);
+			}
+			else {
+				xprintf(SDK_STD_ERR, "[%d] hci_send_wait(%d!=%d)\n", dev_idx, len, ret);
+				ret = -1;
+			}
+		}
+	}
+out:
+	xfunc_out("ret=%d", ret);
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+int wm_get_linkinfo(int dev_idx, struct wm_link_status_s *link_s)
+{
+	u8 buf[HCI_MAX_PACKET];
+	tlv_t tlv[4];
+	int pos = 0, ret;
+	int lmask = SDK_INFO;
+	
+	xfunc_in("dev=%d", dev_idx);
+
+	tlv[pos++].T = TLV_T(T_RSSI);
+	tlv[pos++].T = TLV_T(T_CINR);
+	tlv[pos++].T = TLV_T(T_TX_POWER);
+	tlv[pos++].T = TLV_T(T_CUR_FREQ);
+	
+	ret = hci_req_getinfo(dev_idx, buf, tlv, pos);
+	if (!ret) {
+		pos = 0;
+		link_s->rssi = wm_convert_rssi(*tlv[pos].V);
+		xprintf(lmask, "[%d] T_RSSI=%d\n", dev_idx, *tlv[pos].V);
+		pos++;
+		link_s->cinr = wm_convert_cinr(*tlv[pos].V);
+		xprintf(lmask, ", T_CINR=%d\n", *tlv[pos].V);
+		pos++;
+		link_s->tx_power = wm_convert_txpower(*tlv[pos].V);
+		xprintf(lmask, ", T_TX_POWER=%d\n", *tlv[pos].V);
+		pos++;
+		link_s->cur_freq = U82U32(tlv[pos].V);
+		xprintf(lmask, ", T_CUR_FREQ=%d\n", link_s->cur_freq);
+	}
+	
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int wm_get_netinfo(int dev_idx, struct wm_net_info_s *net_info)
+{
+	device_t *dev;
+	FILE *fp;
+	char *dev_file = "/proc/net/dev";
+	char buf[512], *p_srch;
+	int ret = -1, lmask = SDK_INFO;
+	u32 rx_bytes, rx_packets, rx_errs, rx_drop, rx_fifo, rx_frame,
+		rx_compressed, rx_multicast, tx_bytes, tx_packets;
+		/*tx_errs, tx_drop, tx_fifo, tx_colls, tx_carrier, tx_compressed*/
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	xfunc_in();
+	fp = fopen(dev_file, "rt");
+	if (fp == NULL) {
+		xprintf(SDK_STD_ERR, "[%d] %s fopen NULL\n", dev_idx, dev_file);
+		ret = sdk_set_errno(ERR_STD);
+		goto out;
+	}
+
+	while (fgets(buf, sizeof(buf), fp)) {
+		if ((p_srch = strstr(buf, dev->name))) {
+			p_srch += strlen(dev->name) + 1/*':'*/;
+			#if 0
+			sscanf(p_srch, "%lu %lu %*lu %*lu %*lu %*lu %*lu %*lu %lu %lu",
+				&rx_bytes, &rx_packets, &tx_bytes, &tx_packets);
+			#else
+			sscanf(p_srch, "%u %u %u %u %u %u %u %u %u %u",
+				&rx_bytes, &rx_packets, &rx_errs, &rx_drop, &rx_fifo, &rx_frame,
+				&rx_compressed, &rx_multicast, &tx_bytes, &tx_packets);
+			#endif
+			xprintf(lmask, "rx_bytes=%u\n", rx_bytes);
+			xprintf(lmask, "rx_packets=%u\n", rx_packets);
+			xprintf(lmask, "tx_bytes=%u\n", tx_bytes);
+			xprintf(lmask, "tx_packets=%u\n", tx_packets);
+			net_info->rx_bytes = rx_bytes;
+			net_info->rx_packets = rx_packets;
+			net_info->tx_bytes = tx_bytes;
+			net_info->tx_packets = tx_packets;
+			ret = 0;
+			break;
+		}
+	}
+	fclose(fp);
+out:
+	xfunc_out();
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+int wm_get_rf_info(int dev_idx, GCT_API_RF_INFORM_P rf_info)
+{
+	device_t *dev;
+	wimax_t *wm;
+	u8 buf[HCI_MAX_PACKET];
+	tlv_t tlv[32];
+	u8 T;
+	u16 L;
+	u8 *V;
+	int ret, i, pos = 0;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	assert(dev->wimax->subs_list.head.prev && dev->wimax->subs_list.head.next);
+	wm = dev->wimax;
+
+	tlv[pos++].T = TLV_T(T_UL_PERM_BASE);
+	tlv[pos++].T = TLV_T(T_PER_RECEIVE_COUNT);
+	tlv[pos++].T = TLV_T(T_PER_ERROR_COUNT);
+	tlv[pos++].T = TLV_T(T_DL_PERM_BASE);
+	tlv[pos++].T = TLV_T(T_CURR_PREAMBLE_IDX);
+	tlv[pos++].T = TLV_T(T_PREV_PREAMBLE_IDX);
+	tlv[pos++].T = TLV_T(T_HO_CNT);
+	tlv[pos++].T = TLV_T(T_HO_FAIL_CNT);
+	tlv[pos++].T = TLV_T(T_RESYNC_CNT);
+	tlv[pos++].T = TLV_T(T_HO_SIGNAL_LATENCY);
+	tlv[pos++].T = TLV_T(T_CINR);
+	tlv[pos++].T = TLV_T(T_CINR_2);
+	tlv[pos++].T = TLV_T(T_RSSI);
+	tlv[pos++].T = TLV_T(T_RSSI_2);
+	tlv[pos++].T = TLV_T(T_PER);
+	tlv[pos++].T = TLV_T(T_POWER_CONTROL_MODE);
+	tlv[pos++].T = TLV_T(T_TX_POWER);
+	tlv[pos++].T = TLV_T(T_TX_POWER_MAX);
+	tlv[pos++].T = TLV_T(T_UL_BURST_DATA_FEC_SCHEME);
+	tlv[pos++].T = TLV_T(T_DL_BURST_DATA_FEC_SCHEME);
+	tlv[pos++].T = TLV_T(T_UL_BURST_DATA_UIUC);
+	tlv[pos++].T = TLV_T(T_DL_BURST_DATA_UIUC);
+	tlv[pos++].T = TLV_T(T_CUR_FREQ);
+
+	assert(pos <= numof_array(tlv));
+
+	ret = hci_req_getinfo(dev_idx, buf, tlv, pos);
+	if (ret < 0)
+		goto out;
+
+	for (i = 0; i < pos; i++) {
+		T = tlv[i].T;
+		L = tlv[i].L;
+		V = tlv[i].V;
+		switch (T) {
+			case TLV_T(T_UL_PERM_BASE):
+				rf_info->ULPermBase = *V;
+				xprintf(SDK_DBG, "T_UL_PERM_BASE=%d\n", rf_info->ULPermBase);
+				break;
+			case TLV_T(T_PER_RECEIVE_COUNT):
+				memcpy(&rf_info->nPERReceiveCount, V, TLV_L(T_PER_RECEIVE_COUNT));
+				rf_info->nPERReceiveCount = DB2H(rf_info->nPERReceiveCount);
+				xprintf(SDK_DBG, "T_PER_RECEIVE_COUNT=%d\n", rf_info->nPERReceiveCount);
+				break;
+			case TLV_T(T_PER_ERROR_COUNT):
+				memcpy(&rf_info->nPERErrorCount, V, TLV_L(T_PER_ERROR_COUNT));
+				rf_info->nPERErrorCount = DB2H(rf_info->nPERErrorCount);
+				xprintf(SDK_DBG, "T_PER_ERROR_COUNT=%d\n", rf_info->nPERErrorCount);
+				break;
+			case TLV_T(T_DL_PERM_BASE):
+				rf_info->DLPermBase = *V;
+				xprintf(SDK_DBG, "T_DL_PERM_BASE=%d\n", rf_info->DLPermBase);
+				break;
+			case TLV_T(T_CURR_PREAMBLE_IDX):
+				rf_info->CurrentPreambleIndex = *V;
+				xprintf(SDK_DBG, "T_CURR_PREAMBLE_IDX=%d\n",
+					rf_info->CurrentPreambleIndex);
+				break;
+			case TLV_T(T_PREV_PREAMBLE_IDX):
+				rf_info->PreviousPreambleIndex = *V;
+				xprintf(SDK_DBG, "T_PREV_PREAMBLE_IDX=%d\n",
+					rf_info->PreviousPreambleIndex);
+				break;
+			case TLV_T(T_HO_CNT):
+				memcpy(&rf_info->HandOverCount, V, TLV_L(T_HO_CNT));
+				rf_info->HandOverCount = H2B(rf_info->HandOverCount);
+				xprintf(SDK_DBG, "T_HO_CNT=%d\n", rf_info->HandOverCount);
+				break;
+			case TLV_T(T_HO_FAIL_CNT):
+				memcpy(&rf_info->HandOverFailCount, V, TLV_L(T_HO_FAIL_CNT));
+				rf_info->HandOverFailCount = H2B(rf_info->HandOverFailCount);
+				xprintf(SDK_DBG, "T_HO_FAIL_CNT=%d\n", rf_info->HandOverFailCount);
+				break;
+			case TLV_T(T_RESYNC_CNT):
+				memcpy(&rf_info->ResyncCount, V, TLV_L(T_RESYNC_CNT));
+				rf_info->ResyncCount = H2B(rf_info->ResyncCount);
+				xprintf(SDK_DBG, "T_RESYNC_CNT=%d\n", rf_info->ResyncCount);
+				break;
+			case TLV_T(T_HO_SIGNAL_LATENCY):
+				memcpy(&rf_info->HoSignalLatency, V, TLV_L(T_HO_SIGNAL_LATENCY));
+				rf_info->HoSignalLatency = H2B(rf_info->HoSignalLatency);
+				xprintf(SDK_DBG, "T_HO_SIGNAL_LATENCY=%d\n", rf_info->HoSignalLatency);
+				break;
+			case TLV_T(T_CINR):
+				rf_info->CINR = wm_convert_cinr(*V);
+				xprintf(SDK_DBG, "T_CINR=%d\n", (s8) *V);
+				break;
+			case TLV_T(T_CINR_2):
+				rf_info->CINR2 = wm_convert_cinr(*V);
+				xprintf(SDK_DBG, "T_CINR_2=%d\n", (s8) *V);
+				break;
+			case TLV_T(T_RSSI):
+				rf_info->RSSI = wm_convert_rssi(*V);
+				xprintf(SDK_DBG, "T_RSSI=%d\n", (s8) *V);
+				break;
+			case TLV_T(T_RSSI_2):
+				rf_info->RSSI2 = wm_convert_rssi(*V);
+				xprintf(SDK_DBG, "T_RSSI_2=%d\n", (s8) *V);
+				break;
+			case TLV_T(T_PER):
+				memcpy(&rf_info->PER, V, TLV_L(T_PER));
+				rf_info->PER = H2B(rf_info->PER);
+				xprintf(SDK_DBG, "T_PER=%d\n", rf_info->PER);
+				break;
+			case TLV_T(T_POWER_CONTROL_MODE):
+				rf_info->PowerControlMode = *V;
+				xprintf(SDK_DBG, "T_POWER_CONTROL_MODE=%d\n", *V);
+				break;
+			case TLV_T(T_TX_POWER):
+				rf_info->TxPower= wm_convert_txpower(*V);
+				xprintf(SDK_DBG, "T_TX_POWER=%d\n", (s8) *V);
+				break;
+			case TLV_T(T_TX_POWER_MAX):
+				rf_info->TxPowerMax = wm_convert_txpower(*V);
+				xprintf(SDK_DBG, "T_TX_POWER_MAX=%d\n", (s8) *V);
+				break;
+			case TLV_T(T_UL_BURST_DATA_FEC_SCHEME):
+				rf_info->ULBurstDataFECScheme = *V;
+				xprintf(SDK_DBG, "T_UL_BURST_DATA_FEC_SCHEME=%d\n", *V);
+				break;
+			case TLV_T(T_DL_BURST_DATA_FEC_SCHEME):
+				rf_info->DLBurstDataFECScheme = *V;
+				xprintf(SDK_DBG, "T_DL_BURST_DATA_FEC_SCHEME=%d\n", *V);
+				break;
+			case TLV_T(T_UL_BURST_DATA_UIUC):
+				rf_info->ULBurstDataUIUC = *V;
+				xprintf(SDK_DBG, "T_UL_BURST_DATA_UIUC=%d\n", *V);
+				break;
+			case TLV_T(T_DL_BURST_DATA_UIUC):
+				rf_info->DLBurstDataDIUC = *V;
+				xprintf(SDK_DBG, "T_DL_BURST_DATA_UIUC=%d\n", *V);
+				break;
+			case TLV_T(T_CUR_FREQ):
+				rf_info->Frequency = U82U32(V);
+				xprintf(SDK_DBG, "T_CUR_FREQ=%d\n", rf_info->Frequency);
+				break;
+			default:
+				xprintf(SDK_ERR, "Unknown Get-Info type(0x%02x)\n", T);
+				ret = -1;
+				goto out;
+		}
+	}
+
+	memcpy(&rf_info->bsId, wm->conn_comp.net_id.bs.id, BS_ID_SIZE);
+out:
+	dm_put_dev(dev_idx);
+	return ret;
+}
+
+void array_DB2H(u32 *arr, int n)
+{
+	int i;
+	for (i = 0; i < n; i++, arr++)
+		*arr = DB2H(*arr);
+}
+
+void array_B2H(u16 *arr, int n)
+{
+	int i;
+	for (i = 0; i < n; i++, arr++)
+		*arr = B2H(*arr);
+}
+
+int wm_retrieve_mac_pdu_statistics(mac_pdu_statistics_t *p, u8 *buf, int len)
+{
+	int data_size;
+
+	xfunc_in();
+	assert(p);
+	data_size = p->end-p->start;
+	p->timestamp = (unsigned int)gettimemsofday();
+	memcpy(&p->start, buf, data_size);
+	array_DB2H(&p->num_tx_sdu, data_size/4);
+	xfunc_out();
+	return data_size;
+}
+
+int wm_retrieve_mac_phy_mac_basic(mac_phy_mac_basic_t *p, u8 *buf, int len)
+{
+	ori_mac_phy_mac_basic_t *s = (ori_mac_phy_mac_basic_t *) buf;
+
+	xfunc_in();
+	assert(p);
+	p->timestamp = (unsigned int)gettimemsofday();
+
+	memcpy(&p->start, s, rangeof(ori_mac_phy_mac_basic_t, frame_number, bandwidth));
+	memcpy(&p->time_active, &s->time_active,
+		rangeof(ori_mac_phy_mac_basic_t, time_active, primary_cid));
+	array_DB2H(&p->frame_number, 2);
+	array_B2H(&p->ttg, 2);
+	array_DB2H((u32*)&p->ul_time, 2);
+	array_B2H(&p->bandwidth, 1);
+	array_DB2H(&p->time_active, 3);
+	array_B2H(&p->basic_cid, 2);
+	xfunc_out();
+	return sizeof(ori_mac_phy_mac_basic_t);
+}
+
+int wm_retrieve_mac_power_ctrl(mac_power_ctrl_t *p, u8 *buf, int len)
+{
+	int data_size;
+
+	xfunc_in();
+	assert(p);
+	data_size = p->end-p->start;
+	p->timestamp = (unsigned int)gettimemsofday();
+	memcpy(&p->start, buf, data_size);
+	xfunc_out();
+	return data_size;
+}
+
+int wm_retrieve_mac_phy_burst(mac_phy_burst_t *p, u8 *buf, int len)
+{
+	int data_size;
+
+	xfunc_in();
+	assert(p);
+	data_size = p->end-p->start;
+	p->timestamp = (unsigned int)gettimemsofday();
+	memcpy(&p->start, buf, data_size);
+	array_DB2H(&p->num_dl_map,
+		rangeof(mac_phy_burst_t, num_dl_map, num_harq_ul_burst_retry)/4);
+	array_DB2H(&p->num_harq_crc_error, 1);
+	xfunc_out();
+	return data_size;
+}
+
+int wm_retrieve_mac_phy_mcs(mac_phy_mcs_t *p, u8 *buf, int len)
+{
+	int data_size;
+	ori_mac_phy_mcs_t t;
+	int nCurPos = 0;
+	
+	bool bDL = FALSE;
+	int nMIMOType = MINO_TYPE_NOT_SPEC;
+
+	xfunc_in();
+	assert(p);
+	data_size = p->end-p->start;
+	p->timestamp = (unsigned int)gettimemsofday();
+
+	while (nCurPos < len)
+	{
+		memcpy(&t, buf + nCurPos, sizeof(t));
+		array_DB2H(&t.num_burst,
+			rangeof(ori_mac_phy_mcs_t, num_burst, num_pdu)/4);
+		nCurPos += sizeof(t);
+
+		if (t.modulation_fec >= OFDMA_FEC_MODE_CNT)
+		{
+			xprintf(SDK_ERR, "Invalid modulation_fec(%d)\n", t.modulation_fec);
+			return -1;
+		}
+
+		if (t.repetition_code >= REPETITION_CODING_CNT)
+		{
+			xprintf(SDK_ERR, "Invalid repetition_code(%d)\n", t.repetition_code);
+			return -1;
+		}
+
+		bDL = (t.feature & 0x01) ? 1:0;
+			
+		if (t.feature & 0x02)
+		{
+			nMIMOType = MINO_TYPE2_ANT_STC_MATRIX_A;
+		}
+		else if (t.feature & 0x04)
+		{
+			nMIMOType = MINO_TYPE2_ANT_STC_MATRIX_B_VC;
+		}
+		else
+			nMIMOType = MINO_TYPE_NOT_SPEC;
+
+		// if DL
+		if (bDL)
+		{
+			memcpy(&p->dl[t.modulation_fec][t.repetition_code][nMIMOType], &t.num_burst, 
+				sizeof(p->dl[t.modulation_fec][t.repetition_code][nMIMOType]));
+			p->dl_used[t.modulation_fec][t.repetition_code][nMIMOType] = TRUE;
+		}
+		else // else UL
+		{
+			memcpy(&p->ul[t.modulation_fec][t.repetition_code][nMIMOType], &t.num_burst, 
+				sizeof(p->ul[t.modulation_fec][t.repetition_code][nMIMOType]));
+			p->ul_used[t.modulation_fec][t.repetition_code][nMIMOType] = TRUE;
+		}
+	
+	}
+	
+	xfunc_out();
+	return data_size;
+}
+
+int wm_retrieve_mac_phy_zone(mac_phy_zone_t *p, u8 *buf, int len)
+{
+	xfunc_in();
+	assert(p);
+	p->timestamp = (unsigned int)gettimemsofday();
+	xfunc_out();
+	return sizeof(ori_mac_phy_mcs_t);
+}
+
+int wm_retrieve_mac_phy_cinr_rssi(mac_phy_cinr_rssi_t *p, u8 *buf, int len)
+{
+	int data_size;
+
+	xfunc_in();
+	assert(p);
+	data_size = len; // Len is variable by Firmware version
+	p->timestamp = (unsigned int)gettimemsofday();
+	memcpy(&p->start, buf, data_size);
+	xfunc_out();
+	return data_size;
+}
+
+int wm_retrieve_mac_phy_temp_adc(mac_phy_temp_adc_t *p, u8 *buf, int len)
+{
+	int data_size;
+
+	xfunc_in();
+	assert(p);
+	data_size = p->end-p->start;
+	p->timestamp = (unsigned int)gettimemsofday();
+	memcpy(&p->start, buf, data_size);
+	xfunc_out();
+	return data_size;
+}
+
+int wm_retrieve_mac_phy_ctrl_chan(mac_phy_ctrl_chan_t *p, u8 *buf, int len)
+{
+	int data_size;
+
+	xfunc_in();
+	assert(p);
+	data_size = p->end-p->start;
+	p->timestamp = (unsigned int)gettimemsofday();
+	memcpy(&p->start, buf, data_size);
+	array_DB2H(&p->num_ffb_sent, data_size/4);
+	xfunc_out();
+	return data_size;
+}
+
+int wm_retrieve_mac_phy_dl_statistics(mac_phy_dl_statistics_t *p, u8 *buf, int len)
+{
+	int data_size;
+
+	xfunc_in();
+	assert(p);
+	data_size = p->end-p->start;
+	p->timestamp = (unsigned int)gettimemsofday();
+	memcpy(&p->start, buf, data_size);
+	array_DB2H(&p->sfid, 1);
+	array_B2H(&p->cid, 2);
+	array_DB2H(&p->num_rx_sdu, 8);
+	array_B2H(&p->arq_discard_msgs, 3);
+	xfunc_out();
+	return data_size;
+}
+
+int wm_retrieve_mac_phy_ul_statistics(mac_phy_ul_statistics_t *p, u8 *buf, int len)
+{
+	int data_size;
+
+	xfunc_in();
+	assert(p);
+	data_size = p->end-p->start;
+	p->timestamp = (unsigned int)gettimemsofday();
+	memcpy(&p->start, buf, data_size);
+	array_DB2H(&p->sfid, 1);
+	array_B2H(&p->cid, 2);
+	array_DB2H(&p->num_tx_sdu, 10);
+	array_B2H(&p->arq_discard_msgs, 3);
+	xfunc_out();
+	return data_size;
+}
+
+int wm_retrieve_mac_handover(mac_handover_t *p, u8 *buf, int len)
+{
+	int data_size;
+
+	xfunc_in();
+	assert(p);
+	data_size = p->end-p->start;
+	p->timestamp = (unsigned int)gettimemsofday();
+	memcpy(&p->start, buf, data_size);
+	array_B2H(&p->ho_count, 4);
+	xfunc_out();
+	return data_size;
+}
+
+int wm_retrieve_mac_neighbor(mac_neighbor_t *p, u8 *buf, int len, u8 *bsid)
+{
+	int data_size;
+
+	xfunc_in();
+	assert(p);
+	p->timestamp = (unsigned int)gettimemsofday();
+	p->nr_list = MAX_NEIGHBOT_LIST;
+	data_size = get_neighbor_info(bsid, buf, len, p->list, (int *)&p->nr_list);
+	xfunc_out();
+	return data_size;
+}
+
+int wm_retrieve_mac_harq_statistics(mac_harq_statistics_t *p, u8 *buf, int len)
+{
+	int data_size;
+
+	xfunc_in();
+	assert(p);
+	data_size = p->end-p->start;
+	p->timestamp = (unsigned int)gettimemsofday();
+	memcpy(&p->start, buf, data_size);
+	array_DB2H(p->num_dl_harq_retry, 16);
+	xfunc_out();
+	return data_size;
+}
+
+int wm_retrieve_mac_net_entry_statistics(mac_net_entry_statistics_t *p, u8 *buf, int len)
+{
+	int data_size;
+
+	xfunc_in();
+	assert(p);
+	data_size = p->end-p->start;
+	p->timestamp = (unsigned int)gettimemsofday();
+	memcpy(&p->start, buf, data_size);
+	array_B2H(&p->cdma_rng_time, 6);
+	xfunc_out();
+	return data_size;
+}
+
+int wm_set_run_mode(int dev_idx, int mode)
+{
+	u8 cnt = 0;
+	u8 mode_val;
+	int ret;
+	u8 param[128];
+
+	xfunc_in();
+
+	if (mode & sdk_eng_mode)
+		mode_val = T_ENGINEERING_MODE;
+	else
+		mode_val = T_NORMAL_MODE;
+
+	param[cnt++] = TLV_T(T_RUN_MODE);
+	param[cnt++] = TLV_L(T_RUN_MODE);
+	param[cnt++] = mode_val;
+
+	ret = hci_send(dev_idx, WIMAX_SET_INFO, param, cnt);
+	if (cnt == ret)
+		ret = 0;
+	else {
+		xprintf(SDK_STD_ERR, "[%d] hci_send(%d!=%d)\n", dev_idx, cnt, ret);
+		ret = -1;
+	}
+
+	xfunc_out();
+	return ret;
+}
+
+static int get_neighbor_info(u8 *bsid, u8 *buf, int len,
+	wm_bs_neigh_t *list, int *list_cnt)
+{
+	u8 neighbors = *buf;
+	bs_neigh_t *n;
+	int i = 0, entry_size = 0;
+
+	xfunc_in("list cnt=%d", *list_cnt);
+
+	if (len < sizeof(bs_neigh_t)) {
+		if ((u32)len <= 1)/*0 or 1*/
+			xprintf(SDK_INFO, "Not found neighbor\n");
+		else
+			xprintf(SDK_ERR, "Wrong length=%d\n", len);
+		goto out;
+	}
+
+	if (!neighbors) {
+		xprintf(SDK_INFO, "Neighbor list is empty!\n");
+		goto out;
+	}
+
+	entry_size = (len - 1) / neighbors;
+
+	for (i = 0; i < neighbors; i++) {
+		if (i+1 > *list_cnt)
+			break;
+
+		n = (bs_neigh_t *)(buf + 1 + i * entry_size);
+
+		list[i].frequency = (n->frequency[0]<<16) | (n->frequency[1]<<8) | n->frequency[2];
+		list[i].preamble = n->preamble_idx;
+		list[i].cinr = wm_convert_cinr(n->cinr);
+		list[i].rssi = wm_convert_rssi(n->rssi);
+
+		list[i].bsid[0] = bsid[0];
+		list[i].bsid[1] = bsid[1];
+		list[i].bsid[2] = bsid[2];
+		list[i].bsid[3] = n->bsid[0];
+		list[i].bsid[4] = n->bsid[1];
+		list[i].bsid[5] = n->bsid[2];
+
+		#if 1
+		if (entry_size >= sizeof(bs_neigh_t))
+			list[i].bandwidth = n->bandwidth;
+
+		xprintf(SDK_INFO, "%d %d %d %d %02x%02x%02x:%02x%02x%02x %d\n",
+				list[i].frequency, n->preamble_idx, n->cinr, n->rssi,
+				list[i].bsid[0], list[i].bsid[1], list[i].bsid[2],
+				list[i].bsid[3], list[i].bsid[4], list[i].bsid[5],
+				list[i].bandwidth);
+		#else
+		if (entry_size >= sizeof(bs_neigh_t)) {
+			list[i].bandwidth = n->bandwidth;
+			list[i].rtd = n->rtd;
+		}
+
+		xprintf(SDK_INFO, "%d %d %d %d %02x%02x%02x:%02x%02x%02x %d %d\n",
+				list[i].frequency, n->preamble_idx, n->cinr, n->rssi,
+				list[i].bsid[0], list[i].bsid[1], list[i].bsid[2],
+				list[i].bsid[3], list[i].bsid[4], list[i].bsid[5],
+				list[i].bandwidth, list[i].rtd);
+		#endif
+	}
+out:
+	*list_cnt = i;
+	xfunc_out("list cnt=%d", *list_cnt);
+	return *list_cnt ? (1 + *list_cnt * entry_size) : 0;
+}
+
+int wm_get_neighbor_list(int dev_idx, wm_bs_neigh_t *list, int *list_cnt)
+{
+	device_t *dev;
+	wimax_t *wm;
+	u8 buf[HCI_MAX_PACKET];
+	u8 cnt = 0;
+	u8 param[128];
+	int ret, pos = 0;
+	u8 T;
+	u16 L;
+	u8 *V;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+	wm = dev->wimax;
+
+	param[cnt++] = 0;
+	param[cnt++] = W_NEIGHBOR_LIST;
+
+	ret = hci_send_wait(dev_idx, WIMAX_MODEM_REQUEST, param, cnt,
+		WIMAX_MODEM_REPORT, buf, HCI_MAX_PACKET, 0, 0, IO_TIMEOUT_SEC);
+
+	while (pos < ret) {
+		pos += hci_get_tlv(buf+pos, &T, &L, &V);
+
+		switch (T) {
+			case W_NEIGHBOR_LIST:
+				ret = get_neighbor_info(wm->conn_comp.net_id.bs.id, V, L, list, list_cnt);
+				break;
+			default:
+				xprintf(SDK_ERR, "Unknown type:0x%02X\n", T);
+				ret = -1;
+				goto out;
+		}
+	}
+out:
+	if (ret > 0) ret = 0;
+	else *list_cnt = 0;
+
+	dm_put_dev(dev_idx);
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int wm_notification(int dev_idx, char *buf, int len)
+{
+	hci_notification_t *err_noti = (hci_notification_t *) buf;
+	GCT_API_NOTI_CATEGORY category;
+	GCT_API_NOTI_TYPE type;
+	char *value;
+	int vlen;
+	int ret;
+
+	xfunc_in("len=%d", len);
+
+	category = err_noti->category;
+	type = err_noti->type;
+	value = (char *) err_noti->value;
+	vlen = len - sizeof(hci_notification_t);
+
+	ret = sdk_ind_noti(dev_idx, category, type, value, vlen);
+
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int wm_ind_sf_mode(int dev_idx, u8 *buf, int len)
+{
+	device_t *dev;
+	wimax_t *wm;
+	int ret = 0;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	wm = dev->wimax;
+
+	if (*buf == WIMAX_SF_ENABLE)
+		wm->scan.sf_mode = TRUE;
+	else
+		wm->scan.sf_mode = FALSE;
+
+	dm_put_dev(dev_idx);
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int wm_disable_sf_mode(int dev_idx)
+{
+	device_t *dev;
+	wimax_t *wm;
+	char *cmd = "sfe";
+	int cmd_len = strlen(cmd);
+	int ret = 0;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	wm = dev->wimax;
+
+	if (wm->scan.sf_mode) {
+		if ((ret = hci_send(dev_idx, WIMAX_CLI_CMD, (u8 *)cmd, cmd_len)) == cmd_len)
+			ret = 0;
+		xprintf(SDK_NOTICE, "Disable SF Mode, ret=%d\n", ret);
+		wm->scan.sf_mode = FALSE;
+	}
+
+	dm_put_dev(dev_idx);
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+bool wm_compare_nsp(wm_nsp_identifier_t *nsp, wm_nsp_identifier_t *nsp2)
+{
+	bool ret;
+	int lmask = SDK_FORCE;
+
+	if (U82U24(nsp->id) == U82U24(nsp2->id))
+		ret = TRUE;
+	else
+		ret = FALSE;
+	
+	xprintf(lmask, "%s(%02x%02x%02x) & %s(%02x%02x%02x) : %s\n",
+		nsp->name, nsp->id[0], nsp->id[1], nsp->id[2],
+		nsp2->name, nsp2->id[0], nsp2->id[1], nsp2->id[2],
+		ret ? "match" : "mismatch");
+
+	return ret;
+}
+
+int wm_report_full_reentry(int dev_idx, u8 *buf, int len)
+{
+	device_t *dev;
+	int ret = 0;
+
+	if (!(dev = dm_get_dev(dev_idx)))
+		return -1;
+
+	xfunc_in("dev=%d", dev_idx);
+
+	dm_put_dev(dev_idx);
+	xfunc_out();
+	return ret;
+}
+
+int wm_cmd_mac_state(int dev_idx, GCT_API_CMD_MAC_STATE_TYPE type)
+{
+	u16 cmd;
+	int ret;
+
+	if (!sdk_get_rw_handle())
+		return 0;
+
+	switch(type) {
+		case GCT_API_CMD_MAC_STATE_ENTER_SLEEP_MODE:
+			cmd = WIMAX_ENTER_SLEEP;
+			break;
+
+		case GCT_API_CMD_MAC_STATE_EXIT_SLEEP_MODE:
+			cmd = WIMAX_EXIT_SLEEP;
+			break;
+
+		case GCT_API_CMD_MAC_STATE_ENTER_IDLE_MODE:
+			cmd = WIMAX_ENTER_IDLE;
+			break;
+			
+		case GCT_API_CMD_MAC_STATE_EXIT_IDLE_MODE:
+			cmd = WIMAX_EXIT_IDLE;
+			break;
+	}
+
+	ret = hci_send(dev_idx, cmd, NULL, 0);
+	if (0 != ret) {
+		xprintf(SDK_STD_ERR, "[%d] hci_send(%d)\n", dev_idx, ret);
+		ret = sdk_set_errno(ERR_STD);
+	}
+
+	return ret;
+}
+
+int wm_set_idle_mode_timeout(int dev_idx, u16 timeoutSec)
+{
+	u8 buf[128];
+	int pos;
+	int ret;
+
+	if (!sdk_get_rw_handle())
+		return 0;
+
+	timeoutSec = B2H(timeoutSec);
+
+	pos = hci_set_tlv(buf, TLV_T(T_IDLE_MODE_TO), TLV_L(T_IDLE_MODE_TO), (u8*)&timeoutSec);
+
+	ret = hci_send(dev_idx, WIMAX_SET_INFO, buf, pos);
+	if (!ret) {
+		xprintf(SDK_STD_ERR, "[%d] hci_send(%d)\n", dev_idx, ret);
+		ret = sdk_set_errno(ERR_STD);
+	}
+	return ret;
+}
+
+int wm_get_phy_mac_basic(int dev_idx, GCT_API_MAC_PHY_MAC_BASIC_P pData)
+{
+	u8 buf[HCI_MAX_PACKET], *p = buf;
+	u8 T, *V;
+	u16 L;
+	int pos = 0, len = 0, ret = -1;
+	ori_mac_phy_mac_basic_t *s;
+
+	*p++ = MODE_MODEM_REPORT;
+	*p++ = W_PHY_MAC_BASIC;
+	len = hci_send_wait(dev_idx, WIMAX_MODEM_REQUEST, buf, p-buf,
+		WIMAX_MODEM_REPORT, buf, sizeof(buf), 0, 0, 5);
+	if (len <= HCI_HEADER_SIZE) {
+		xprintf(SDK_ERR, "HCI response error: len=%d\n", ret);
+		ret = -1;
+		goto out;
+	}
+
+	memset(pData, 0x00, sizeof(GCT_API_MAC_PHY_MAC_BASIC));
+
+	while (pos < len) {
+		pos += hci_get_tlv(&buf[pos], &T, &L, &V);
+		switch (T) {
+			case TLV_T(W_PHY_MAC_BASIC):
+				s = (ori_mac_phy_mac_basic_t *) V;
+
+				memcpy(&pData->frame_number, s, 
+					rangeof(ori_mac_phy_mac_basic_t, frame_number, ul_time));
+
+				array_DB2H(&pData->frame_number, 2);
+				array_B2H(&pData->ttg, 2);
+				array_DB2H((u32*)&pData->ul_time, 1);
+
+				if (L > 28) {
+					memcpy(&pData->frequency, &s->frequency, 
+						rangeof(ori_mac_phy_mac_basic_t, frequency, bandwidth));
+					memcpy(&pData->time_active, &s->time_active,
+						rangeof(ori_mac_phy_mac_basic_t, time_active, primary_cid));
+
+					array_DB2H((u32*)&pData->frequency, 1);
+					array_B2H(&pData->bandwidth, 1);
+					array_DB2H(&pData->time_active, 3);
+					array_B2H(&pData->basic_cid, 2);
+				}
+
+				ret = L;
+				break;
+			default:
+				ret = -1;
+		}
+		xprintf(SDK_DBG, "Type(%02x): L=%u, ret=%d\n", T, L, ret);
+		if (ret < 0) {
+			xprintf(SDK_NOTICE, "Unknown Type=0x%02x\n", T);
+			break;
+		}
+	}
+
+out:
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int wm_get_phy_mcs(int dev_idx, GCT_API_MAC_PHY_MCS_P pData)
+{
+	u8 buf[HCI_MAX_PACKET], *p = buf;
+	u8 T, *V;
+	u16 L;
+	int pos = 0, len = 0, nCurPos = 0, ret = -1;
+	bool bDL = FALSE;
+	int nMIMOType = MINO_TYPE_NOT_SPEC;
+	ori_mac_phy_mcs_t t;
+
+	*p++ = MODE_MODEM_REPORT;
+	*p++ = W_PHY_MSC;
+	len = hci_send_wait(dev_idx, WIMAX_MODEM_REQUEST, buf, p-buf,
+		WIMAX_MODEM_REPORT, buf, sizeof(buf), 0, 0, 5);
+	if (len <= HCI_HEADER_SIZE) {
+		xprintf(SDK_ERR, "HCI response error: len=%d\n", ret);
+		ret = -1;
+		goto out;
+	}
+
+	memset(pData, 0x00, sizeof(GCT_API_MAC_PHY_MCS));
+
+	while (pos < len) {
+		pos += hci_get_tlv(&buf[pos], &T, &L, &V);
+		switch (T) {
+			case TLV_T(W_PHY_MSC):
+				while (nCurPos < L)
+				{
+					memcpy(&t, V + nCurPos, sizeof(t));
+					array_DB2H(&t.num_burst,
+						rangeof(ori_mac_phy_mcs_t, num_burst, num_pdu)/4);
+					nCurPos += sizeof(t);
+				
+					if (t.modulation_fec >= OFDMA_FEC_MODE_CNT)
+					{
+						xprintf(SDK_ERR, "Invalid modulation_fec(%d)\n", t.modulation_fec);
+						ret = -1;
+						goto out;
+					}
+				
+					if (t.repetition_code >= REPETITION_CODING_CNT)
+					{
+						xprintf(SDK_ERR, "Invalid repetition_code(%d)\n", t.repetition_code);
+						ret = -1;
+						goto out;
+					}
+				
+					bDL = (t.feature & 0x01) ? 1:0;
+						
+					if (t.feature & 0x02)
+					{
+						nMIMOType = MINO_TYPE2_ANT_STC_MATRIX_A;
+					}
+					else if (t.feature & 0x04)
+					{
+						nMIMOType = MINO_TYPE2_ANT_STC_MATRIX_B_VC;
+					}
+					else
+						nMIMOType = MINO_TYPE_NOT_SPEC;
+				
+					// if DL
+					if (bDL)
+					{
+						memcpy(&pData->dl[t.modulation_fec][t.repetition_code][nMIMOType], &t.num_burst, 
+							sizeof(pData->dl[t.modulation_fec][t.repetition_code][nMIMOType]));
+						pData->dl_used[t.modulation_fec][t.repetition_code][nMIMOType] = TRUE;
+					}
+					else // else UL
+					{
+						memcpy(&pData->ul[t.modulation_fec][t.repetition_code][nMIMOType], &t.num_burst, 
+							sizeof(pData->ul[t.modulation_fec][t.repetition_code][nMIMOType]));
+						pData->ul_used[t.modulation_fec][t.repetition_code][nMIMOType] = TRUE;
+					}
+				
+				}
+
+				ret = L;
+				break;
+			default:
+				ret = -1;
+		}
+		xprintf(SDK_DBG, "Type(%02x): L=%u, ret=%d\n", T, L, ret);
+		if (ret < 0) {
+			xprintf(SDK_NOTICE, "Unknown Type=0x%02x\n", T);
+			break;
+		}
+	}
+
+out:
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
+int wm_get_phy_cinr_rssi(int dev_idx, GCT_API_MAC_PHY_CINR_RSSI_P pData)
+{
+	u8 buf[HCI_MAX_PACKET], *p = buf;
+	u8 T, *V;
+	u16 L;
+	int pos = 0, len = 0, ret = -1;
+
+	*p++ = MODE_MODEM_REPORT;
+	*p++ = W_PHY_CINR_RSSI;
+	len = hci_send_wait(dev_idx, WIMAX_MODEM_REQUEST, buf, p-buf,
+		WIMAX_MODEM_REPORT, buf, sizeof(buf), 0, 0, 5);
+	if (len <= HCI_HEADER_SIZE) {
+		xprintf(SDK_ERR, "HCI response error: len=%d\n", ret);
+		ret = -1;
+		goto out;
+	}
+
+	memset(pData, 0x00, sizeof(GCT_API_MAC_PHY_CINR_RSSI));
+
+	while (pos < len) {
+		pos += hci_get_tlv(&buf[pos], &T, &L, &V);
+		switch (T) {
+			case TLV_T(W_PHY_CINR_RSSI):
+				memcpy(pData, V, L);
+
+				ret = L;
+				break;
+			default:
+				ret = -1;
+		}
+		xprintf(SDK_DBG, "Type(%02x): L=%u, ret=%d\n", T, L, ret);
+		if (ret < 0) {
+			xprintf(SDK_NOTICE, "Unknown Type=0x%02x\n", T);
+			break;
+		}
+	}
+
+out:
+	xfunc_out("ret=%d", ret);
+	return ret;
+}
+
diff --git a/sdk/wimax.h b/sdk/wimax.h
new file mode 100644
index 0000000..2bfacb8
--- /dev/null
+++ b/sdk/wimax.h
@@ -0,0 +1,873 @@
+// 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.
+
+#if !defined(WIMAX_H_20080710)
+#define WIMAX_H_20080710
+#include "gcttype.h"
+#include "global.h"
+#include "timer.h"
+#include "eap.h"
+#include "io.h"
+#include "log.h"
+#if defined(CONFIG_ENABLE_SERVICE_FLOW)
+#include "sf.h"
+#endif // CONFIG_ENABLE_SERVICE_FLOW
+
+#define WM_MAX_VENDOR_NAME_LEN			128
+#define WM_MAX_MODEL_NAME_LEN			128
+#define WM_MAX_NAI_LEN					128
+#define WM_MAX_NSP_NAME_LEN				128
+#define WM_MAX_SUBSCRIPTION_NAME_LEN	128
+#define WM_MAX_NSP						64
+#define WM_MAX_NAP						64
+
+#if defined(CONFIG_ENABLE_BW_SWITCHING_FOR_KT)
+#define WM_DEFAULT_SCAN_INTERVAL_SEC		2
+#else
+#define WM_DEFAULT_SCAN_INTERVAL_SEC		5
+#endif
+
+// common data structures
+#define NSP_ID_SIZE     3
+#define NAP_ID_SIZE		3
+#define BS_ID_SIZE		6
+
+#define WIDE_SCAN_HNSP_ID	0xfffffd
+
+#define DEFAULT_CAPABILITY	(0xfffffffflu)
+
+typedef enum {
+	rf_on,
+	rf_off
+
+} rf_stat_t;
+
+typedef enum wimax_scan_type_e { 
+	wm_scan_all_channels,	/*wide scan*/
+	wm_scan_all_subscriptions,
+	wm_scan_curr_subscription
+
+} wimax_scan_type_t;
+
+typedef enum { 
+	wm_phy_min,
+	wm_phy_sc, 
+	wm_phy_sca, 
+	wm_phy_ofdm, 
+	wm_phy_ofdma, 
+	wm_phy_max
+
+} wm_phy_type_t;
+
+typedef enum { 
+	wm_assoc_success,
+	wm_assoc_ranging_abort_by_bs,
+	wm_assoc_ranging_timeout,
+	wm_assoc_ranging_max_retry_exceeded,
+	wm_assoc_ranging_other_failure,
+	wm_assoc_sbc_timeout,
+	wm_assoc_incompatible_sbc,
+	wm_assoc_sbc_other_failure,
+	wm_assoc_auth_eap_timeout,
+	wm_assoc_auth_eap_failure,
+	wm_assoc_auth_satek_timeout,
+	wm_assoc_auth_satek_failure,
+	wm_assoc_auth_key_req_timeout,
+	wm_assoc_auth_key_req_failure,
+	wm_assoc_req_msg_auth_failure,
+	wm_assoc_req_timeout,
+	wm_assoc_req_other_failure,
+	wm_assoc_isf_creat_timeout,
+	wm_assoc_isf_creat_failure
+
+} wm_association_status_t;
+
+typedef enum { 
+	wm_connect_success, 
+	wm_connect_success_activating, 
+	wm_connect_success_provisioning,
+	wm_connect_max_assoc_retry_exceeded, 
+	wm_connect_other_failure
+
+} wm_connection_status_t;
+
+typedef enum {
+	wm_ho_initiated_by_BS,
+	wm_ho_initiated_by_MS
+
+} wm_handover_reason_t;
+
+typedef enum {
+	wm_disconnect_by_DREZ,
+	wm_disconnect_by_MS,
+	wm_disconnect_by_OoZ,
+	wm_disconnect_by_Others
+
+} wm_disconnect_reason_t;
+
+typedef enum {
+	wm_addition_ind,
+	wm_deletion_ind,
+	wm_change_ind,
+
+} wm_change_type_t;
+
+enum { S_RNG, S_SBC, S_PKM, S_REG, S_DSX };
+enum { S_START, S_COMPLETE };
+
+typedef struct wm_nap_s {
+	/* id */
+	u8 		bsid[6];
+
+	/* RSSI and CINR */
+	u8		cinr;
+	u8		rssi;
+
+	/* Pointers to linked list of either visible_nap_list or cached_nap_list */
+	struct list_head list;
+
+} wm_nap_t;
+
+typedef struct wm_nsp_s {
+	u32		id;
+	u8		name[WM_MAX_NSP_NAME_LEN];
+	u8 		cinr;
+	u8		rssi;
+	u8		type;
+
+	/* Chain list of hash table */
+	struct list_head list;
+
+	struct wm_nap_s *nap_array[WM_MAX_NAP];
+	u8		nr_nap;
+
+	struct wm_nap_s *capl_array[WM_MAX_NAP];
+	u8		nr_capl;
+
+} wm_nsp_t;
+
+typedef struct wm_nsp_identifier_s {
+	u8 id[NSP_ID_SIZE];
+	u8 name[WM_MAX_NSP_NAME_LEN];
+
+} wm_nsp_identifier_t;
+
+typedef struct wm_nap_identifier_s {
+	u8	id[NAP_ID_SIZE];
+
+} wm_nap_identifier_t;
+
+typedef struct wm_bs_identifier_s {
+	u8	id[BS_ID_SIZE];
+
+} wm_bs_identifier_t;
+
+typedef struct wm_subscription_identifier_s {
+	u8					oper_x[WM_MAX_NAI_LEN];/*Operator/X node*/
+	wm_nsp_identifier_t	hnspid;	/*hnspid.name is operator name*/
+	u8					user_hnai[WM_MAX_NAI_LEN];/*user home NAI*/
+
+} wm_subscription_identifier_t;
+
+typedef union wm_pkm_s {
+	u8	pkm_support;
+	struct {
+		u8	pkm_v1: 1;
+		u8	pkm_v2: 1;
+	};
+
+} wm_pkm_t;
+
+typedef union wm_auth_policy_s { 
+	u8 auth_policy_support; 
+	struct { 
+		u8 rsa_initial_entry : 1; 
+		u8 eap_initial_entry : 1; 
+		u8 authenticated_eap_entry : 1; 
+		u8 reserved : 1; 
+		u8 rsa_reentry : 1; 
+		u8 eap_reentry : 1; 
+		u8 authenticated_eap_reentry : 1; 
+	};
+
+} wm_auth_policy_t;
+
+typedef union wm_cs_type_supported_s { 
+	u32 supported_cs; 
+	struct { 
+		u32 ATMCS : 1; 
+		u32 IPv4CS : 1; 
+		u32 IPv6CS : 1; 
+		u32 EthernetCS : 1; 
+		u32 _8021QCS : 1; 
+		u32 IPv4OverEthernetCS : 1; 
+		u32 IPv6OverEthernetCS : 1; 
+		s32 IPv4Over8021QCS : 1;
+		u32 IPv6Over8021QCS : 1; 
+		u32 EthernetWithROHCCS : 1; 
+		u32 EthernetWithECRTPCS : 1; 
+		u32 IPWithROHCCS : 1; 
+		u32 IPWithECRTPCS : 1; 
+	};
+} wm_cs_type_supported_t;
+
+typedef struct wm_rev_info_s {
+	u32	bl_ver;
+	u32	rel_ver;
+	u32	fw_ver;
+	u32	phy_hw_ver;
+
+} wm_rev_info_t;
+
+typedef struct wm_device_information_s {
+	u32		max_subs_supported;
+	u32		max_service_flow_supported;
+
+	wm_phy_type_t phy_type;
+	wm_pkm_t pkm_support;
+	wm_auth_policy_t auth_support;
+	wm_eap_param_t	eapp;
+
+	dhcp_info_t	dhcp_info;
+
+	#if defined(CONFIG_ENABLE_SERVICE_FLOW)
+	wm_service_flow_t service_flow;
+	#endif // CONFIG_ENABLE_SERVICE_FLOW
+
+	wm_cs_type_supported_t cs_type_supported;
+	bool	msihv_extensibility_security;
+	bool	device_locked;
+
+	wm_rev_info_t revision;
+
+	u8	device_mac[6];
+	u8	vendor_name[WM_MAX_VENDOR_NAME_LEN];
+	u8	model_name[WM_MAX_MODEL_NAME_LEN];
+
+} wm_device_info_t;
+
+typedef struct bs_info_s {
+	u8 hnspid[NSP_ID_SIZE];
+	u8 nspid[NSP_ID_SIZE];
+	u8 napid[NAP_ID_SIZE];
+	u8 bsid[BS_ID_SIZE];
+
+} bs_info_t;
+
+typedef struct wm_net_id_s {
+	wm_nsp_identifier_t	nsp;
+	wm_nap_identifier_t	nap;
+	wm_bs_identifier_t	bs;
+
+} wm_net_id_t;
+
+typedef struct wm_connect_s {
+	u32 hnspid;
+	u32 vnspid;
+
+} wm_connect_t;
+#define IS_VISITED_NSP(wm)	((wm)->conn.hnspid != (wm)->conn.vnspid)
+
+typedef struct wm_association_start_s {
+	wm_net_id_t net_id;
+
+} wm_association_start_t;
+
+typedef struct wm_association_complete_s {
+	wm_association_status_t status;
+	wm_net_id_t net_id;
+
+} wm_association_complete_t;
+
+typedef struct wm_disconnect_ind_s {	
+	wm_disconnect_reason_t	reason;
+
+} wm_disconnect_ind_t;
+
+typedef struct wm_handover_start_s {
+	wm_handover_reason_t	reason;
+
+} wm_handover_start_t;
+
+typedef struct wm_handover_complete_s {	
+	wm_connection_status_t	status;
+	wm_net_id_t net_id;
+
+} wm_handover_complete_t;
+
+typedef struct wn_connect_complete_s {
+	wm_connection_status_t	status;
+	wm_subscription_identifier_t subscription;
+	wm_net_id_t net_id;
+
+} wm_connect_complete_t;
+
+typedef struct nsp_list_data_s {
+	wm_nsp_identifier_t	NspIdentifier;
+	struct list_head	list;
+
+} nsp_list_data_t;
+
+typedef struct nap_list_data_s {
+	wm_nap_identifier_t nap_id;
+	struct list_head	list;
+
+} nap_list_data_t;
+
+typedef struct wm_subscription_info_s {
+	u8		idx;
+	struct list_head	list;
+	struct list_head	nsp_data_head;
+	struct list_head	nap_data_head;/*CAPL*/
+	
+	wm_subscription_identifier_t	subscription_id;
+	bool							auto_selection;
+	bool							auto_selection_configurable;
+	bool							auto_connect_at_home;
+	bool							auto_connect_when_roam;
+	bool							subs_locked;
+	bool							activated;
+	u32								num_operator_preferred_nsps;
+	u32								nsp_array_offs;
+
+} wm_subscription_info_t;
+
+typedef struct wm_subs_id_info_s {
+	struct list_head				list;
+	bool							activated;
+	wm_subscription_identifier_t	subs_id;
+
+} wm_subs_id_info_t;
+
+#if defined(CONFIG_ENABLE_BW_SWITCHING_FOR_KT)
+#define SWITCHING_BW_MAX_SCAN_INTERVAL_SEC		64
+#define BW_10MHz		(10*1000)
+#define BW_8750KHz		(8750)
+#endif
+typedef struct wm_scan_s {
+	wimax_scan_type_t	type;
+	wm_subscription_info_t	*selected_subs;
+	timer_obj_t			timer;
+	bool				sf_mode;
+	int					scan_interval_sec;
+	int					last_scan_ms;
+	bool				on_scanning;
+	#if defined(CONFIG_ENABLE_BW_SWITCHING_FOR_KT)
+	u32					scan_bw;
+	int					nr_no_scaned;
+	#endif
+
+} wm_scan_t;
+
+typedef struct wm_net_info_s {
+	u32	rx_bytes;
+	u32	rx_packets;
+	u32	tx_bytes;
+	u32	tx_packets;
+
+} wm_net_info_t;
+
+typedef struct wm_link_status_s {
+	u8	rssi;
+	u8	cinr;
+	u8	tx_power;
+	u32	cur_freq;
+
+} wm_link_status_t;
+
+typedef struct bs_neigh_s {
+	unsigned char	frequency[3];
+	unsigned char	preamble_idx;
+	char	cinr;
+	char	rssi;
+	unsigned char	bsid[3];
+	unsigned char	bandwidth;
+	//signed short	rtd;
+
+} __attribute__((packed)) bs_neigh_t;
+
+typedef struct wm_bs_neigh_s {
+	u32	frequency;
+	u8	preamble;
+	u8	cinr;
+	u8	rssi;
+	u8	bsid[BS_ID_SIZE];
+	u8	bandwidth;
+	//s16	rtd;
+
+} wm_bs_neigh_t;
+
+typedef enum wm_using_lock_e {
+	WM_USING_LOCK_ODM,
+	WM_USING_LOCK_ENTRIES
+
+} wm_using_lock_t;
+
+typedef struct mac_pdu_statistics_s {	/*0x50*/
+	u32	timestamp;
+	
+	u8	start[0];
+
+	u32	num_tx_sdu;
+	u32	num_tx_sdu_drop;
+	u32	num_rx_sdu;
+	u32	num_rx_sdu_drop;
+	u32	len_tx_sdu;
+	u32	len_tx_sdu_drop;
+	u32	len_rx_sdu;
+	u32	len_rx_sdu_drop;
+	u32	num_tx_pdu;
+	u32	num_rx_pdu;
+	u32	len_tx_pdu;
+	u32	len_rx_pdu;
+	u32	num_crc_error;
+	u32	num_dec_error;
+	u32	num_hcs_error;
+	u32	num_key_error;
+	u32	num_len_error;
+	u32	bw_req_retries;
+	u32	bw_req_count;
+	
+	u8	end[0];
+
+} mac_pdu_statistics_t;
+
+typedef struct ori_mac_phy_mac_basic_s {	/*0x51*/
+	u32	frame_number;
+	u32	fch;
+	u16	ttg;
+	u16	rtg;
+	u8	num_dl_symbol;
+	u8	num_ul_symbol;
+	u8	current_pi;	/*PreambleIndex*/
+	u8	previous_pi;	/*PreambleIndex*/
+	u8	ul_perm_base;
+	u8	mac_state;
+	u8	bsid[6];
+	s32	ul_time;
+	u32	frequency;
+	u16	bandwidth;
+	u32	time_active;
+	u32	time_sleep;
+	u32	time_idle;
+	u16	basic_cid;
+	u16	primary_cid;
+
+} __attribute__((packed)) ori_mac_phy_mac_basic_t;
+
+typedef struct mac_phy_mac_basic_s {	/*0x51*/
+	u32	timestamp;
+	
+	u8	start[0];
+
+	u32	frame_number;
+	u32	fch;
+	u16	ttg;
+	u16	rtg;
+	u8	num_dl_symbol;
+	u8	num_ul_symbol;
+	u8	current_pi;	/*PreambleIndex*/
+	u8	previous_pi;	/*PreambleIndex*/
+	u8	ul_perm_base;
+	u8	mac_state;
+	u8	bsid[6];
+	s32	ul_time;
+	u32	frequency;
+	u16	bandwidth;
+	u16	pad;
+	u32	time_active;
+	u32	time_sleep;
+	u32	time_idle;
+	u16	basic_cid;
+	u16	primary_cid;
+	
+	u8	end[0];
+
+} mac_phy_mac_basic_t;
+
+typedef struct mac_power_ctrl_s {	/*0x52*/
+	u32	timestamp;
+
+	u8	start[0];
+
+	u8	power_ctrl_mode;
+	u8	tx_power;
+	u8	tx_sc_power;
+	u8	last_tx_power;
+	u8	last_tx_sc_power;
+	u8	tx_max_power;
+	u8	tx_max_sc_power;
+	u8	tx_min_power;
+	u8	tx_min_sc_power;
+	
+	u8	end[0];
+
+} mac_power_ctrl_t;
+
+typedef struct mac_phy_burst_s {	/*0x53*/
+	u32	timestamp;
+
+	u8	start[0];
+
+	u32	num_dl_map;
+	u32	num_ul_map;
+	u32	num_dl_map_error;
+	u32	num_ul_map_error;
+	u32	num_dl_burst;
+	u32	num_dl_burst_error;
+	u32	num_ul_burst;
+	u32	num_harq_dl_burst;
+	u32	num_harq_dl_burst_drop;
+	u32	num_harq_ul_burst;
+	u32	num_harq_ul_burst_retry;
+	u8	last_dl_burst_msc;
+	u8	last_dl_burst_rpt;
+	u8	last_diuc;
+	u8	last_ul_burst_msc;
+	u8	last_ul_burst_rpt;
+	u8	last_uiuc;
+	u16	reserved;
+	u32	num_harq_crc_error;
+	
+	u8	end[0];
+
+} mac_phy_burst_t;
+
+typedef struct ori_mac_phy_mcs_s {	/*0x54*/
+	u8	modulation_fec;
+	u8	repetition_code;
+	u8	iuc;
+	u8	feature;
+
+	u32	num_burst;
+	u32	num_burst_error;
+	u32	len_pdu;
+	u32	num_pdu;
+
+} __attribute__((packed)) ori_mac_phy_mcs_t;
+
+typedef struct mac_phy_mcs_s {	/*0x54*/
+	u32	timestamp;
+	
+	u8	start[0];
+
+struct struct_s {
+		u32 num_burst;
+		u32 num_burst_error;
+		u32 len_pdu;
+		u32 num_pdu;
+	} dl[OFDMA_FEC_MODE_CNT][REPETITION_CODING_CNT][MIMO_TYPE_CNT], ul[OFDMA_FEC_MODE_CNT][REPETITION_CODING_CNT][MIMO_TYPE_CNT];
+
+	bool dl_used[OFDMA_FEC_MODE_CNT][REPETITION_CODING_CNT][MIMO_TYPE_CNT];
+	bool ul_used[OFDMA_FEC_MODE_CNT][REPETITION_CODING_CNT][MIMO_TYPE_CNT];
+
+	u8	end[0];
+
+} mac_phy_mcs_t;
+
+#define ZONE_NUMBER	1
+typedef struct mac_phy_zone_s {	/*0x55*/
+	u32	timestamp;
+	
+	u8	start[0];
+
+	u32	zone[ZONE_NUMBER];
+	
+	u8	end[0];
+
+} mac_phy_zone_t;
+
+typedef struct mac_phy_cinr_rssi_s {	/*0x56*/
+	u32	timestamp;
+	
+	u8	start[0];
+
+	s8	cinr_mean;
+	s8	cinr_std_dev;
+	s8	rssi_mean;
+	s8	rssi_std_dev;
+	s8	cinr_a_mean;
+	s8	cinr_b_mean;
+	s8	cinr_main;
+	s8	cinr_diversity;
+	s8	rssi_main;
+	s8	rssi_diversity;
+	s8	preamble_cinr_reuse3;
+	s8	preamble_cinr_reuse1;
+	
+	u8	end[0];
+
+} mac_phy_cinr_rssi_t;
+
+typedef struct mac_phy_temp_adc_s {	/*0x57*/
+	u32	timestamp;
+	
+	u8	start[0];
+
+	s8	temperature;
+	u8	adc;
+	
+	u8	end[0];
+
+} mac_phy_temp_adc_t;
+
+typedef struct mac_phy_ctrl_chan_s {	/*0x58*/
+	u32	timestamp;
+	
+	u8	start[0];
+
+	u32	num_ffb_sent;
+	u32	num_ack_sent;
+	u32	num_irng_sent;
+	u32	num_prng_sent;
+	u32	num_bw_req_rng_sent;
+	u32	num_ho_rng_sent;
+	u32	num_irng_rsp;
+	u32	num_prng_rsp;
+	u32	num_horng_rsp;
+	u32	num_irng_req;
+	u32	num_horng_req;
+	u32	num_irng_req_success;
+	u32	num_horng_req_success;
+	u32	num_cdma_alloc_ie;
+	
+	u8	end[0];
+
+} mac_phy_ctrl_chan_t;
+
+typedef struct mac_phy_dl_statistics_s {	/*0x59*/
+	u32	timestamp;
+	
+	u8	start[0];
+
+	u32	sfid;
+	u16	cid;
+	u16	feature_flag;
+	u32	num_rx_sdu;
+	u32	num_rx_sdu_drop;
+	u32	len_rx_sdu;
+	u32	len_rx_sdu_drop;
+	u32	num_rx_pdu;
+	u32	len_rx_pdu;
+	u32	arq_rx_blocks;
+	u32	arq_rx_blocks_retries;
+	u16	arq_discard_msgs;
+	u16	arq_reset_msgs;
+	u16	arq_sync_losses;
+	
+	u8	end[0];
+
+} mac_phy_dl_statistics_t;
+
+typedef struct mac_phy_ul_statistics_s {	/*0x5a*/
+	u32	timestamp;
+	
+	u8	start[0];
+
+	u32	sfid;
+	u16	cid;
+	u16	feature_flag;
+	u32	num_tx_sdu;
+	u32	num_tx_sdu_drop;
+	u32	len_tx_sdu;
+	u32	len_tx_sdu_drop;
+	u32	num_tx_pdu;
+	u32	len_tx_pdu;
+	u32	bw_req_count;
+	u32	gmsh_out;
+	u32	arq_tx_blocks;
+	u32	arq_tx_blocks_retries;
+	u16	arq_discard_msgs;
+	u16	arq_reset_msgs;
+	u16	arq_sync_losses;
+	
+	u8	end[0];
+
+} mac_phy_ul_statistics_t;
+
+typedef struct mac_handover_s {	/*0x5b*/
+	u32	timestamp;
+	
+	u8	start[0];
+
+	u16	ho_count;
+	u16	ho_fail_count;
+	u16	resync_count;
+	u16	ho_latency;
+	
+	u8	end[0];
+
+} mac_handover_t;
+
+typedef struct ori_mac_neighbor_s {
+	u8	frequency[3];
+	u8	preamble_idx;
+	s8	cinr;
+	s8	rssi;
+	u8	bsid[3];
+	u8	bandwidth;
+	s16	rtd;
+} ori_mac_neighbor_t;
+
+#define MAX_NEIGHBOT_LIST		16
+typedef struct mac_neighbor_s {	/*0x5c*/
+	u32	timestamp;
+
+	u32	nr_list;
+
+	u8	start[0];
+
+	wm_bs_neigh_t list[MAX_NEIGHBOT_LIST];
+	
+	u8	end[0];
+
+} mac_neighbor_t;
+
+typedef struct mac_harq_statistics_s {	/*0x5d*/
+	u32	timestamp;
+	
+	u8	start[0];
+
+	u32	num_dl_harq_retry[8];
+	u32	num_ul_harq_retry[8];
+	
+	u8	end[0];
+
+} mac_harq_statistics_t;
+
+typedef struct mac_net_entry_statistics_s {	/*0x5e*/
+	u32	timestamp;
+	
+	u8	start[0];
+
+	u16	cdma_rng_time;
+	u16	rng_time;
+	u16	sbc_time;
+	u16	pkm_time;
+	u16	reg_time;
+	u16	dsa_time;
+	u16	total_net_entry_time;
+	
+	u8	end[0];
+
+} mac_net_entry_statistics_t;
+
+typedef struct mac_report_s {
+	mac_pdu_statistics_t			pdu_statistics;
+	mac_phy_mac_basic_t			phy_mac_basic;
+	mac_power_ctrl_t				power_ctrl;
+	mac_phy_burst_t				phy_burst;
+	mac_phy_mcs_t					phy_mcs;
+	mac_phy_zone_t				phy_zone;
+	mac_phy_cinr_rssi_t			phy_cinr_rssi;
+	mac_phy_temp_adc_t			phy_temp_adc;
+	mac_phy_ctrl_chan_t			phy_ctrl_chan;
+	mac_phy_dl_statistics_t		phy_dl_stat;
+	mac_phy_ul_statistics_t		phy_ul_stat;
+	mac_handover_t				handover;
+	mac_neighbor_t				neighbor;
+	mac_harq_statistics_t			harq_stat;
+	mac_net_entry_statistics_t	net_entry_stat;
+
+} mac_report_t;
+
+typedef struct wimax_s {
+	pthread_mutex_t		using_lock[WM_USING_LOCK_ENTRIES];
+	pthread_mutex_t		fsm_lock;
+
+	wm_device_info_t	dev_info;
+
+	struct list2_head	scan_list;	/*link wm_nsp_s->list*/
+	struct list2_head	subs_list;	/*link wm_subscription_info_t->list*/
+
+	wm_scan_t 					scan;
+	wm_connect_t				conn;
+	wm_association_start_t		asso_start;
+	wm_association_complete_t	asso_comp;
+	wm_disconnect_ind_t			disconn_ind;
+	wm_handover_start_t			ho_start;
+	wm_handover_complete_t		ho_comp;
+	wm_connect_complete_t		conn_comp;
+
+} wimax_t;
+
+inline static void wm_in_wimax(struct wimax_s *wm, int entry)
+{
+	xfunc_in("entry=%d", entry);
+	pthread_mutex_lock(&wm->using_lock[entry]);
+	xfunc_out("entry=%d", entry);
+}
+inline static void wm_out_wimax(struct wimax_s *wm, int entry)
+{
+	xfunc_in("entry=%d", entry);
+	pthread_mutex_unlock(&wm->using_lock[entry]);
+	xfunc_out("entry=%d", entry);
+}
+
+void wm_cleanup_device(int dev_idx);
+void wm_open_device(int dev_idx);
+void wm_close_device(int dev_idx);
+void wm_init_scan(int dev_idx);
+void wm_deinit_scan(int dev_idx);
+int wm_init_device_info(int dev_idx);
+int wm_sync_subscription(int dev_idx);
+int wm_set_scan_type(int dev_idx, wimax_scan_type_t type);
+int wm_active_scan_interval(int dev_idx, u32 interval_sec);
+int wm_req_scan(int dev_idx);
+int wm_net_search_scan(int dev_idx, wimax_scan_type_t scantype);
+int wm_cancel_scan(int dev_idx);
+void wm_clean_scan_info(int dev_idx);
+int wm_req_interval_scan(int dev_idx, int interval_milisec);
+int wm_update_subscription(int dev_idx, u8 *buf, int len);
+wm_subscription_info_t *wm_get_subscription(int dev_idx, u8 subs_idx, u8 *hnspid);
+wm_subscription_info_t *wm_get_activated_subs(int dev_idx);
+int wm_combine_level(int dev_idx, int c0, int c1);
+u8 wm_convert_cinr(s8 cinr);
+u8 wm_convert_rssi(s8 rssi);
+int wm_get_network_type(struct wimax_s *wm, u8 *nspid);
+struct wm_nsp_s *wm_lookup_nsp_by_name(struct wimax_s *wm, u8 *nsp_name);
+struct wm_nsp_s *wm_lookup_nsp_by_id(struct wimax_s *wm, u8 *nspid);
+int wm_connect_network(int dev_idx, u8 *hnspid, u8 *vnspid);
+int wm_re_connect_network(int dev_idx);
+int wm_cr801_re_connect(int dev_idx);
+int wm_get_dhcp_info(int dev_idx);
+int wm_disconnect_network(int dev_idx, int timeout_sec);
+int wm_get_rf_state(int dev_idx, rf_stat_t *rf_stat);
+int wm_set_rf_state(int dev_idx, rf_stat_t rf_stat, int timeout_sec);
+int wm_set_capability(int dev_idx, u32 capability);
+int wm_report_capability(int dev_idx, u8 *buf, int len);
+int wm_set_eap(int dev_idx, bool enable);
+int wm_get_netinfo(int dev_idx, struct wm_net_info_s *net_info);
+int wm_get_linkinfo(int dev_idx, struct wm_link_status_s *link_s);
+int wm_get_rf_info(int dev_idx, GCT_API_RF_INFORM_P rf_info);
+int wm_retrieve_mac_pdu_statistics(mac_pdu_statistics_t *p, u8 *buf, int len);
+int wm_retrieve_mac_phy_mac_basic(mac_phy_mac_basic_t *p, u8 *buf, int len);
+int wm_retrieve_mac_power_ctrl(mac_power_ctrl_t *p, u8 *buf, int len);
+int wm_retrieve_mac_phy_burst(mac_phy_burst_t *p, u8 *buf, int len);
+int wm_retrieve_mac_phy_mcs(mac_phy_mcs_t *p, u8 *buf, int len);
+int wm_retrieve_mac_phy_zone(mac_phy_zone_t *p, u8 *buf, int len);
+int wm_retrieve_mac_phy_cinr_rssi(mac_phy_cinr_rssi_t *p, u8 *buf, int len);
+int wm_retrieve_mac_phy_temp_adc(mac_phy_temp_adc_t *p, u8 *buf, int len);
+int wm_retrieve_mac_phy_ctrl_chan(mac_phy_ctrl_chan_t *p, u8 *buf, int len);
+int wm_retrieve_mac_phy_dl_statistics(mac_phy_dl_statistics_t *p, u8 *buf, int len);
+int wm_retrieve_mac_phy_ul_statistics(mac_phy_ul_statistics_t *p, u8 *buf, int len);
+int wm_retrieve_mac_handover(mac_handover_t *p, u8 *buf, int len);
+int wm_retrieve_mac_neighbor(mac_neighbor_t *p, u8 *buf, int len, u8 *bsid);
+int wm_retrieve_mac_harq_statistics(mac_harq_statistics_t *p, u8 *buf, int len);
+int wm_retrieve_mac_net_entry_statistics(mac_net_entry_statistics_t *p, u8 *buf, int len);
+int wm_set_run_mode(int dev_idx, int mode);
+int wm_get_neighbor_list(int dev_idx, wm_bs_neigh_t *list, int *list_cnt);
+int wm_notification(int dev_idx, char *buf, int len);
+int wm_ind_sf_mode(int dev_idx, u8 *buf, int len);
+int wm_disable_sf_mode(int dev_idx);
+bool wm_compare_nsp(wm_nsp_identifier_t *nsp, wm_nsp_identifier_t *nsp2);
+int wm_reset_selected_subsctiption(int dev_idx, wm_nsp_identifier_t *hnspid);
+int wm_report_full_reentry(int dev_idx, u8 *buf, int len);
+int wm_cmd_mac_state(int dev_idx, GCT_API_CMD_MAC_STATE_TYPE type);
+int wm_set_idle_mode_timeout(int dev_idx, u16 timeoutSec);
+int wm_get_phy_mac_basic(int dev_idx, GCT_API_MAC_PHY_MAC_BASIC_P pData);
+int wm_get_phy_mcs(int dev_idx, GCT_API_MAC_PHY_MCS_P pData);
+int wm_get_phy_cinr_rssi(int dev_idx, GCT_API_MAC_PHY_CINR_RSSI_P pData);
+
+#endif
diff --git a/sdk/wm_ioctl.h b/sdk/wm_ioctl.h
new file mode 100644
index 0000000..7ab47f9
--- /dev/null
+++ b/sdk/wm_ioctl.h
@@ -0,0 +1,92 @@
+// 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.
+
+#if !defined(WM_IOCTL_H_20080715)
+#define WM_IOCTL_H_20080715
+#if !defined(__KERNEL__)
+#include <net/if.h>
+#endif
+
+#define NETLINK_WIMAX	31
+
+#define SIOCWMIOCTL			SIOCDEVPRIVATE
+
+#define SIOCG_DATA			0x8D10
+#define SIOCS_DATA			0x8D11
+
+enum {
+	SIOC_DATA_FSM,
+	SIOC_DATA_NETLIST,
+	SIOC_DATA_CONNNSP,
+	SIOC_DATA_CONNCOMP,
+	SIOC_DATA_PROFILEID,
+
+	SIOC_DATA_END
+};
+
+#define SIOC_DATA_MAX			16
+
+/* FSM */
+enum {
+	M_INIT = 0,
+	M_OPEN_OFF,
+	M_OPEN_ON,
+	M_SCAN,
+	M_CONNECTING,
+	M_CONNECTED,
+	M_FSM_END,
+	
+	C_INIT = 0,
+	C_CONNSTART,
+	C_ASSOCSTART,
+	C_RNG,
+	C_SBC,
+	C_AUTH,
+	C_REG,
+	C_DSX,
+	C_ASSOCCOMPLETE,
+	C_CONNCOMPLETE,
+	C_FSM_END,
+
+	D_INIT = 0,
+	D_READY,
+	D_LISTEN,
+	D_IPACQUISITION,
+
+	END_FSM
+
+};
+
+typedef struct fsm_s {
+	int		m_status;	/*main status*/
+	int		c_status;	/*connection status*/
+	int		d_status;	/*oma-dm status*/
+
+} fsm_t;
+
+typedef struct data_s {
+	int		size;
+	void	*buf;
+
+} data_t;
+
+typedef struct wm_req_s {
+	union {
+		char	ifrn_name[IFNAMSIZ];
+	} ifr_ifrn;
+
+	unsigned short	cmd;
+
+	unsigned short	data_id;
+	data_t	data;
+
+/*NOTE: sizeof(struct wm_req_s) must be less than sizeof(struct ifreq).*/
+} wm_req_t;
+
+#ifndef ifr_name
+#define ifr_name	ifr_ifrn.ifrn_name
+#endif
+
+#endif
+