int IPACM_LanToLan::del_offload_link(ipa_ip_type iptype, IPACM_Lan* client, IPACM_Lan* peer, offload_link_info* link)
{
	if(client == NULL || peer == NULL || link == NULL)
	{
		IPACMERR("Either iface or link is NULL.\n");
		return IPACM_FAILURE;
	}

	IPACMDBG_H("Delete an offload link for IP type: %d\n", iptype);

	int res = IPACM_SUCCESS;

	if(client->del_lan2lan_flt_rule(iptype, link->flt_rule_hdl) == IPACM_FAILURE)
	{
		IPACMERR("Failed to delete flt rule.\n");
		res = IPACM_FAILURE;
	}

	if(peer->del_lan2lan_rt_rule(iptype, link->rt_rule_hdl) == IPACM_FAILURE)
	{
		IPACMERR("Failed to delete rt rules.\n");
		res = IPACM_FAILURE;
	}

	if(peer->del_lan2lan_hdr(iptype, link->hdr_hdl) == IPACM_FAILURE)
	{
		IPACMERR("Failed to delete header.\n");
		res = IPACM_FAILURE;
	}

	return res;
}
int IPACM_LanToLan::clear_peer_list(client_info* client)
{
	if(client == NULL)
	{
		IPACMERR("Client is NULL.\n");
		return IPACM_FAILURE;
	}

	bool err_flag;
	peer_info_list::iterator client_it;
	peer_info_list::iterator peer_it;
	client_info* peer;

	for(client_it = client->peer.begin(); client_it != client->peer.end(); client_it++)
	{
		err_flag = true;
		peer = client_it->peer_pointer;
		for(peer_it = peer->peer.begin(); peer_it != peer->peer.end(); peer_it++)
		{
			if(peer_it->peer_pointer == client)
			{
				peer->peer.erase(peer_it);
				err_flag = false;
				break;
			}
		}
		if(err_flag == true)
		{
			IPACMERR("Failed to find peer info.\n");
			return IPACM_FAILURE;
		}
	}
	client->peer.clear();
	return IPACM_SUCCESS;
}
bool IPACM_Routing::ModifyRoutingRule(struct ipa_ioc_mdfy_rt_rule *mdfyRules)
{
	int retval = 0, cnt;

	if (!DeviceNodeIsOpened())
	{
		IPACMERR("Device is not opened\n");
		return false;
	}

	retval = ioctl(m_fd, IPA_IOC_MDFY_RT_RULE, mdfyRules);
	if (retval)
	{
		IPACMERR("Failed modifying routing rules %p\n", mdfyRules);
		return false;
	}

	for(cnt=0; cnt<mdfyRules->num_rules; cnt++)
	{
		if(mdfyRules->rules[cnt].status != 0)
		{
			IPACMERR("Unable to modify rule: %d\n", cnt);
		}
	}

	IPACMDBG_H("Modified routing rules %p\n", mdfyRules);
	return true;
}
Exemple #4
0
int IPACM_Config::Init(void)
{
	/* Read IPACM Config file */
	char	IPACM_config_file[IPA_MAX_FILE_LEN];
	IPACM_conf_t	*cfg;
	cfg = (IPACM_conf_t *)malloc(sizeof(IPACM_conf_t));
	if(cfg == NULL)
	{
		IPACMERR("Unable to allocate cfg memory.\n");
		return IPACM_FAILURE;
	}
	uint32_t subnet_addr;
	uint32_t subnet_mask;
	int i, ret = IPACM_SUCCESS;
	struct in_addr in_addr_print;

	m_fd = open(DEVICE_NAME, O_RDWR);
	if (0 > m_fd)
	{
		IPACMERR("Failed opening %s.\n", DEVICE_NAME);
	}
	strncpy(IPACM_config_file, "/etc/IPACM_cfg.xml", sizeof(IPACM_config_file));

	IPACMDBG_H("\n IPACM XML file is %s \n", IPACM_config_file);
	if (IPACM_SUCCESS == ipacm_read_cfg_xml(IPACM_config_file, cfg))
	{
		IPACMDBG_H("\n IPACM XML read OK \n");
	}
	else
	{
		IPACMERR("\n IPACM XML read failed \n");
		ret = IPACM_FAILURE;
		goto fail;
	}

	/* Check wlan AP-AP access mode configuration */
	if (cfg->num_wlan_guest_ap == 2)
	{
		IPACMDBG_H("IPACM_Config::Both wlan APs can not be configured in guest ap mode. \n");
		IPACMDBG_H("IPACM_Config::configure both APs in full access mode or at least one in guest ap mode. \n");
		ret = IPACM_FAILURE;
		goto fail;
	}
	/* Construct IPACM Iface table */
	ipa_num_ipa_interfaces = cfg->iface_config.num_iface_entries;
	if (iface_table != NULL)
	{
		free(iface_table);
		iface_table = NULL;
		IPACMDBG_H("RESET IPACM_Config::iface_table\n");
	}
	iface_table = (ipa_ifi_dev_name_t *)calloc(ipa_num_ipa_interfaces,
					sizeof(ipa_ifi_dev_name_t));
	if(iface_table == NULL)
	{
		IPACMERR("Unable to allocate iface_table memory.\n");
		ret = IPACM_FAILURE;
<<<<<<< HEAD
int IPACM_LanToLan::turnoff_offload_links(ipa_ip_type iptype, client_info* client)
{
	if(client == NULL)
	{
		IPACMERR("Client is NULL.\n");
		return IPACM_FAILURE;
	}

	bool err_flag;
	offload_link_info_list::iterator client_it;
	offload_link_info_list::iterator peer_it;
	client_info* peer;

	for(client_it = client->link.begin(); client_it != client->link.end(); client_it++)
	{
		peer = client_it->peer_pointer;
		if(del_offload_link(iptype, client->p_iface, peer->p_iface, &(*client_it)) == IPACM_FAILURE)
		{
			IPACMERR("Failed to delete client's offload link.\n");
			return IPACM_FAILURE;
		}

		err_flag = true;
		for(peer_it = peer->link.begin(); peer_it != peer->link.end(); peer_it++)
		{
			if(peer_it->peer_pointer == client)
			{
				if(del_offload_link(iptype, peer->p_iface, client->p_iface, &(*peer_it)) == IPACM_FAILURE)
				{
					IPACMERR("Failed to delete peer's offload link.\n");
					return IPACM_FAILURE;
				}
				peer->link.erase(peer_it);
				err_flag = false;
				break;
			}
		}
		if(err_flag)
		{
			IPACMERR("Unable to find corresponding offload link in peer's entry.\n");
			return IPACM_FAILURE;
		}
		if(iptype == IPA_IP_v4)
		{
			num_offload_pair_v4_ --;
			IPACMDBG_H("Now the number of v4 offload pair is %d\n", num_offload_pair_v4_);
		}
		else
		{
			num_offload_pair_v6_ --;
			IPACMDBG_H("Now the number of v6 offload pair is %d\n", num_offload_pair_v6_);
		}
	}

	client->link.clear();
	return IPACM_SUCCESS;
}
void IPACM_LanToLan_Iface::handle_intra_interface_info()
{
	uint32_t hdr_proc_ctx_hdl;

	if(m_p_iface->tx_prop == NULL)
	{
		IPACMERR("No tx prop.\n");
		return;
	}

	m_intra_interface_info.peer = this;

	snprintf(m_intra_interface_info.rt_tbl_name_for_flt[IPA_IP_v4], IPA_RESOURCE_NAME_MAX,
		"eth_v4_intra_interface");
	IPACMDBG_H("IPv4 routing table for flt name: %s\n", m_intra_interface_info.rt_tbl_name_for_flt[IPA_IP_v4]);
	snprintf(m_intra_interface_info.rt_tbl_name_for_flt[IPA_IP_v6], IPA_RESOURCE_NAME_MAX,
		"eth_v6_intra_interface");
	IPACMDBG_H("IPv6 routing table for flt name: %s\n", m_intra_interface_info.rt_tbl_name_for_flt[IPA_IP_v6]);

	memcpy(m_intra_interface_info.rt_tbl_name_for_rt[IPA_IP_v4], m_intra_interface_info.rt_tbl_name_for_flt[IPA_IP_v4],
		IPA_RESOURCE_NAME_MAX);
	IPACMDBG_H("IPv4 routing table for rt name: %s\n", m_intra_interface_info.rt_tbl_name_for_rt[IPA_IP_v4]);
	memcpy(m_intra_interface_info.rt_tbl_name_for_rt[IPA_IP_v6], m_intra_interface_info.rt_tbl_name_for_flt[IPA_IP_v6],
		IPA_RESOURCE_NAME_MAX);
	IPACMDBG_H("IPv6 routing table for rt name: %s\n", m_intra_interface_info.rt_tbl_name_for_rt[IPA_IP_v6]);

	m_p_iface->eth_bridge_add_hdr_proc_ctx(m_p_iface->tx_prop->tx[0].hdr_l2_type,
		&hdr_proc_ctx_hdl);
	hdr_proc_ctx_for_intra_interface = hdr_proc_ctx_hdl;
	IPACMDBG_H("Hdr proc ctx for intra-interface communication: hdl %d\n", hdr_proc_ctx_hdl);

	return;
}
int IPACM_LanToLan::add_flt_rules(ipa_ip_type iptype, client_info* client)
{
	if(client == NULL)
	{
		IPACMERR("No client info is found.\n");
		return IPACM_FAILURE;
	}

	bool err_flag;
	offload_link_info_list::iterator client_it;
	offload_link_info_list::iterator peer_it;
	client_info* peer;

	for(client_it = client->link.begin(); client_it != client->link.end(); client_it++)
	{
		peer = client_it->peer_pointer;
		if(client->p_iface->add_lan2lan_flt_rule(iptype, client->ip.ipv4_addr, peer->ip.ipv4_addr,
			client->ip.ipv6_addr, peer->ip.ipv6_addr, &(client_it->flt_rule_hdl)) == IPACM_FAILURE)
		{
			IPACMERR("Failed to add client's filtering rule.\n");
			return IPACM_FAILURE;
		}

		err_flag = true;
		for(peer_it = peer->link.begin(); peer_it != peer->link.end(); peer_it++)
		{
			if(peer_it->peer_pointer == client)
			{
				if(peer->p_iface->add_lan2lan_flt_rule(iptype, peer->ip.ipv4_addr, client->ip.ipv4_addr,
					peer->ip.ipv6_addr, client->ip.ipv6_addr, &(peer_it->flt_rule_hdl)) == IPACM_FAILURE)
				{
					IPACMERR("Failed to delete peer's offload link.\n");
					return IPACM_FAILURE;
				}
				err_flag = false;
				break;
			}
		}
		if(err_flag)
		{
			IPACMERR("Unable to find corresponding offload link in peer's entry.\n");
			return IPACM_FAILURE;
		}
	}
	return IPACM_SUCCESS;
}
IPACM_Routing::IPACM_Routing()
{
	m_fd = open(DEVICE_NAME, O_RDWR);
	if (0 == m_fd)
	{
		IPACMERR("Failed opening %s.\n", DEVICE_NAME);
	}
}
bool IPACM_Routing::DeleteRoutingHdl(uint32_t rt_rule_hdl, ipa_ip_type ip)
{
	const uint8_t NUM_RULES = 1;
	struct ipa_ioc_del_rt_rule *rt_rule;
	struct ipa_rt_rule_del *rt_rule_entry;
	bool res = true;
	int len = 0;

	if (rt_rule_hdl == 0)
	{
		IPACMERR(" No route handle passed. Ignoring it\n");
		return res;
	}

	len = (sizeof(struct ipa_ioc_del_rt_rule)) + (NUM_RULES * sizeof(struct ipa_rt_rule_del));
	rt_rule = (struct ipa_ioc_del_rt_rule *)malloc(len);
	if (rt_rule == NULL)
	{
		IPACMERR("unable to allocate memory for del route rule\n");
		return false;
	}

	memset(rt_rule, 0, len);
	rt_rule->commit = 1;
	rt_rule->num_hdls = NUM_RULES;
	rt_rule->ip = ip;

	rt_rule_entry = &rt_rule->hdl[0];
	rt_rule_entry->status = -1;
	rt_rule_entry->hdl = rt_rule_hdl;

	IPACMDBG_H("Deleting Route hdl:(0x%x) with ip type: %d\n", rt_rule_entry->hdl, ip);
	if ((false == DeleteRoutingRule(rt_rule)) ||
			(rt_rule_entry->status))
	{
		PERROR("Routing rule deletion failed!\n");
		goto fail;
		res = false;
	}

fail:
	free(rt_rule);

	return res;
}
void IPACM_LanToLan::handle_del_connection(ipacm_event_connection* new_conn)
{
#ifdef CT_OPT
	if(new_conn == NULL)
	{
		IPACMERR("No connection info is found.\n");
		return;
	}
	if(new_conn->iptype != IPA_IP_v4 && new_conn->iptype != IPA_IP_v6)
	{
		IPACMERR("IP type is not expected: %d.\n", new_conn->iptype);
		return;
	}

	IPACMDBG_H("Del connection info: IP type: %d, src_v4_addr: 0x%08x, dst_v4_addr: 0x%08x\n", new_conn->iptype, new_conn->src_ipv4_addr, new_conn->dst_ipv4_addr);
	IPACMDBG_H("src_v6_addr: 0x%08x%08x%08x%08x, dst_v6_addr: 0x%08x%08x%08x%08x", new_conn->src_ipv6_addr[0], new_conn->src_ipv6_addr[1], new_conn->src_ipv6_addr[2],
				new_conn->src_ipv6_addr[3], new_conn->dst_ipv6_addr[0], new_conn->dst_ipv6_addr[1], new_conn->dst_ipv6_addr[2], new_conn->dst_ipv6_addr[3]);

	if(is_lan2lan_connection(new_conn) == false)
	{
		IPACMDBG_H("The connection is not lan2lan connection.\n");
		remove_cache_connection(new_conn);
		return;
	}

	ipacm_cmd_q_data evt;
	ipacm_event_connection* conn;

	conn = (ipacm_event_connection*)malloc(sizeof(ipacm_event_connection));
	if(conn == NULL)
	{
		IPACMERR("Failed to allocate memory for del_connection event.\n");
		return;
	}
	memcpy(conn, new_conn, sizeof(ipacm_event_connection));

	memset(&evt, 0, sizeof(evt));
	evt.event = IPA_LAN_TO_LAN_DEL_CONNECTION;
	evt.evt_data = (void*)conn;
	IPACM_EvtDispatcher::PostEvt(&evt);
#endif
	return;
}
bool IPACM_Routing::AddRoutingRule(struct ipa_ioc_add_rt_rule *ruleTable)
{
	int retval = 0, cnt=0;
	bool isInvalid = false;

	if (!DeviceNodeIsOpened())
	{
		IPACMERR("Device is not opened\n");
		return false;
	}

	for(cnt=0; cnt<ruleTable->num_rules; cnt++)
	{
		if(ruleTable->rules[cnt].rule.dst > IPA_CLIENT_MAX)
		{
			IPACMERR("Invalid dst pipe, Rule:%d  dst_pipe:%d\n", cnt, ruleTable->rules[cnt].rule.dst);
			isInvalid = true;
		}
	}

	if(isInvalid)
	{
		return false;
	}

	retval = ioctl(m_fd, IPA_IOC_ADD_RT_RULE, ruleTable);
	if (retval)
	{
		IPACMERR("Failed adding routing rule %p\n", ruleTable);
		return false;
	}

	for(cnt=0; cnt<ruleTable->num_rules; cnt++)
	{
		IPACMDBG("Rule:%d  dst_pipe:%d\n", cnt, ruleTable->rules[cnt].rule.dst);
	}

	IPACMDBG_H("Added routing rule %p\n", ruleTable);
	return true;
}
void IPACM_LanToLan::handle_client_power_save(ipacm_event_lan_client* data)
{
	if(data == NULL)
	{
		IPACMERR("No client info is found.\n");
		return;
	}
	if(data->mac_addr == NULL || data->ipv6_addr == NULL || data->p_iface == NULL)
	{
		IPACMERR("Event data is not populated properly.\n");
		return;
	}
	if(data->iptype != IPA_IP_v4 && data->iptype != IPA_IP_v6)
	{
		IPACMERR("IP type is not expected: %d.\n", data->iptype);
		return;
	}

	IPACMDBG_H("Client power save info: iface %s, iptype: %d, mac: 0x%02x%02x%02x%02x%02x%02x, v4_addr: 0x%08x, v6_addr: 0x%08x%08x%08x%08x \n",
		data->p_iface->dev_name, data->iptype,
		data->mac_addr[0], data->mac_addr[1], data->mac_addr[2], data->mac_addr[3], data->mac_addr[4], data->mac_addr[5],
		data->ipv4_addr, data->ipv6_addr[0], data->ipv6_addr[1], data->ipv6_addr[2], data->ipv6_addr[3]);

	client_info* client_ptr;
	uint64_t v6_addr;

	if(data->iptype == IPA_IP_v4)
	{
		if(client_info_v4_.count(data->ipv4_addr) == 0)//if not found the client, return
		{
			IPACMERR("The client is not found the client, return.\n");
			return;
		}
		IPACMDBG_H("The client is found.\n");
		client_info& client = client_info_v4_[data->ipv4_addr];
		client_ptr = &client;
	}
	else
	{
		memcpy(&v6_addr, &(data->ipv6_addr[2]), sizeof(uint64_t));
		if(client_info_v6_.count(v6_addr) == 0)	//if not found the client, insert it in table
		{
			IPACMERR("The client is not found the client, return.\n");
			return;
		}
		IPACMDBG_H("The client is found.\n");
		client_info& client = client_info_v6_[v6_addr];
		client_ptr = &client;
	}

	if(remove_flt_rules(data->iptype, client_ptr) == IPACM_FAILURE)
	{
		IPACMERR("Failed to remove flt rules when power save.\n");
		return;
	}
	client_ptr->is_active = false;
	client_ptr->is_powersave = true;
	return;
}
//If need to remove an entry in peer list, return true, otherwise return false
bool IPACM_LanToLan::remove_connection(client_info* src_client, client_info* dst_client)
{
	if(src_client == NULL || dst_client == NULL)
	{
		IPACMERR("Either source or dest client is NULL.\n");
		return false;
	}

	peer_info_list::iterator it;
	bool ret = false;

	for(it = src_client->peer.begin(); it != src_client->peer.end(); it++)
	{
		if(it->peer_pointer == dst_client)
		{
			it->num_connection--;
			IPACMDBG_H("Find dst client entry in src peer list, connection count: %d\n", it->num_connection);
			if(it->num_connection == 0)
			{
				IPACMDBG_H("Need to remove dst entry in src peer list.\n");
				ret = true;
			}
			break;
		}
	}
	if(ret == true)
	{
		src_client->peer.erase(it);
	}

	ret = false;
	for(it = dst_client->peer.begin(); it != dst_client->peer.end(); it++)
	{
		if(it->peer_pointer == src_client)
		{
			it->num_connection--;
			IPACMDBG_H("Find src client entry in dst peer list, connection count: %d\n", it->num_connection);
			if(it->num_connection == 0)
			{
				IPACMDBG_H("Need to remove src entry in dst peer list.\n");
				ret = true;
			}
			break;
		}
	}
	if(ret == true)
	{
		dst_client->peer.erase(it);
	}
	return ret;
}
void IPACM_LanToLan::erase_offload_link(ipa_ip_type iptype, client_info* src_client, client_info* dst_client)
{
	if(src_client == NULL || dst_client == NULL)
	{
		IPACMERR("Either source or dest client is NULL.\n");
		return;
	}

	offload_link_info_list::iterator it;
	int res_src = IPACM_FAILURE, res_dst = IPACM_FAILURE;

	for(it = src_client->link.begin(); it != src_client->link.end(); it++)
	{
		if(it->peer_pointer == dst_client)
		{
			res_src = IPACM_SUCCESS;
			IPACMDBG_H("Find dst client entry in src link list\n");
			res_src = del_offload_link(iptype, src_client->p_iface, dst_client->p_iface, &(*it));
			src_client->link.erase(it);
			break;
		}
	}

	for(it = dst_client->link.begin(); it != dst_client->link.end(); it++)
	{
		if(it->peer_pointer == src_client)
		{
			res_dst = IPACM_SUCCESS;
			IPACMDBG_H("Find src client entry in dst link list\n");
			res_dst = del_offload_link(iptype, dst_client->p_iface, src_client->p_iface, &(*it));
			dst_client->link.erase(it);
			break;
		}
	}

	if(res_src == IPACM_SUCCESS && res_dst == IPACM_SUCCESS)
	{
		if(iptype == IPA_IP_v4)
		{
			num_offload_pair_v4_ --;
			IPACMDBG_H("Decrease num of v4 offload pairs to %d\n", num_offload_pair_v4_);
		}
		else
		{
			num_offload_pair_v6_ --;
			IPACMDBG_H("Decrease num of v6 offload pairs to %d\n", num_offload_pair_v6_);
		}
	}
	return;
}
//If need to insert an entry in peer list, return true, otherwise return false
bool IPACM_LanToLan::add_connection(client_info* src_client, client_info* dst_client)
{
	if(src_client == NULL || dst_client == NULL)
	{
		IPACMERR("Either source or dest client is NULL.\n");
		return false;
	}

	peer_info_list::iterator it;
	peer_info new_peer;
	bool ret = false;

	for(it = src_client->peer.begin(); it != src_client->peer.end(); it++)
	{
		if(it->peer_pointer == dst_client)
		{
			it->num_connection++;
			IPACMDBG_H("Find dst client entry in peer list, connection count: %d\n", it->num_connection);
			break;
		}
	}
	if(it == src_client->peer.end())
	{
		IPACMDBG_H("Not finding dst client entry, insert a new one in peer list.\n");
		new_peer.peer_pointer = dst_client;
		new_peer.num_connection = 1;
		src_client->peer.push_back(new_peer);
		ret = true;
	}

	for(it = dst_client->peer.begin(); it != dst_client->peer.end(); it++)
	{
		if(it->peer_pointer == src_client)
		{
			it->num_connection++;
			IPACMDBG_H("Find dst client entry in peer list, connection count: %d\n", it->num_connection);
			break;
		}
	}
	if(it == dst_client->peer.end())
	{
		IPACMDBG_H("Not finding src client entry, insert a new one in peer list.\n");
		new_peer.peer_pointer = src_client;
		new_peer.num_connection = 1;
		dst_client->peer.push_back(new_peer);
		ret = true;
	}
	return ret;
}
bool IPACM_Routing::DeleteRoutingRule(struct ipa_ioc_del_rt_rule *ruleTable)
{
	int retval = 0;

	if (!DeviceNodeIsOpened()) return false;

	retval = ioctl(m_fd, IPA_IOC_DEL_RT_RULE, ruleTable);
	if (retval)
	{
		IPACMERR("Failed deleting routing rule table %p\n", ruleTable);
		return false;
	}

	IPACMDBG_H("Deleted routing rule %p\n", ruleTable);
	return true;
}
bool IPACM_Routing::Commit(enum ipa_ip_type ip)
{
	int retval = 0;

	if (!DeviceNodeIsOpened()) return false;

	retval = ioctl(m_fd, IPA_IOC_COMMIT_RT, ip);
	if (retval)
	{
		IPACMERR("Failed commiting routing rules.\n");
		return false;
	}

	IPACMDBG_H("Commited routing rules to IPA HW.\n");
	return true;
}
bool IPACM_Routing::PutRoutingTable(uint32_t routingTableHandle)
{
	int retval = 0;

	if (!DeviceNodeIsOpened()) return false;

	retval = ioctl(m_fd, IPA_IOC_PUT_RT_TBL, routingTableHandle);
	if (retval)
	{
		IPACMERR("IPA_IOCTL_PUT_RT_TBL ioctl failed.\n");
		return false;
	}

	IPACMDBG_H("IPA_IOCTL_PUT_RT_TBL ioctl issued to IPA routing block.\n");
	return true;
}
bool IPACM_Routing::Reset(enum ipa_ip_type ip)
{
	int retval = 0;

	if (!DeviceNodeIsOpened()) return false;

	retval = ioctl(m_fd, IPA_IOC_RESET_RT, ip);
	retval |= ioctl(m_fd, IPA_IOC_COMMIT_RT, ip);
	if (retval)
	{
		IPACMERR("Failed resetting routing block.\n");
		return false;
	}

	IPACMDBG_H("Reset command issued to IPA routing block.\n");
	return true;
}
bool IPACM_Routing::GetRoutingTable(struct ipa_ioc_get_rt_tbl *routingTable)
{
	int retval = 0;

	if (!DeviceNodeIsOpened()) return false;

	retval = ioctl(m_fd, IPA_IOC_GET_RT_TBL, routingTable);
	if (retval)
	{
		IPACMERR("IPA_IOCTL_GET_RT_TBL ioctl failed, routingTable =0x%p, retval=0x%x.\n", routingTable, retval);
		return false;
	}
	IPACMDBG_H("IPA_IOCTL_GET_RT_TBL ioctl issued to IPA routing block.\n");
	/* put routing table right after successfully get routing table */
	PutRoutingTable(routingTable->hdl);

	return true;
}
void IPACM_LanToLan_Iface::add_client_flt_rule(peer_iface_info *peer, client_info *client, ipa_ip_type iptype)
{
	list<flt_rule_info>::iterator it_flt;
	uint32_t flt_rule_hdl;
	flt_rule_info new_flt_info;
	ipa_ioc_get_rt_tbl rt_tbl;

	rt_tbl.ip = iptype;
	memcpy(rt_tbl.name, peer->rt_tbl_name_for_flt[iptype], sizeof(rt_tbl.name));
	IPACMDBG_H("This flt rule points to rt tbl %s.\n", rt_tbl.name);

	if(IPACM_Iface::m_routing.GetRoutingTable(&rt_tbl) == false)
	{
		IPACMERR("Failed to get routing table.\n");
		return;
	}

	m_p_iface->eth_bridge_add_flt_rule(client->mac_addr, rt_tbl.hdl,
		iptype, &flt_rule_hdl);
	IPACMDBG_H("Installed flt rule for IP type %d: handle %d\n", iptype, flt_rule_hdl);

	for(it_flt = peer->flt_rule.begin(); it_flt != peer->flt_rule.end(); it_flt++)
	{
		if(it_flt->p_client == client)	//the client is already in the flt info list
		{
			IPACMDBG_H("The client is found in flt info list.\n");
			it_flt->flt_rule_hdl[iptype] = flt_rule_hdl;
			break;
		}
	}

	if(it_flt == peer->flt_rule.end())	//the client is not in the flt info list
	{
		IPACMDBG_H("The client is not found in flt info list, insert a new one.\n");
		memset(&new_flt_info, 0, sizeof(new_flt_info));
		new_flt_info.p_client = client;
		new_flt_info.flt_rule_hdl[iptype] = flt_rule_hdl;

		peer->flt_rule.push_front(new_flt_info);
	}

	return;
}
void IPACM_LanToLan::check_potential_link(ipa_ip_type iptype, client_info* client)
{
	if(client == NULL)
	{
		IPACMERR("Client is NULL.\n");
		return;
	}

	IPACMDBG_H("Check client's peer list.\n");
	IPACMDBG_H("Client: IP type: %d, IPv4 addr: 0x%08x, IPv6 addr: 0x%08x%08x%08x%08x\n", iptype, client->ip.ipv4_addr,
				client->ip.ipv6_addr[0], client->ip.ipv6_addr[1], client->ip.ipv6_addr[2], client->ip.ipv6_addr[3]);

	peer_info_list::iterator peer_it;
	int res, num = 0;

	for(peer_it = client->peer.begin(); peer_it != client->peer.end(); peer_it++)
	{
		if(peer_it->peer_pointer->is_active == true && peer_it->num_connection > 0)
		{
			res = IPACM_SUCCESS;
			res = add_offload_link(iptype, client, peer_it->peer_pointer);
			res = add_offload_link(iptype, peer_it->peer_pointer, client);
			if(res == IPACM_SUCCESS)
			{
				if(iptype == IPA_IP_v4)
				{
					num_offload_pair_v4_ ++;
					IPACMDBG_H("Now the number of v4 offload links is %d.\n", num_offload_pair_v4_);
				}
				else
				{
					num_offload_pair_v6_ ++;
					IPACMDBG_H("Now the number of v6 offload links is %d.\n", num_offload_pair_v6_);
				}
				num++;
			}
		}
	}
	IPACMDBG_H("Added %d offload links in total.\n", num);
	return;
}
void IPACM_LanToLan::handle_iface_up(ipacm_event_eth_bridge *data)
{
	list<IPACM_LanToLan_Iface>::iterator it;

	IPACMDBG_H("Interface name: %s IP type: %d\n", data->p_iface->dev_name, data->iptype);
	for(it = m_iface.begin(); it != m_iface.end(); it++)
	{
		if(it->get_iface_pointer() == data->p_iface)
		{
			IPACMDBG_H("Found the interface.\n");
			if(it->get_m_is_ip_addr_assigned(data->iptype) == false)
			{
				IPACMDBG_H("IP type %d was not active before, activating it now.\n", data->iptype);
				it->set_m_is_ip_addr_assigned(data->iptype, true);

				/* install inter-interface rules */
				if(it->get_m_support_inter_iface_offload())
					it->add_all_inter_interface_client_flt_rule(data->iptype);

				/* install intra-BSS rules */
				if(it->get_m_support_intra_iface_offload())
					it->add_all_intra_interface_client_flt_rule(data->iptype);
			}
			break;
		}
	}

	if(it == m_iface.end())	//If the interface has not been created before
	{
		if(m_iface.size() == MAX_NUM_IFACE)
		{
			IPACMERR("The number of interfaces has reached maximum %d.\n", MAX_NUM_IFACE);
			return;
		}

		if(!data->p_iface->tx_prop || !data->p_iface->rx_prop)
		{
			IPACMERR("The interface %s does not have tx_prop or rx_prop.\n", data->p_iface->dev_name);
			return;
		}

		if(data->p_iface->tx_prop->tx[0].hdr_l2_type == IPA_HDR_L2_NONE || data->p_iface->tx_prop->tx[0].hdr_l2_type == IPA_HDR_L2_MAX)
		{
			IPACMERR("Invalid l2 header type %s!\n", ipa_l2_hdr_type[data->p_iface->tx_prop->tx[0].hdr_l2_type]);
			return;
		}

		IPACMDBG_H("Does not find the interface, insert a new one.\n");
		IPACM_LanToLan_Iface new_iface(data->p_iface);
		new_iface.set_m_is_ip_addr_assigned(data->iptype, true);

		m_iface.push_front(new_iface);
		IPACMDBG_H("Now the total number of interfaces is %d.\n", m_iface.size());

		IPACM_LanToLan_Iface &front_iface = m_iface.front();

		/* install inter-interface rules */
		if(front_iface.get_m_support_inter_iface_offload())
		{
			for(it = ++m_iface.begin(); it != m_iface.end(); it++)
			{
				/* add peer info only when both interfaces support inter-interface communication */
				if(it->get_m_support_inter_iface_offload())
				{
					/* populate hdr_proc_ctx and routing table handle */
					handle_new_iface_up(&front_iface, &(*it));

					/* add client specific routing rule on existing interface */
					it->add_client_rt_rule_for_new_iface();
				}
			}

			/* add client specific filtering rule on new interface */
			front_iface.add_all_inter_interface_client_flt_rule(data->iptype);
		}

		/* populate the intra-interface information */
		if(front_iface.get_m_support_intra_iface_offload())
		{
			front_iface.handle_intra_interface_info();
		}

		/* handle cached client add event */
		handle_cached_client_add_event(front_iface.get_iface_pointer());
	}
	return;
}
void IPACM_LanToLan::handle_new_lan2lan_connection(ipacm_event_connection* data)
{
	IPACMDBG_H("New lan2lan connection info: IP type: %d, src_v4_addr: 0x%08x, dst_v4_addr: 0x%08x\n", data->iptype, data->src_ipv4_addr, data->dst_ipv4_addr);
	IPACMDBG_H("src_v6_addr: 0x%08x%08x%08x%08x, dst_v6_addr: 0x%08x%08x%08x%08x", data->src_ipv6_addr[0], data->src_ipv6_addr[1], data->src_ipv6_addr[2],
				data->src_ipv6_addr[3], data->dst_ipv6_addr[0], data->dst_ipv6_addr[1], data->dst_ipv6_addr[2], data->dst_ipv6_addr[3]);

	client_info* src_client_ptr;
	client_info* dst_client_ptr;

	if(data->iptype == IPA_IP_v4)
	{
		if(client_info_v4_.count(data->src_ipv4_addr) == 0 || client_info_v4_.count(data->dst_ipv4_addr) == 0)
		{
			IPACMERR("Either source or destination is not in table.\n");
			return;
		}
		client_info& src_client = client_info_v4_[data->src_ipv4_addr];
		src_client_ptr = &src_client;
		client_info& dst_client = client_info_v4_[data->dst_ipv4_addr];
		dst_client_ptr = &dst_client;
	}
	else //ipv6 case
	{
		uint64_t src_ipv6_addr;
		uint64_t dst_ipv6_addr;
		memcpy(&src_ipv6_addr, &(data->src_ipv6_addr[2]), sizeof(uint64_t));
		memcpy(&dst_ipv6_addr, &(data->dst_ipv6_addr[2]), sizeof(uint64_t));

		if(client_info_v6_.count(src_ipv6_addr) == 0 || client_info_v6_.count(dst_ipv6_addr) == 0)
		{
			IPACMERR("Either source or destination is not in table.\n");
			return;
		}
		client_info& src_client = client_info_v6_[src_ipv6_addr];
		src_client_ptr = &src_client;
		client_info& dst_client = client_info_v6_[dst_ipv6_addr];
		dst_client_ptr = &dst_client;
	}

	IPACMDBG_H("Both src and dst are already in table.\n");
	bool is_first_connection;
	is_first_connection = add_connection(src_client_ptr, dst_client_ptr);

	if(is_first_connection && src_client_ptr->is_active && dst_client_ptr->is_active)
	{
		IPACMDBG_H("This is first connection, add offload links.\n");

		if(add_offload_link(data->iptype, src_client_ptr, dst_client_ptr) == IPACM_FAILURE)
		{
			IPACMERR("Failed to add offload link for src->dst direction.\n");
			return;
		}
		if(add_offload_link(data->iptype, dst_client_ptr, src_client_ptr) == IPACM_FAILURE)
		{
			IPACMERR("Failed to add offload link for dst->src direction.\n");
			return;
		}

		if(data->iptype == IPA_IP_v4)
		{
			num_offload_pair_v4_ ++;
			IPACMDBG_H("Added offload links, now num_offload_pair_v4_: %d\n", num_offload_pair_v4_);
		}
		else
		{
			num_offload_pair_v6_ ++;
			IPACMDBG_H("Added offload links, now num_offload_pair_v6_: %d\n", num_offload_pair_v6_);
		}
	}
	return;
}
void IPACM_LanToLan::handle_client_active(ipacm_event_lan_client* data)
{
	if(data == NULL)
	{
		IPACMERR("No client info is found.\n");
		return;
	}
	if(data->mac_addr == NULL || data->ipv6_addr == NULL || data->p_iface == NULL)
	{
		IPACMERR("Event data is not populated properly.\n");
		return;
	}
	if(data->iptype != IPA_IP_v4 && data->iptype != IPA_IP_v6)
	{
		IPACMERR("IP type is not expected.\n");
		return;
	}

	IPACMDBG_H("New client info: iface %s, iptype: %d, mac: 0x%02x%02x%02x%02x%02x%02x, v4_addr: 0x%08x, v6_addr: 0x%08x%08x%08x%08x \n",
		data->p_iface->dev_name, data->iptype,
		data->mac_addr[0], data->mac_addr[1], data->mac_addr[2], data->mac_addr[3], data->mac_addr[4], data->mac_addr[5],
		data->ipv4_addr, data->ipv6_addr[0], data->ipv6_addr[1], data->ipv6_addr[2], data->ipv6_addr[3]);

	bool client_not_found;
	client_info* client_ptr;

	if(data->iptype == IPA_IP_v4)
	{
		client_not_found = (client_info_v4_.count(data->ipv4_addr) == 0);
		IPACMDBG_H("Is the client not found? %d\n", client_not_found);
		client_info& client = client_info_v4_[data->ipv4_addr];
		client_ptr = &client;
	}
	else
	{
		uint64_t v6_addr;
		memcpy(&v6_addr, &(data->ipv6_addr[2]), sizeof(uint64_t));

		client_not_found = (client_info_v6_.count(v6_addr) == 0);
		IPACMDBG_H("Is the client not found? %d\n", client_not_found);
		client_info& client = client_info_v6_[v6_addr];
		client_ptr = &client;
	}

	if(client_not_found == true)
	{
		if(data->iptype == IPA_IP_v4)
		{
			client_ptr->ip.ipv4_addr = data->ipv4_addr;
		}
		else
		{
			memcpy(client_ptr->ip.ipv6_addr, data->ipv6_addr, sizeof(client_ptr->ip.ipv6_addr));
		}
		memcpy(client_ptr->mac_addr, data->mac_addr, sizeof(client_ptr->mac_addr));
		client_ptr->is_active =  true;
		client_ptr->is_powersave = false;
		client_ptr->p_iface = data->p_iface;

		generate_new_connection(data->iptype, client_ptr);
		check_cache_connection(data->iptype, client_ptr);
	}
	else	//the client is found
	{
		if(client_ptr->is_active == true)	//the client is active
		{
			IPACMDBG_H("The client is active.\n");
			if(memcmp(client_ptr->mac_addr, data->mac_addr, sizeof(client_ptr->mac_addr)) == 0)
			{
				IPACMDBG_H("Mac addr is the same, do nothing.\n");
			}
			else
			{
				IPACMERR("The new client has same IP but differenc mac.\n");
				turnoff_offload_links(data->iptype, client_ptr);
				clear_peer_list(client_ptr);

				if(data->iptype == IPA_IP_v4)
				{
					client_ptr->ip.ipv4_addr = data->ipv4_addr;
				}
				else
				{
					memcpy(client_ptr->ip.ipv6_addr, data->ipv6_addr, sizeof(client_ptr->ip.ipv6_addr));
				}
				memcpy(client_ptr->mac_addr, data->mac_addr, sizeof(client_ptr->mac_addr));
				client_ptr->is_active =  true;
				client_ptr->is_powersave = false;
				client_ptr->p_iface = data->p_iface;

				generate_new_connection(data->iptype, client_ptr);
				check_cache_connection(data->iptype, client_ptr);
			}
		}
		else 	//the client is inactive
		{
			IPACMDBG_H("The client is inactive.\n");
			if(data->iptype == IPA_IP_v4)
			{
				client_ptr->ip.ipv4_addr = data->ipv4_addr;
			}
			else
			{
				memcpy(client_ptr->ip.ipv6_addr, data->ipv6_addr, sizeof(client_ptr->ip.ipv6_addr));
			}
			memcpy(client_ptr->mac_addr, data->mac_addr, sizeof(client_ptr->mac_addr));
			client_ptr->is_active =  true;
			client_ptr->is_powersave = false;
			client_ptr->p_iface = data->p_iface;

			check_potential_link(data->iptype, client_ptr);
			generate_new_connection(data->iptype, client_ptr);
			check_cache_connection(data->iptype, client_ptr);
		}
	}
	IPACMDBG_H("There are %d clients in v4 table and %d clients in v6 table.\n", client_info_v4_.size(), client_info_v6_.size());
	return;
}
int IPACM_EvtDispatcher::PostEvt
(
	 ipacm_cmd_q_data *data
)
{
	Message *item = NULL;
	MessageQueue *MsgQueue = NULL;

	if(data->event < IPA_EXTERNAL_EVENT_MAX)
	{
		IPACMDBG("Insert event into external queue.\n");
		MsgQueue = MessageQueue::getInstanceExternal();
	}
	else
	{
		IPACMDBG("Insert event into internal queue.\n");
		MsgQueue = MessageQueue::getInstanceInternal();
	}
	if(MsgQueue == NULL)
	{
		IPACMERR("unable to retrieve MsgQueue instance\n");
		return IPACM_FAILURE;
	}

	item = new Message();
	if(item == NULL)
	{
		IPACMERR("unable to create new message item\n");
		return IPACM_FAILURE;
	}

	item->evt.callback_ptr = IPACM_EvtDispatcher::ProcessEvt;
	memcpy(&item->evt.data, data, sizeof(ipacm_cmd_q_data));

	if(pthread_mutex_lock(&mutex) != 0)
	{
		IPACMERR("unable to lock the mutex\n");
		return IPACM_FAILURE;
	}

	IPACMDBG("Enqueing item\n");
	MsgQueue->enqueue(item);
	IPACMDBG("Enqueued item %p\n", item);

	if(pthread_cond_signal(&cond_var) != 0)
	{
		IPACMDBG("unable to lock the mutex\n");
		/* Release the mutex before you return failure */
		if(pthread_mutex_unlock(&mutex) != 0)
		{
			IPACMERR("unable to unlock the mutex\n");
			return IPACM_FAILURE;
		}
		return IPACM_FAILURE;
	}

	if(pthread_mutex_unlock(&mutex) != 0)
	{
		IPACMERR("unable to unlock the mutex\n");
		return IPACM_FAILURE;
	}

	return IPACM_SUCCESS;
}
void IPACM_LanToLan::handle_client_disconnect(ipacm_event_lan_client* data)
{
	if(data == NULL)
	{
		IPACMERR("No client info is found.\n");
		return;
	}
	if(data->mac_addr == NULL || data->ipv6_addr == NULL || data->p_iface == NULL)
	{
		IPACMERR("Event data is not populated properly.\n");
		return;
	}
	if(data->iptype != IPA_IP_v4 && data->iptype != IPA_IP_v6)
	{
		IPACMERR("IP type is not expected: %d.\n", data->iptype);
		return;
	}

	IPACMDBG_H("Del client info: iface %s, iptype: %d, mac: 0x%02x%02x%02x%02x%02x%02x, v4_addr: 0x%08x, v6_addr: 0x%08x%08x%08x%08x \n",
		data->p_iface->dev_name, data->iptype,
		data->mac_addr[0], data->mac_addr[1], data->mac_addr[2], data->mac_addr[3], data->mac_addr[4], data->mac_addr[5],
		data->ipv4_addr, data->ipv6_addr[0], data->ipv6_addr[1], data->ipv6_addr[2], data->ipv6_addr[3]);

	client_info* client_ptr;
	uint64_t v6_addr;
	if(data->iptype == IPA_IP_v4)
	{
		if(client_info_v4_.count(data->ipv4_addr) == 0)	//if not found the client, return
		{
			IPACMERR("The client is not found the client, return.\n");
			return;
		}
		IPACMDBG_H("The client is found.\n");
		client_info& client = client_info_v4_[data->ipv4_addr];
		client_ptr = &client;
	}
	else
	{
		memcpy(&v6_addr, &(data->ipv6_addr[2]), sizeof(uint64_t));
		if(client_info_v6_.count(v6_addr) == 0)	//if not found the client, insert it in table
		{
			IPACMERR("The client is not found the client, return.\n");
			return;
		}
		IPACMDBG_H("The client is found.\n");
		client_info& client = client_info_v6_[v6_addr];
		client_ptr = &client;
	}

	turnoff_offload_links(data->iptype, client_ptr);
	clear_peer_list(client_ptr);
	if(data->iptype == IPA_IP_v4)
	{
		client_info_v4_.erase(data->ipv4_addr);
	}
	else
	{
		client_info_v6_.erase(v6_addr);
	}
	return;
}
void IPACM_LanToLan::check_cache_connection(ipa_ip_type iptype, client_info* client)
{
#ifdef CT_OPT
	connection_list::iterator it;
	if(iptype == IPA_IP_v4)
	{
		it = connection_v4_.begin();
		while(it != connection_v4_.end())
		{
			if( (it->src_ipv4_addr == client->ip.ipv4_addr && client_info_v4_.count(it->dst_ipv4_addr) > 0)
				|| (it->dst_ipv4_addr == client->ip.ipv4_addr && client_info_v4_.count(it->src_ipv4_addr) > 0) )
			{
				IPACMDBG("Found a cache connection for src client 0x%08x and dst client 0x%08x.\n", it->src_ipv4_addr, it->dst_ipv4_addr);
				ipacm_cmd_q_data evt;
				ipacm_event_connection* conn;

				conn = (ipacm_event_connection*)malloc(sizeof(ipacm_event_connection));
				if(conn == NULL)
				{
					IPACMERR("Failed to allocate memory for new_connection event.\n");
					return;
				}
				memcpy(conn, &(*it), sizeof(ipacm_event_connection));

				memset(&evt, 0, sizeof(evt));
				evt.event = IPA_LAN_TO_LAN_NEW_CONNECTION;
				evt.evt_data = (void*)conn;
				IPACM_EvtDispatcher::PostEvt(&evt);

				it = connection_v4_.erase(it);
				IPACMDBG_H("Now the number of cache connections is %d.\n", connection_v4_.size());
			}
			else
			{
				it++;
			}
		}
	}
	else
	{
		uint64_t src_v6_addr, dst_v6_addr;
		it = connection_v6_.begin();
		while(it != connection_v6_.end())
		{
			memcpy(&src_v6_addr, &(it->src_ipv6_addr[2]), sizeof(uint64_t));
			memcpy(&dst_v6_addr, &(it->dst_ipv6_addr[2]), sizeof(uint64_t));
			if( (memcmp(it->src_ipv6_addr, client->ip.ipv6_addr, 4*sizeof(uint32_t)) == 0 && client_info_v6_.count(dst_v6_addr) > 0)
				|| (memcmp(it->dst_ipv6_addr, client->ip.ipv6_addr, 4*sizeof(uint32_t)) == 0 && client_info_v6_.count(src_v6_addr) > 0) )
			{
				IPACMDBG("Found a cache connection with src client 0x%08x%08x%08x%08x and dst client 0x%08x%08x%08x%08x.\n", it->src_ipv6_addr[0],
							it->src_ipv6_addr[1], it->src_ipv6_addr[2], it->src_ipv6_addr[3], it->dst_ipv6_addr[0], it->dst_ipv6_addr[1],
							it->dst_ipv6_addr[2], it->dst_ipv6_addr[3]);
				ipacm_cmd_q_data evt;
				ipacm_event_connection* conn;

				conn = (ipacm_event_connection*)malloc(sizeof(ipacm_event_connection));
				if(conn == NULL)
				{
					IPACMERR("Failed to allocate memory for new_connection event.\n");
					return;
				}
				memcpy(conn, &(*it), sizeof(ipacm_event_connection));

				memset(&evt, 0, sizeof(evt));
				evt.event = IPA_LAN_TO_LAN_NEW_CONNECTION;
				evt.evt_data = (void*)conn;
				IPACM_EvtDispatcher::PostEvt(&evt);

				it = connection_v6_.erase(it);
				IPACMDBG_H("Now the number of cache connections is %d.\n", connection_v6_.size());
			}
			else
			{
				it++;
			}
		}
	}
#endif
	return;
}
void IPACM_IfaceManager::event_callback(ipa_cm_event_id event, void *param)
{
	int ipa_interface_index;
	ipacm_event_data_fid *evt_data = (ipacm_event_data_fid *)param;
	ipacm_event_data_mac *StaData = (ipacm_event_data_mac *)param;
	ipacm_event_data_all *data_all = (ipacm_event_data_all *)param;
	ipacm_ifacemgr_data ifmgr_data = {0};

	switch(event)
	{
		case IPA_CFG_CHANGE_EVENT:
				IPACMDBG_H(" RESET IPACM_cfg \n");
				IPACM_Iface::ipacmcfg->Init();
			break;
		case IPA_BRIDGE_LINK_UP_EVENT:
			IPACMDBG_H(" Save the bridge0 mac info in IPACM_cfg \n");
			ipa_interface_index = IPACM_Iface::iface_ipa_index_query(data_all->if_index);
			/* check for failure return */
			if (IPACM_FAILURE == ipa_interface_index) {
				IPACMERR("IPA_BRIDGE_LINK_UP_EVENT: not supported iface id: %d\n", data_all->if_index);
				break;
			}
			/* check if iface is bridge interface*/
			if (strcmp(IPACM_Iface::ipacmcfg->ipa_virtual_iface_name, IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name) == 0)
			{
				IPACM_Iface::ipacmcfg->ipa_bridge_enable = true;
				memcpy(IPACM_Iface::ipacmcfg->bridge_mac,
								data_all->mac_addr,
								sizeof(IPACM_Iface::ipacmcfg->bridge_mac));
				IPACMDBG_H("cached bridge0 MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
						 IPACM_Iface::ipacmcfg->bridge_mac[0], IPACM_Iface::ipacmcfg->bridge_mac[1], IPACM_Iface::ipacmcfg->bridge_mac[2],
						 IPACM_Iface::ipacmcfg->bridge_mac[3], IPACM_Iface::ipacmcfg->bridge_mac[4], IPACM_Iface::ipacmcfg->bridge_mac[5]);
			}
			break;
		case IPA_LINK_UP_EVENT:
			IPACMDBG_H("Recieved IPA_LINK_UP_EVENT event: link up %d: \n", evt_data->if_index);
			ipa_interface_index = IPACM_Iface::iface_ipa_index_query(evt_data->if_index);
			/* check for failure return */
			if (IPACM_FAILURE == ipa_interface_index) {
				IPACMERR("IPA_LINK_UP_EVENT: not supported iface id: %d\n", evt_data->if_index);
				break;
			}
			/* LTE-backhaul */
			if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == EMBMS_IF)
			{
				IPACMDBG("WAN-EMBMS (%s) link already up, iface: %d: \n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,evt_data->if_index);
			}
			else if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == WAN_IF)
			{
				IPACMDBG_H("WAN-LTE (%s) link up, iface: %d: \n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,evt_data->if_index);
				ifmgr_data.if_index = evt_data->if_index;
				ifmgr_data.if_type = Q6_WAN;
				create_iface_instance(&ifmgr_data);
			}
			break;

		case IPA_USB_LINK_UP_EVENT:
			IPACMDBG_H("Recieved IPA_USB_LINK_UP_EVENT event: link up %d: \n", evt_data->if_index);
			ipa_interface_index = IPACM_Iface::iface_ipa_index_query(evt_data->if_index);
			/* check for failure return */
			if (IPACM_FAILURE == ipa_interface_index) {
				IPACMERR("IPA_USB_LINK_UP_EVENT: not supported iface id: %d\n", evt_data->if_index);
				break;
			}
			/* check if it's WAN_IF */
			if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == WAN_IF)
			{
				/* usb-backhaul using sta_mode ECM_WAN*/
				IPACMDBG_H("WAN-usb (%s) link up, iface: %d: \n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name, evt_data->if_index);
				ifmgr_data.if_index = evt_data->if_index;
				ifmgr_data.if_type = ECM_WAN;
				create_iface_instance(&ifmgr_data);
			}
			else
			{
				ifmgr_data.if_index = evt_data->if_index;
				ifmgr_data.if_type = Q6_WAN;
				create_iface_instance(&ifmgr_data);
			}
			break;

		case IPA_WLAN_AP_LINK_UP_EVENT:
			ipa_interface_index = IPACM_Iface::iface_ipa_index_query(evt_data->if_index);
			/* check for failure return */
			if (IPACM_FAILURE == ipa_interface_index) {
				IPACMERR("IPA_WLAN_AP_LINK_UP_EVENT: not supported iface id: %d\n", evt_data->if_index);
				break;
			}
			/* change iface category from unknown to WLAN_IF */
			if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == UNKNOWN_IF)
			{
				IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat = WLAN_IF;
				IPACMDBG_H("WLAN AP (%s) link up, iface: %d: \n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,evt_data->if_index);
				ifmgr_data.if_index = evt_data->if_index;
				ifmgr_data.if_type = Q6_WAN;
				create_iface_instance(&ifmgr_data);
			}
			else
			{
				IPACMDBG_H("iface %s already up and act as %d mode: \n",IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat);
			}
			break;

		case IPA_WLAN_STA_LINK_UP_EVENT:
			ipa_interface_index = IPACM_Iface::iface_ipa_index_query(StaData->if_index);
			/* check for failure return */
			if (IPACM_FAILURE == ipa_interface_index) {
				IPACMERR("IPA_WLAN_STA_LINK_UP_EVENT: not supported iface id: %d\n", StaData->if_index);
				break;
			}
			/* change iface category from unknown to WAN_IF */
			if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == UNKNOWN_IF)
			{
				/* wlan-backhaul using sta_mode WLAN_WAN */
				IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat = WAN_IF;
				IPACMDBG_H("WLAN STA (%s) link up, iface: %d: \n",
				IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name, StaData->if_index);

				ifmgr_data.if_index = StaData->if_index;
				ifmgr_data.if_type = WLAN_WAN;
				memcpy(ifmgr_data.mac_addr, StaData->mac_addr, sizeof(ifmgr_data.mac_addr));
				create_iface_instance(&ifmgr_data);
			}
			else
			{
				IPACMDBG_H("iface %s already up and act as %d mode: \n",
				IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,
						IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat);
			}
			break;

		/* Add new instance open for eMBMS iface and wan iface */
		case IPA_WAN_EMBMS_LINK_UP_EVENT:
			ipa_interface_index = IPACM_Iface::iface_ipa_index_query(evt_data->if_index);
			/* check for failure return */
			if (IPACM_FAILURE == ipa_interface_index) {
				IPACMERR("IPA_WAN_EMBMS_LINK_UP_EVENT: not supported iface id: %d\n", evt_data->if_index);
				break;
			}
			/* change iface category from unknown to EMBMS_IF */
			if ((IPACM_Iface::ipacmcfg->ipacm_odu_enable == true) && (IPACM_Iface::ipacmcfg->ipacm_odu_embms_enable == true))
			{
				IPACMDBG(" ODU-mode enable or not (%d) \n",IPACM_Iface::ipacmcfg->ipacm_odu_enable);
				if(IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat == WAN_IF)
				{
					IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat=EMBMS_IF;
					IPACMDBG("WAN eMBMS (%s) link up, iface: %d: \n", IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,evt_data->if_index);
					ifmgr_data.if_index = StaData->if_index;
					ifmgr_data.if_type = Q6_WAN;
					create_iface_instance(&ifmgr_data);
				}
				else
				{
					IPACMDBG("iface %s already up and act as %d mode: \n",IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].iface_name,IPACM_Iface::ipacmcfg->iface_table[ipa_interface_index].if_cat);
				}
			}
			break;

		default:
			break;
	}
	return;
}
int IPACM_LanToLan::add_offload_link(ipa_ip_type iptype, client_info* client, client_info* peer)
{
	if( (iptype == IPA_IP_v4 && num_offload_pair_v4_ >= MAX_OFFLOAD_PAIR)
		|| (iptype == IPA_IP_v6 && num_offload_pair_v6_ >= MAX_OFFLOAD_PAIR) )
	{
		IPACMDBG_H("The number of offload pairs already reaches maximum.\n");
		return IPACM_FAILURE;
	}
	if(client == NULL || peer == NULL)
	{
		IPACMERR("Either client or peer is NULL.\n");
		return IPACM_FAILURE;
	}

	uint32_t hdr_hdl, flt_hdl;
	lan_to_lan_rt_rule_hdl rt_rule_hdl;

	offload_link_info link_info;


	if(iptype == IPA_IP_v4)
	{
		IPACMDBG_H("Add offload link for IPv4, client IP: 0x%08x, peer IP: 0x%08x \n", client->ip.ipv4_addr, peer->ip.ipv4_addr);
	}
	else if(iptype == IPA_IP_v6)
	{
		IPACMDBG_H("Add offload link for IPv6, client IP: 0x%08x%08x%08x%08x, peer IP: 0x%08x%08x%08x%08x \n",
				client->ip.ipv6_addr[0], client->ip.ipv6_addr[1], client->ip.ipv6_addr[2], client->ip.ipv6_addr[3],
				peer->ip.ipv6_addr[0], peer->ip.ipv6_addr[1], peer->ip.ipv6_addr[2], peer->ip.ipv6_addr[3]);
	}
	else
	{
		IPACMERR("IP type is not expected.\n");
		return IPACM_FAILURE;
	}

	//add lan2lan header
	if(peer->p_iface->add_lan2lan_hdr(iptype, client->mac_addr, peer->mac_addr, &hdr_hdl) == IPACM_FAILURE)
	{
		IPACMERR("Failed to create lan2lan header.\n");
		return IPACM_FAILURE;
	}
	IPACMDBG_H("Created lan2lan hdr with hdl %d.\n", hdr_hdl);

	//add lan2lan routing/filtering rules
	if(peer->p_iface->add_lan2lan_rt_rule(iptype, client->ip.ipv4_addr, peer->ip.ipv4_addr,
					client->ip.ipv6_addr, peer->ip.ipv6_addr, hdr_hdl, &rt_rule_hdl) == IPACM_FAILURE)
	{
		IPACMERR("Failed to create lan2lan rt rule.\n");
		goto rt_fail;
	}
	IPACMDBG_H("Created %d lan2lan rt rules.\n", rt_rule_hdl.num_rule);
	IPACMDBG_H("Created lan2lan rt rules with hdl: %d.\n", rt_rule_hdl.rule_hdl[0]);

	if(client->p_iface->add_lan2lan_flt_rule(iptype, client->ip.ipv4_addr, peer->ip.ipv4_addr,
					client->ip.ipv6_addr, peer->ip.ipv6_addr, &flt_hdl) == IPACM_FAILURE)
	{
		IPACMERR("Failed to create lan2lan flt rule.\n");
		goto flt_fail;
	}
	IPACMDBG_H("Created lan2lan flt rule with hdl %d.\n", flt_hdl);

	link_info.peer_pointer = peer;
	link_info.flt_rule_hdl = flt_hdl;
	link_info.hdr_hdl = hdr_hdl;
	memcpy(&link_info.rt_rule_hdl, &rt_rule_hdl, sizeof(lan_to_lan_rt_rule_hdl));

	client->link.push_back(link_info);

	return IPACM_SUCCESS;

flt_fail:
	peer->p_iface->del_lan2lan_rt_rule(iptype, rt_rule_hdl);

rt_fail:
	peer->p_iface->del_lan2lan_hdr(iptype, hdr_hdl);

	return IPACM_FAILURE;
}