示例#1
0
/* This function read IPACM XML and populate the IPA CM Cfg */
int ipacm_read_cfg_xml(char *xml_file, IPACM_conf_t *config)
{
	xmlDocPtr doc = NULL;
	xmlNode* root = NULL;
	int ret_val = IPACM_SUCCESS;

	/* Invoke the XML parser and obtain the parse tree */
	doc = xmlReadFile(xml_file, "UTF-8", XML_PARSE_NOBLANKS);
	if (doc == NULL) {
		IPACMDBG_H("IPACM_xml_parse: libxml returned parse error!\n");
		return IPACM_FAILURE;
	}

	/*Get the root of the tree*/
	root = xmlDocGetRootElement(doc);

	memset(config, 0, sizeof(IPACM_conf_t));

	/* parse the xml tree returned by libxml */
	ret_val = ipacm_cfg_xml_parse_tree(root, config);

	if (ret_val != IPACM_SUCCESS)
	{
		IPACMDBG_H("IPACM_xml_parse: ipacm_cfg_xml_parse_tree returned parse error!\n");
	}

	/* Free up the libxml's parse tree */
	xmlFreeDoc(doc);

	return ret_val;
}
void IPACM_LanToLan::handle_client_add(ipacm_event_eth_bridge *data)
{
	list<IPACM_LanToLan_Iface>::iterator it_iface;

	IPACMDBG_H("Incoming client MAC: 0x%02x%02x%02x%02x%02x%02x, interface: %s\n", 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->p_iface->dev_name);

	for(it_iface = m_iface.begin(); it_iface != m_iface.end(); it_iface++)
	{
		if(it_iface->get_iface_pointer() == data->p_iface)	//find the interface
		{
			IPACMDBG_H("Found the interface.\n");
			it_iface->handle_client_add(data->mac_addr);
			break;
		}
	}

	/* if the iface was not found, cache the client add event */
	if(it_iface == m_iface.end())
	{
		IPACMDBG_H("The interface is not found.\n");
		if(m_cached_client_add_event.size() < MAX_NUM_CACHED_CLIENT_ADD_EVENT)
		{
			IPACMDBG_H("Cached the client information.\n");
			m_cached_client_add_event.push_front(*data);
		}
		else
		{
			IPACMDBG_H("Cached client add event has reached maximum number.\n");
		}
	}
	return;
}
示例#3
0
/* This function read QCMAP CM Firewall XML and populate the QCMAP CM Cfg */
int IPACM_read_firewall_xml(char *xml_file, IPACM_firewall_conf_t *config)
{
	xmlDocPtr doc = NULL;
	xmlNode* root = NULL;
	int ret_val;

	IPACM_ASSERT(xml_file != NULL);
	IPACM_ASSERT(config != NULL);

	/* invoke the XML parser and obtain the parse tree */
	doc = xmlReadFile(xml_file, "UTF-8", XML_PARSE_NOBLANKS);
	if (doc == NULL) {
		IPACMDBG_H("IPACM_xml_parse: libxml returned parse error\n");
		return IPACM_FAILURE;
	}
	/*get the root of the tree*/
	root = xmlDocGetRootElement(doc);

	/* parse the xml tree returned by libxml*/
	ret_val = IPACM_firewall_xml_parse_tree(root, config);

	if (ret_val != IPACM_SUCCESS)
	{
		IPACMDBG_H("IPACM_xml_parse: ipacm_firewall_xml_parse_tree returned parse error!\n");
	}

	/* free the tree */
	xmlFreeDoc(doc);

	return ret_val;
}
void IPACM_LanToLan_Iface::del_client_flt_rule(peer_iface_info *peer, client_info *client)
{
	list<flt_rule_info>::iterator it_flt;

	for(it_flt = peer->flt_rule.begin(); it_flt != peer->flt_rule.end(); it_flt++)
	{
		if(it_flt->p_client == client)	//found the client in flt info list
		{
			IPACMDBG_H("Found the client in flt info list.\n");
			if(m_is_ip_addr_assigned[IPA_IP_v4])
			{
				m_p_iface->eth_bridge_del_flt_rule(it_flt->flt_rule_hdl[IPA_IP_v4], IPA_IP_v4);
				IPACMDBG_H("IPv4 flt rule %d is deleted.\n", it_flt->flt_rule_hdl[IPA_IP_v4]);
			}
			if(m_is_ip_addr_assigned[IPA_IP_v6])
			{
				m_p_iface->eth_bridge_del_flt_rule(it_flt->flt_rule_hdl[IPA_IP_v6], IPA_IP_v6);
				IPACMDBG_H("IPv6 flt rule %d is deleted.\n", it_flt->flt_rule_hdl[IPA_IP_v6]);
			}

			peer->flt_rule.erase(it_flt);
			break;
		}
	}
	return;
}
void IPACM_LanToLan::handle_iface_down(ipacm_event_eth_bridge *data)
{
	list<IPACM_LanToLan_Iface>::iterator it_target_iface;

	IPACMDBG_H("Interface name: %s\n", data->p_iface->dev_name);

	for(it_target_iface = m_iface.begin(); it_target_iface != m_iface.end(); it_target_iface++)
	{
		if(it_target_iface->get_iface_pointer() == data->p_iface)
		{
			IPACMDBG_H("Found the interface.\n");
			break;
		}
	}

	if(it_target_iface == m_iface.end())
	{
		IPACMDBG_H("The interface has not been found.\n");
		/* clear cached client add event for the unfound interface*/
		clear_cached_client_add_event(data->p_iface);
		return;
	}

	it_target_iface->handle_down_event();
	m_iface.erase(it_target_iface);

	return;
}
void IPACM_LanToLan::cache_new_connection(ipacm_event_connection* new_conn)
{
	if(is_potential_lan2lan_connection(new_conn) == true)
	{
		if(new_conn->iptype == IPA_IP_v4)
		{
			if(connection_v4_.size() == max_cache_connection)
			{
				IPACMDBG_H("Cached ipv4 connections already reach maximum, clear up the list.\n");
				connection_v4_.clear();
			}

			connection_v4_.push_back(*new_conn);
			IPACMDBG_H("Cache an ipv4 connection, now the number of ipv4 cache connection is %d.\n", connection_v4_.size());
		}
		else
		{
			if(connection_v6_.size() == max_cache_connection)
			{
				IPACMDBG_H("Cached ipv6 connections already reach maximum, clear up the list.\n");
				connection_v6_.clear();
			}

			connection_v6_.push_back(*new_conn);
			IPACMDBG_H("Cache an ipv6 connection, now the number of ipv6 cache connection is %d.\n", connection_v6_.size());
		}
	}
	return;
}
IPACM_LanToLan_Iface::IPACM_LanToLan_Iface(IPACM_Lan *p_iface)
{
	int i;

	m_p_iface = p_iface;
	memset(m_is_ip_addr_assigned, 0, sizeof(m_is_ip_addr_assigned));
	m_support_inter_iface_offload = true;
	m_support_intra_iface_offload = false;
	for(i = 0; i < IPA_HDR_L2_MAX; i++)
	{
		ref_cnt_peer_l2_hdr_type[i] = 0;
		hdr_proc_ctx_for_inter_interface[i] = 0;
	}
	hdr_proc_ctx_for_intra_interface = 0;

	if(p_iface->ipa_if_cate == WLAN_IF)
	{
		IPACMDBG_H("Interface %s is WLAN interface.\n", p_iface->dev_name);
		m_support_intra_iface_offload = true;
		if( ((IPACM_Wlan*)p_iface)->is_guest_ap() )
		{
			IPACMDBG_H("Interface %s is guest AP.\n", p_iface->dev_name);
			m_support_inter_iface_offload = false;
		}
	}
	return;
}
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;
}
void IPACM_LanToLan::print_data_structure_info()
{
	list<IPACM_LanToLan_Iface>::iterator it;
	list<ipacm_event_eth_bridge>::iterator it_event;
	int i;

	IPACMDBG_H("There are %d interfaces in total.\n", m_iface.size());

	for(it = m_iface.begin(); it != m_iface.end(); it++)
	{
		it->print_data_structure_info();
	}

	IPACMDBG_H("There are %d cached client add events in total.\n", m_cached_client_add_event.size());

	i = 1;
	for(it_event = m_cached_client_add_event.begin(); it_event != m_cached_client_add_event.end(); it_event++)
	{
		IPACMDBG_H("Client %d MAC: 0x%02x%02x%02x%02x%02x%02x, interface: %s\n", i, it_event->mac_addr[0], it_event->mac_addr[1], it_event->mac_addr[2],
			it_event->mac_addr[3], it_event->mac_addr[4], it_event->mac_addr[5], it_event->p_iface->dev_name);
		i++;
	}

	return;
}
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;
}
示例#11
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;
}
//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::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;
}
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;
}
void IPACM_LanToLan_Iface::decrement_ref_cnt_peer_l2_hdr_type(ipa_hdr_l2_type peer_l2_type)
{
	ref_cnt_peer_l2_hdr_type[peer_l2_type]--;
	IPACMDBG_H("Now the ref_cnt of peer l2 hdr type %s is %d.\n", ipa_l2_hdr_type[peer_l2_type],
		ref_cnt_peer_l2_hdr_type[peer_l2_type]);

	return;
}
void IPACM_LanToLan_Iface::del_hdr_proc_ctx(ipa_hdr_l2_type peer_l2_type)
{
	if(ref_cnt_peer_l2_hdr_type[peer_l2_type] == 0)
	{
		m_p_iface->eth_bridge_del_hdr_proc_ctx(hdr_proc_ctx_for_inter_interface[peer_l2_type]);
		IPACMDBG_H("Hdr proc ctx with hdl %d is deleted.\n", hdr_proc_ctx_for_inter_interface[peer_l2_type]);
	}
	return;
}
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;
}
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_Iface::clear_all_flt_rule_for_one_peer_iface(peer_iface_info *peer)
{
	list<flt_rule_info>::iterator it;

	for(it = peer->flt_rule.begin(); it != peer->flt_rule.end(); it++)
	{
		if(m_is_ip_addr_assigned[IPA_IP_v4])
		{
			m_p_iface->eth_bridge_del_flt_rule(it->flt_rule_hdl[IPA_IP_v4], IPA_IP_v4);
			IPACMDBG_H("IPv4 flt rule %d is deleted.\n", it->flt_rule_hdl[IPA_IP_v4]);
		}
		if(m_is_ip_addr_assigned[IPA_IP_v6])
		{
			m_p_iface->eth_bridge_del_flt_rule(it->flt_rule_hdl[IPA_IP_v6], IPA_IP_v6);
			IPACMDBG_H("IPv6 flt rule %d is deleted.\n", it->flt_rule_hdl[IPA_IP_v6]);
		}
	}
	peer->flt_rule.clear();
	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;
}
int IPACM_IfaceManager::SearchInstance(int ipa_if_index)
{

	iface_instances *tmp = head;

	while(tmp != NULL)
	{
		if(ipa_if_index == tmp->ipa_if_index)
		{
			IPACMDBG_H("Find existed iface-instance name: %s\n",
							 IPACM_Iface::ipacmcfg->iface_table[ipa_if_index].iface_name);
			return IPA_INSTANCE_FOUND;
		}
		tmp = tmp->next;
	}

	IPACMDBG_H("No existed iface-instance name: %s,\n",
					 IPACM_Iface::ipacmcfg->iface_table[ipa_if_index].iface_name);

	return IPA_INSTANCE_NOT_FOUND;
}
void IPACM_LanToLan_Iface::add_all_intra_interface_client_flt_rule(ipa_ip_type iptype)
{
	list<client_info>::iterator it_client;

	IPACMDBG_H("Add flt rules for own clients.\n");
	for(it_client = m_client_info.begin(); it_client != m_client_info.end(); it_client++)
	{
		add_client_flt_rule(&m_intra_interface_info, &(*it_client), iptype);
	}

	return;
}
void IPACM_LanToLan_Iface::add_hdr_proc_ctx(ipa_hdr_l2_type peer_l2_type)
{
	uint32_t hdr_proc_ctx_hdl;

	if(ref_cnt_peer_l2_hdr_type[peer_l2_type] == 1)
	{
		m_p_iface->eth_bridge_add_hdr_proc_ctx(peer_l2_type, &hdr_proc_ctx_hdl);
		hdr_proc_ctx_for_inter_interface[peer_l2_type] = hdr_proc_ctx_hdl;
		IPACMDBG_H("Installed inter-interface hdr proc ctx on iface %s: handle %d\n", m_p_iface->dev_name, hdr_proc_ctx_hdl);
	}
	return;
}
void IPACM_LanToLan_Iface::handle_client_del(uint8_t *mac)
{
	list<client_info>::iterator it_client;
	list<peer_iface_info>::iterator it_peer_info;
	bool flag[IPA_HDR_L2_MAX];

	for(it_client = m_client_info.begin(); it_client != m_client_info.end(); it_client++)
	{
		if(memcmp(it_client->mac_addr, mac, sizeof(it_client->mac_addr)) == 0)	//found the client
		{
			IPACMDBG_H("Found the client.\n");
			break;
		}
	}

	if(it_client != m_client_info.end())	//if we found the client
	{
		/* uninstall inter-interface rules */
		if(m_support_inter_iface_offload)
		{
			memset(flag, 0, sizeof(flag));
			for(it_peer_info = m_peer_iface_info.begin(); it_peer_info != m_peer_iface_info.end();
				it_peer_info++)
			{
				IPACMDBG_H("Delete client filtering rule on peer interface.\n");
				it_peer_info->peer->del_one_client_flt_rule(this, &(*it_client));

				/* make sure to delete routing rule only once for each peer l2 header type */
				if(flag[it_peer_info->peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type] == false)
				{
					IPACMDBG_H("Delete client routing rule for peer interface.\n");
					del_client_rt_rule(&(*it_peer_info), &(*it_client));
					flag[it_peer_info->peer->get_iface_pointer()->tx_prop->tx[0].hdr_l2_type] = true;
				}
			}
		}

		/* uninstall intra-interface rules */
		if(m_support_intra_iface_offload)
		{
			/* delete filtering rule first */
			IPACMDBG_H("Delete client filtering rule for intra-interface communication.\n");
			del_client_flt_rule(&m_intra_interface_info, &(*it_client));

			/* delete routing rule */
			IPACMDBG_H("Delete client routing rule for intra-interface communication.\n");
			del_client_rt_rule(&m_intra_interface_info, &(*it_client));
		}

		/* erase the client from client info list */
		m_client_info.erase(it_client);
	}
	else
	{
		IPACMDBG_H("The client is not found.\n");
	}

	return;
}
void IPACM_LanToLan_Iface::print_peer_info(peer_iface_info *peer_info)
{
	list<flt_rule_info>::iterator it_flt;
	list<rt_rule_info>::iterator it_rt;

	IPACMDBG_H("Printing peer info for iface %s:\n", peer_info->peer->m_p_iface->dev_name);

	IPACMDBG_H("There are %d flt info in total.\n", peer_info->flt_rule.size());
	for(it_flt = peer_info->flt_rule.begin(); it_flt != peer_info->flt_rule.end(); it_flt++)
	{
		IPACMDBG_H("Flt rule handle for client 0x%08x:\n", it_flt->p_client);
		if(m_is_ip_addr_assigned[IPA_IP_v4])
		{
			IPACMDBG_H("IPv4 %d\n", it_flt->flt_rule_hdl[IPA_IP_v4]);
		}
		if(m_is_ip_addr_assigned[IPA_IP_v6])
		{
			IPACMDBG_H("IPv6 %d\n", it_flt->flt_rule_hdl[IPA_IP_v6]);
		}
	}

	return;
}
void IPACM_LanToLan::remove_cache_connection(ipacm_event_connection* del_conn)
{
	connection_list::iterator it;
	if(is_potential_lan2lan_connection(del_conn) == true)
	{
		if(del_conn->iptype == IPA_IP_v4)
		{
			for(it = connection_v4_.begin(); it != connection_v4_.end(); it++)
			{
				if(it->src_ipv4_addr == del_conn->src_ipv4_addr && it->dst_ipv4_addr == del_conn->dst_ipv4_addr)
				{
					IPACMDBG("Find the cached ipv4 connection, remove it from list.\n");
					connection_v4_.erase(it);
					IPACMDBG_H("Now the number of ipv4 cache connection is %d.\n", connection_v4_.size());
					return;
				}
			}
			IPACMDBG_H("Do not find the cached ipv4 connection, do nothing.\n");
		}
		else
		{
			for(it = connection_v6_.begin(); it != connection_v6_.end(); it++)
			{
				if(memcmp(it->src_ipv6_addr, del_conn->src_ipv6_addr, 4*sizeof(uint32_t)) == 0
					&& memcmp(it->dst_ipv6_addr, del_conn->dst_ipv6_addr, 4*sizeof(uint32_t)) == 0 )
				{
					IPACMDBG("Find the cached ipv6 connection, remove it from list.\n");
					connection_v6_.erase(it);
					IPACMDBG_H("Now the number of ipv6 cache connection is %d.\n", connection_v6_.size());
					return;
				}
			}
			IPACMDBG_H("Do not find the cached ipv6 connection, do nothing.\n");
		}
	}
	return;
}
void IPACM_LanToLan_Iface::del_one_client_flt_rule(IPACM_LanToLan_Iface *peer_iface, client_info *client)
{
	list<peer_iface_info>::iterator it;

	for(it = m_peer_iface_info.begin(); it != m_peer_iface_info.end(); it++)
	{
		if(it->peer == peer_iface)
		{
			IPACMDBG_H("Found the peer iface info.\n");
			del_client_flt_rule(&(*it), client);
			break;
		}
	}
	return;
}