int bastet_comm_write(u8 *msg, u32 len)
{
    BASTET_MSG_STRU *pMsg = NULL;
    VOS_UINT32 ulLength = 0;

    if (NULL == msg) {
        return -1;
    }

    ulLength = sizeof(BASTET_MSG_STRU) + BST_MAX_WRITE_PAYLOAD - 4;
    pMsg = (BASTET_MSG_STRU *)PS_ALLOC_MSG_WITH_HEADER_LEN(ACPU_PID_BASTET_COMM, ulLength);
    if (NULL == pMsg) {
        BASTET_LOGE("PS_ALLOC_MSG_WITH_HEADER_LEN failed");
        return -1;
    }
    pMsg->ulReceiverPid = UEPS_PID_BASTET;
    PS_MEM_CPY((VOS_VOID*)pMsg->aucValue, msg, len);

    pMsg->usLen = len;

    if (PS_SEND_MSG(ACPU_PID_BASTET_COMM, pMsg) != 0) {
        BASTET_LOGE("PS_SEND_MSG failed");
        return -1;
    }

    return 0;
}
/*
 * Function is called when application starts bastet proxy.
 */
int start_bastet_sock(struct bst_set_sock_sync_delay *init_prop)
{
	int err = 0;
	struct sock *sk;
	struct bst_sock_id *guide = &init_prop->guide;

	sk = get_sock_by_fd_pid(guide->fd, guide->pid);
	if (NULL == sk) {
		BASTET_LOGE("can not find sock by fd: %d pid: %d", guide->fd, guide->pid);
		return -ENOENT;
	}

	if (TCP_ESTABLISHED != sk->sk_state) {
		BASTET_LOGE("sk: %p sk_state is not TCP_ESTABLISHED", sk);
		sock_put(sk);
		return -EPERM;
	}

	if (tcp_sk(sk)->repair) {
		BASTET_LOGE("sk: %p in repair mode", sk);
		sock_put(sk);
		return -EPERM;
	}

	BASTET_LOGI("sk: %p", sk);

	err = do_start_bastet_sock(sk, init_prop);
	sock_put(sk);
	return err;
}
int bastet_sync_prop_stop(struct bst_sock_comm_prop *comm_prop)
{
	struct sock *sk;
	struct bastet_sock *bsk;

	sk = get_sock_by_comm_prop(comm_prop);
	if (NULL == sk) {
		BASTET_LOGE("can not find sock by lport: %d, lIp: %pI4, rport: %d, rIp: %pI4",
					comm_prop->local_port, &comm_prop->local_ip,
					comm_prop->remote_port, &comm_prop->remote_ip);
		return -ENOENT;
	}

	if (sk->sk_state == TCP_TIME_WAIT) {
		BASTET_LOGE("sk: %p not expected time wait sock", sk);
		inet_twsk_put(inet_twsk(sk));
		return -EPERM;
	}
	BASTET_LOGI("sk: %p", sk);
	bsk = sk->bastet;
	if (bsk) {
		if (bsk->bastet_sock_state != BST_SOCK_NOT_USED) {
			bsk->user_ctrl = BST_USER_START;
			bsk->bastet_sock_state = BST_SOCK_VALID;
			setup_sock_sync_delay_timer(sk);
		}
	}

	sock_put(sk);
	return 0;
}
/*
 * Set sock sync properties.
 */
int set_tcp_sock_sync_prop(struct bst_set_sock_sync_prop *set_prop)
{
	int err = 0;
	struct sock *sk;
	struct bastet_sock *bsk;
	struct bst_sock_comm_prop *guide = &set_prop->guide;

	sk = get_sock_by_comm_prop(guide);
	if (NULL == sk) {
		BASTET_LOGE("can not find sock by lport: %d, lIp: %pI4, rport: %d, rIp: %pI4",
					guide->local_port, &guide->local_ip,
					guide->remote_port, &guide->remote_ip);
		return -ENOENT;
	}

	if (sk->sk_state == TCP_TIME_WAIT) {
		BASTET_LOGE("sk: %p not expected time wait sock", sk);
		inet_twsk_put(inet_twsk(sk));
		return -EPERM;
	}

	bsk = sk->bastet;
	if (NULL == bsk) {
		BASTET_LOGE("sk: %p not expected bastet null", sk);
		err = -EPERM;
		goto out_put;
	}

	BASTET_LOGI("sk: %p", sk);

	spin_lock_bh(&sk->sk_lock.slock);

	if (NULL != bsk->sync_p) {
		BASTET_LOGE("sk: %p has a pending sock set", sk);
		err = -EPERM;
		goto out_unlock;
	}

	cancel_sock_bastet_timer(sk);

	if (sock_owned_by_user(sk)) {
		err = setup_sock_sync_set_timer(sk, &set_prop->sync_prop);
		goto out_unlock;
	}

	sock_set_internal(sk, &set_prop->sync_prop);

out_unlock:
	spin_unlock_bh(&sk->sk_lock.slock);

	adjust_traffic_flow_by_sock(sk, set_prop->sync_prop.tx, set_prop->sync_prop.rx);

out_put:
	sock_put(sk);
	return err;
}
/*
 * Close sock, when modem bastet fails this sock.
 */
int set_tcp_sock_closed(struct bst_sock_comm_prop *guide)
{
	int err = 0;
	struct sock *sk;
	struct bastet_sock *bsk;

	sk = get_sock_by_comm_prop(guide);
	if (NULL == sk) {
		BASTET_LOGE("can not find sock by lport: %d, lIp: %pI4, rport: %d, rIp: %pI4",
					guide->local_port, &guide->local_ip,
					guide->remote_port, &guide->remote_ip);
		return -ENOENT;
	}

	if (sk->sk_state == TCP_TIME_WAIT) {
		BASTET_LOGE("sk: %p not expected time wait sock", sk);
		inet_twsk_put(inet_twsk(sk));
		return -EPERM;
	}

	bsk = sk->bastet;
	if (NULL == bsk) {
		BASTET_LOGE("sk: %p not expected bastet null", sk);
		err = -EPERM;
		goto out_put;
	}

	BASTET_LOGI("sk: %p", sk);

	spin_lock_bh(&sk->sk_lock.slock);

	if (BST_SOCK_INVALID != bsk->bastet_sock_state
		&& BST_SOCK_UPDATING != bsk->bastet_sock_state) {
		BASTET_LOGE("sk: %p sync_current_state: %d not expected", sk, bsk->bastet_sock_state);
		goto out_unlock;
	}

	cancel_sock_bastet_timer(sk);

	bsk->bastet_sock_state = BST_SOCK_NOT_USED;

	if (sock_owned_by_user(sk)) {
		setup_sock_sync_close_timer(sk);
		goto out_unlock;
	}

	set_sock_close_internal(sk);

out_unlock:
	spin_unlock_bh(&sk->sk_lock.slock);

out_put:
	sock_put(sk);
	return err;
}
int bastet_sync_prop_start(struct bst_set_sock_sync_prop *set_prop)
{
	int err = 0;
	struct sock *sk;
	struct bastet_sock *bsk;
	struct bst_sock_comm_prop *guide = &set_prop->guide;

	sk = get_sock_by_comm_prop(guide);
	if (NULL == sk) {
		BASTET_LOGE("can not find sock by lport: %d, lIp: %pI4, rport: %d, rIp: %pI4",
					guide->local_port, &guide->local_ip,
					guide->remote_port, &guide->remote_ip);
		return -ENOENT;
	}

	if (sk->sk_state == TCP_TIME_WAIT) {
		BASTET_LOGE("sk: %p not expected time wait sock", sk);
		inet_twsk_put(inet_twsk(sk));
		return -EPERM;
	}

	bsk = sk->bastet;
	if (NULL == bsk) {
		BASTET_LOGE("sk: %p not expected bastet null", sk);
		err = -EPERM;
		goto out_put;
	}

	BASTET_LOGI("sk: %p", sk);

	if (NULL != bsk->sync_p) {
		BASTET_LOGE("sk: %p has a pending sock set", sk);
		err = -EPERM;
		goto out;
	}

	sock_set_internal(sk, &set_prop->sync_prop);
	bastet_sync_prop_cancel(sk);
	bsk->flag = true;
	BASTET_LOGI("wake up bastet wq");
	wake_up_interruptible(&bsk->wq);

out:
	adjust_traffic_flow_by_sock(sk, set_prop->sync_prop.tx, set_prop->sync_prop.rx);

out_put:
	sock_put(sk);
	return err;
}
/*
 * Generate bastet sock in sock struct.
 */
static int create_bastet_sock(struct sock *sk, struct bst_set_sock_sync_delay *init_prop)
{
	struct bastet_sock *bsk;

	bsk = kmalloc(sizeof(*bsk), GFP_KERNEL);
	if (NULL == bsk) {
		BASTET_LOGE("kmalloc failed");
		return -ENOMEM;
	}

	bsk->bastet_sock_state = BST_SOCK_NOT_USED;
	bsk->bastet_timer_event = BST_TMR_EVT_INVALID;
	bsk->user_ctrl = BST_USER_STOP;
	bsk->fd = init_prop->guide.fd;
	bsk->pid = init_prop->guide.pid;
	bsk->proxy_id = init_prop->proxy_id;
	bsk->bastet_timeout = 0;
	bsk->last_sock_active_time_point = jiffies;
	bsk->sync_p = NULL;
	bsk->need_repair = 0;

	bsk->delay_sync_time_section = msecs_to_jiffies(init_prop->hold_time);

	setup_timer(&bsk->bastet_timer, bastet_sock_bastet_timeout, (unsigned long)sk);

	skb_queue_head_init(&bsk->recv_queue);
	bsk->recv_len = 0;
	init_waitqueue_head(&bsk->wq);
	bsk->flag = false;

	sk->bastet = bsk;
	return 0;
}
/*
 * Get modem id and rab id.
 */
int get_modem_rab_id(struct bst_modem_rab_id *info)
{
    struct net_device *dev;
    RNIC_SPEC_CTX_STRU *spec_net_card;
    RNIC_PDP_CTX_STRU *pdp_addr;
    RNIC_NETCARD_DEV_INFO_STRU *priv;

    if (NULL == info) {
        return -EINVAL;
    }

    dev = dev_get_by_name(&init_net, cur_netdev_name);
    if (NULL == dev) {
        return -ENOENT;
    }

    priv = (RNIC_NETCARD_DEV_INFO_STRU *)netdev_priv(dev);

    spec_net_card = RNIC_GetSpecNetCardCtxAddr(priv->enRmNetId);
    pdp_addr = &spec_net_card->stPdpCtx;

    if (RNIC_PDP_REG_STATUS_ACTIVE != pdp_addr->stIpv4PdpInfo.enRegStatus) {
        BASTET_LOGE("Ipv4 pdp reg status inactive");
        return -EPERM;
    }

    info->modem_id = spec_net_card->enModemId;
    /* Bastet only running in IPv4 mode,
     * so, get IPv4 Pdp info */
    info->rab_id = pdp_addr->stIpv4PdpInfo.ucRabId;

    return 0;
}
int bastet_ccorereset_cbfun(DRV_RESET_CB_MOMENT_E eparam, int userdata)
{
    if (MDRV_RESET_CB_BEFORE == eparam) {
        BASTET_LOGE("MDRV_RESET_CB_BEFORE");
        bastet_modem_reset_notify();
    }

    return BSP_RESET_OK;
}
/*
 * Function is called when application stops bastet proxy.
 */
int stop_bastet_sock(struct bst_sock_id *guide)
{
	struct sock *sk;
	struct bastet_sock *bsk;
	u8 sync_state;

	sk = get_sock_by_fd_pid(guide->fd, guide->pid);
	if (NULL == sk) {
		BASTET_LOGE("can not find sock by fd: %d pid: %d", guide->fd, guide->pid);
		return -ENOENT;
	}

	bsk = sk->bastet;
	if (NULL == bsk) {
		BASTET_LOGE("sk: %p not expected bastet null", sk);
		sock_put(sk);
		return -EPERM;
	}

	BASTET_LOGI("sk: %p", sk);

	spin_lock_bh(&sk->sk_lock.slock);

	bsk->user_ctrl = BST_USER_STOP;

	sync_state = bsk->bastet_sock_state;
	switch (sync_state) {
	case BST_SOCK_VALID:
		bsk->bastet_sock_state = BST_SOCK_NOT_USED;

		cancel_sock_bastet_timer(sk);
		break;
	case BST_SOCK_INVALID:
		request_sock_sync(sk);
		break;
	default:
		break;
	}

	spin_unlock_bh(&sk->sk_lock.slock);

	sock_put(sk);
	return 0;
}
/*
 * Set socket sync hold time
*/
int set_sock_sync_hold_time(struct bst_set_sock_sync_delay hold_delay)
{
	struct sock *sk = NULL;
	struct bastet_sock *bsk = NULL;
	unsigned long orig_delay = 0;
	unsigned long expire = 0;

	sk = get_sock_by_fd_pid(hold_delay.guide.fd, hold_delay.guide.pid);
	if (NULL == sk) {
		BASTET_LOGE("can not find sock by fd: %d pid: %d", hold_delay.guide.fd, hold_delay.guide.pid);
		return -ENOENT;
	}
	bsk = sk->bastet;
	if (NULL == bsk) {
		BASTET_LOGE("sk: %p not expected bastet null", sk);
		sock_put(sk);
		return -EPERM;
	}
	BASTET_LOGI("hold_time=%u", hold_delay.hold_time);
	orig_delay = bsk->delay_sync_time_section;
	bsk->delay_sync_time_section = msecs_to_jiffies(hold_delay.hold_time);
	if (timer_pending(&bsk->bastet_timer)) {
		if (orig_delay < bsk->delay_sync_time_section) {
			BASTET_LOGI("screen off to on");
			expire = bsk->last_sock_active_time_point + bsk->delay_sync_time_section;
		} else {
			BASTET_LOGI("screen on to off");
			if (time_after(jiffies, bsk->last_sock_active_time_point + bsk->delay_sync_time_section)) {
				BASTET_LOGI("need to timeout right now");
				expire = jiffies;
			} else {
				expire = bsk->last_sock_active_time_point + bsk->delay_sync_time_section;
			}
		}
		bsk->bastet_timeout = expire;
		mod_timer(&bsk->bastet_timer, expire);
	}
	sock_put(sk);

	return 0;
}
/*
 * Function is called when application prepare bastet proxy.
 */
int prepare_bastet_sock(struct bst_set_sock_sync_delay *sync_prop)
{
	int err = 0;
	struct sock *sk;
	struct bastet_sock *bsk;

	sk = get_sock_by_fd_pid(sync_prop->guide.fd, sync_prop->guide.pid);
	if (NULL == sk) {
		BASTET_LOGE("can not find sock by fd: %d pid: %d", sync_prop->guide.fd, sync_prop->guide.pid);
		return -ENOENT;
	}

	if (TCP_ESTABLISHED != sk->sk_state) {
		BASTET_LOGE("sk: %p sk_state is not TCP_ESTABLISHED", sk);
		sock_put(sk);
		return -EPERM;
	}

	if (tcp_sk(sk)->repair) {
		BASTET_LOGE("sk: %p in repair mode", sk);
		sock_put(sk);
		return -EPERM;
	}

	BASTET_LOGI("sk: %p", sk);

	bsk = sk->bastet;
	if (NULL == bsk) {
		err = create_bastet_sock(sk, sync_prop);
		if (err < 0) {
			sock_put(sk);
			return err;
		}
		bsk = sk->bastet;
	}

	sock_put(sk);

	return err;
}
/*
 * BST_TMR_REQ_SOCK_SYNC timeout.
 * Request sync time is up, but sock sync properties still invalid.
 * Usually, daemon should set sock sync properties before timeout.
 */
static void request_sock_bastet_timeout(struct sock *sk)
{
	struct bastet_sock *bsk = sk->bastet;

	/* Accurating time */
	if (time_after(bsk->bastet_timeout, jiffies)) {
		sk_reset_timer(sk, &bsk->bastet_timer, bsk->bastet_timeout);
		return;
	}

	/* We must reset timer event, bastet_delay_sock_sync_notify depends on it
	 * this code must be put after accurating time
	 */
	bsk->bastet_timer_event = BST_TMR_EVT_INVALID;

	if (BST_SOCK_UPDATING != bsk->bastet_sock_state){
		BASTET_LOGE("sk: %p state: %d not expected", sk, bsk->bastet_sock_state);
		return;
	}

	/* Try reuqest timer again */
	if (bsk->sync_retry) {
		request_sock_sync(sk);
		return;
	}

	/* If goes here, bastet sock sync failed,
	 * Send or recv data anyway. */
	BASTET_LOGE("sk: %p request timeout", sk);

	if (BST_USER_START == bsk->user_ctrl) {
		/* Before send or recv data, set state to BST_SOCK_VALID*/
		bsk->bastet_sock_state = BST_SOCK_VALID;
		process_sock_send_and_recv(sk);
	} else {
		bsk->bastet_sock_state = BST_SOCK_NOT_USED;
	}
}
/*
 * Get sock common properties.
 */
int get_tcp_sock_comm_prop(struct bst_get_sock_comm_prop *get_prop)
{
	struct sock *sk;
	struct bst_sock_id *guide = &get_prop->guide;

	sk = get_sock_by_fd_pid(guide->fd, guide->pid);
	if (NULL == sk) {
		BASTET_LOGE("can not find sock by fd: %d pid: %d", guide->fd, guide->pid);
		return -ENOENT;
	}

	if (TCP_ESTABLISHED != sk->sk_state) {
		BASTET_LOGE("sk: %p sk_state not expected", sk);
		sock_put(sk);
		return -EPERM;
	}

	BASTET_LOGI("sk: %p", sk);

	bastet_get_comm_prop(sk, &get_prop->comm_prop);
	sock_put(sk);
	return 0;
}
void bastet_comm_recv(MsgBlock *pMsg)
{
    u32 len = 0;
    BASTET_MSG_STRU *pTmpMsg = (BASTET_MSG_STRU *)pMsg;

    if (NULL == pMsg) {
        BASTET_LOGE("MsgBlock is empty");
        return;
    }

    len = pTmpMsg->usLen;
    if (len > BST_MAX_WRITE_PAYLOAD) {
        len = BST_MAX_WRITE_PAYLOAD;
    }
    post_indicate_packet(BST_IND_HISICOM, pTmpMsg->aucValue, len);
}
/*
 * BST_TMR_SET_SOCK_SYNC timeout.
 */
static void set_sock_bastet_timeout(struct sock *sk)
{
	struct bastet_sock *bsk = sk->bastet;

	bsk->bastet_timer_event = BST_TMR_EVT_INVALID;

	if (NULL == bsk->sync_p) {
		BASTET_LOGE("sk: %p not expected null sync prop", sk);
		return;
	}

	sock_set_internal(sk, bsk->sync_p);

	kfree(bsk->sync_p);
	bsk->sync_p = NULL;
}
int get_tcp_bastet_sock_state(struct bst_get_bastet_sock_state *get_prop)
{
	struct sock *sk;
	struct bst_sock_id *guide = &get_prop->guide;

	sk = get_sock_by_fd_pid(guide->fd, guide->pid);
	if (NULL == sk) {
		BASTET_LOGE("can not find sock by fd: %d pid: %d", guide->fd, guide->pid);
		return -ENOENT;
	}
	BASTET_LOGI("sk: %p", sk);

	get_prop->sync_state = get_bastet_sock_state(sk);

	sock_put(sk);
	return 0;
}
/*
 * Bastet sock timeout, include all bastet time events.
 */
static void bastet_sock_bastet_timeout(unsigned long data)
{
	int event;
	struct sock *sk = (struct sock *)data;
	struct bastet_sock *bsk = sk->bastet;

	BASTET_LOGI("sk: %p time event: %d", sk, bsk->bastet_timer_event);

	bh_lock_sock(sk);

	/* Include in lock */
	event = bsk->bastet_timer_event;

	if (sock_owned_by_user(sk)) {
		/* Try again later */
		if (BST_TMR_DELAY_SOCK_SYNC == event) {
			bastet_wakelock_acquire_timeout(BST_SKIP_SOCK_OWNER_TIME + BST_WAKELOCK_TIMEOUT);
		}
		sk_reset_timer(sk, &bsk->bastet_timer, jiffies + BST_SKIP_SOCK_OWNER_TIME);
		goto out_unlock;
	}

	switch(event){
	case BST_TMR_REQ_SOCK_SYNC:
		request_sock_bastet_timeout(sk);
		break;
	case BST_TMR_SET_SOCK_SYNC:
		set_sock_bastet_timeout(sk);
		break;
	case BST_TMR_DELAY_SOCK_SYNC:
		delay_sock_bastet_timeout(sk);
		break;
	case BST_TMR_CLOSE_SOCK:
		close_sock_bastet_timeout(sk);
		break;
	default:
		BASTET_LOGE("sk: %p invalid time event: %d", sk, event);
		break;
	}

	sk_mem_reclaim(sk);
out_unlock:
	bh_unlock_sock(sk);
	sock_put(sk);
}
/*
 * BST_TMR_DELAY_SOCK_SYNC timeout.
 * If sock is ready, get sock sync properties and post them to daemon
 */
static void delay_sock_bastet_timeout(struct sock *sk)
{
	int err;
	struct bst_set_sock_sync_prop sock_p;
	struct bastet_sock *bsk = sk->bastet;

	/* Accurating time */
	if (time_after(bsk->bastet_timeout, jiffies)) {
		sk_reset_timer(sk, &bsk->bastet_timer, bsk->bastet_timeout);
		return;
	}

	/* We must reset timer event, bastet_delay_sock_sync_notify depends on it
	 * this code must be put after accurating time
	 */
	bsk->bastet_timer_event = BST_TMR_EVT_INVALID;

	/* In repair mode or userspace needs repair, do not sync sock */
	if (unlikely(tcp_sk(sk)->repair || bsk->need_repair)) {
		BASTET_LOGE("sk: %p in repair mode", sk);
		return;
	}

	if (TCP_ESTABLISHED != sk->sk_state) {
		BASTET_LOGE("sk: %p sk_state is not TCP_ESTABLISHED", sk);
		return;
	}

	if (BST_SOCK_VALID != bsk->bastet_sock_state) {
		BASTET_LOGE("sk: %p state: %d not expected", sk, bsk->bastet_sock_state);
		return;
	}

	/* Sock owner has used since last setup */
	if (time_after(bsk->last_sock_active_time_point + bsk->delay_sync_time_section, jiffies)) {
		setup_sock_sync_delay_timer(sk);
		return;
	}

	/* Sock owner has some data unacked,
	 * Coming ack would trigger delay timer again */
	if (!tcp_write_queue_empty(sk)) {
		BASTET_LOGI("sk: %p has sent data not acked", sk);
		post_indicate_packet(BST_IND_TRIGGER_THAW, &bsk->pid, sizeof(pid_t));
		return;
	}

	/* Sock owner has some data to recv, do not sync.
	 * If sock owner has none recv action,
	 * delay timer should be stopped. */
	if (!skb_queue_empty(&sk->sk_receive_queue)) {
		BASTET_LOGI("sk: %p has received data in queue", sk);
		bsk->last_sock_active_time_point = jiffies;
		setup_sock_sync_delay_timer(sk);
		post_indicate_packet(BST_IND_TRIGGER_THAW, &bsk->pid, sizeof(pid_t));
		return;
	}

	memset(&sock_p, 0, sizeof(struct bst_set_sock_sync_prop));
	bastet_get_comm_prop(sk, &sock_p.guide);
	bastet_get_sock_prop(sk, &sock_p.sync_prop);

	err = post_indicate_packet(BST_IND_SOCK_SYNC_PROP, &sock_p, sizeof(sock_p));
	if (!err) {
		/* if post success */
		bsk->bastet_sock_state = BST_SOCK_INVALID;
	}
}