blob: 4919992edd40727ba4acb8084511eb51ce1191d5 [file] [log] [blame]
// Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "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;
}