IPACM: Add support for Ethernet bridging in MCC Mode
This change enables ethernet bridging in MCC mode. Routing
rules are updated accroding to tx properties of registered
interfaces.
Change-Id: I9a6a77578d6b5ed151ec59af774797c4bd203fb2
diff --git a/ipacm/inc/IPACM_Wlan.h b/ipacm/inc/IPACM_Wlan.h
index 37584e2..fb5555a 100644
--- a/ipacm/inc/IPACM_Wlan.h
+++ b/ipacm/inc/IPACM_Wlan.h
@@ -322,6 +322,11 @@
int handle_wlan_client_reset_rt(ipa_ip_type iptype);
void handle_SCC_MCC_switch(ipa_ip_type);
+
+ void eth_bridge_handle_wlan_SCC_MCC_switch(ipa_ip_type iptype);
+
+ int eth_bridge_modify_wlan_rt_rule(uint8_t* mac, eth_bridge_src_iface src_iface, ipa_ip_type iptyp);
+
};
diff --git a/ipacm/src/IPACM_Main.cpp b/ipacm/src/IPACM_Main.cpp
index 0aef584..3cc58e1 100644
--- a/ipacm/src/IPACM_Main.cpp
+++ b/ipacm/src/IPACM_Main.cpp
@@ -611,16 +611,22 @@
case WLAN_SWITCH_TO_SCC:
IPACMDBG_H("Received WLAN_SWITCH_TO_SCC\n");
- IPACM_Iface::ipacmcfg->isMCC_Mode = false;
- evt_data.event = IPA_WLAN_SWITCH_TO_SCC;
- break;
-
+ if (IPACM_Iface::ipacmcfg->isMCC_Mode == true)
+ {
+ IPACM_Iface::ipacmcfg->isMCC_Mode = false;
+ evt_data.event = IPA_WLAN_SWITCH_TO_SCC;
+ break;
+ }
+ continue;
case WLAN_SWITCH_TO_MCC:
IPACMDBG_H("Received WLAN_SWITCH_TO_MCC\n");
- IPACM_Iface::ipacmcfg->isMCC_Mode = true;
- evt_data.event = IPA_WLAN_SWITCH_TO_MCC;
- break;
-
+ if (IPACM_Iface::ipacmcfg->isMCC_Mode == false)
+ {
+ IPACM_Iface::ipacmcfg->isMCC_Mode == true;
+ evt_data.event = IPA_WLAN_SWITCH_TO_MCC;
+ break;
+ }
+ continue;
default:
IPACMDBG_H("Unhandled message type: %d\n", event_hdr.msg_type);
continue;
diff --git a/ipacm/src/IPACM_Wlan.cpp b/ipacm/src/IPACM_Wlan.cpp
index 862836c..e0f9a82 100644
--- a/ipacm/src/IPACM_Wlan.cpp
+++ b/ipacm/src/IPACM_Wlan.cpp
@@ -737,10 +737,13 @@
{
handle_SCC_MCC_switch(IPA_IP_v4);
handle_SCC_MCC_switch(IPA_IP_v6);
+ eth_bridge_handle_wlan_SCC_MCC_switch(IPA_IP_v4);
+ eth_bridge_handle_wlan_SCC_MCC_switch(IPA_IP_v6);
}
else
{
handle_SCC_MCC_switch(ip_type);
+ eth_bridge_handle_wlan_SCC_MCC_switch(ip_type);
}
break;
@@ -750,10 +753,13 @@
{
handle_SCC_MCC_switch(IPA_IP_v4);
handle_SCC_MCC_switch(IPA_IP_v6);
+ eth_bridge_handle_wlan_SCC_MCC_switch(IPA_IP_v4);
+ eth_bridge_handle_wlan_SCC_MCC_switch(IPA_IP_v6);
}
else
{
handle_SCC_MCC_switch(ip_type);
+ eth_bridge_handle_wlan_SCC_MCC_switch(ip_type);
}
break;
@@ -4288,8 +4294,18 @@
res = IPACM_FAILURE;
goto fail;
}
+ /* Handle MCC Mode case */
+ if (IPACM_Iface::ipacmcfg->isMCC_Mode == true)
+ {
+ IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+ tx_prop->tx[i].alt_dst_pipe);
+ rt_rule.rule.dst = tx_prop->tx[i].alt_dst_pipe;
+ }
+ else
+ {
+ rt_rule.rule.dst = tx_prop->tx[i].dst_pipe;
+ }
- rt_rule.rule.dst = tx_prop->tx[i].dst_pipe;
memcpy(&rt_rule.rule.attrib, &tx_prop->tx[i].attrib, sizeof(rt_rule.rule.attrib));
if(src == SRC_WLAN) //src is WLAN means packet is from WLAN
{
@@ -4826,3 +4842,257 @@
}
return;
}
+
+void IPACM_Wlan::eth_bridge_handle_wlan_SCC_MCC_switch(ipa_ip_type iptype)
+{
+
+ for (int i= 0; i < IPACM_Lan::num_wlan_client; i++)
+ {
+ if (IPACM_Lan::eth_bridge_wlan_client[i].ipa_if_num == ipa_if_num)
+ {
+ if (IPACM_Lan::wlan_to_wlan_hdr_proc_ctx.valid == true)
+ {
+ if (eth_bridge_modify_wlan_rt_rule(IPACM_Lan::eth_bridge_wlan_client[i].mac, SRC_WLAN, iptype) == IPACM_FAILURE)
+ {
+ IPACMDBG_H("SCC/MCC switch is failed for iptype: %d src_iface: %d \n", iptype, SRC_WLAN);
+ return;
+ }
+ }
+ if (IPACM_Lan::usb_to_wlan_hdr_proc_ctx.valid == true)
+ {
+ if (eth_bridge_modify_wlan_rt_rule(IPACM_Lan::eth_bridge_wlan_client[i].mac, SRC_USB, iptype) == IPACM_FAILURE)
+ {
+ IPACMDBG_H("SCC/MCC switch is failed for iptype: %d src_iface: %d \n", iptype, SRC_USB);
+ return;
+ }
+ }
+ }
+ }
+
+ IPACMDBG_H("SCC/MCC switch is successful for iptype: %d\n", iptype);
+}
+
+int IPACM_Wlan::eth_bridge_modify_wlan_rt_rule(uint8_t* mac, eth_bridge_src_iface src_iface, ipa_ip_type iptype)
+{
+ struct ipa_ioc_mdfy_rt_rule *rt_rule = NULL;
+ struct ipa_rt_rule_mdfy *rt_rule_entry;
+ uint32_t index = 0, num_rt_rule = 0, position;
+
+ if (tx_prop == NULL)
+ {
+ IPACMDBG_H("No tx properties \n");
+ return IPACM_FAILURE;
+ }
+
+ if (mac == NULL)
+ {
+ IPACMERR("Client MAC address is empty.\n");
+ return IPACM_FAILURE;
+ }
+
+ IPACMDBG_H("Receive WLAN client MAC 0x%02x%02x%02x%02x%02x%02x.\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+ if (iptype == IPA_IP_v4)
+ {
+ num_rt_rule = each_client_rt_rule_count_v4;
+ }
+ else
+ {
+ num_rt_rule = each_client_rt_rule_count_v6;
+ }
+
+ if (src_iface == SRC_WLAN)
+ {
+ if (iptype == IPA_IP_v4)
+ {
+ for (index = 0; index < wlan_client_rt_from_wlan_info_count_v4; index++)
+ {
+ if (memcmp(eth_bridge_get_client_rt_info_ptr(index, src_iface, IPA_IP_v4)->mac, mac,
+ sizeof(eth_bridge_get_client_rt_info_ptr(index, src_iface, IPA_IP_v4)->mac)) == 0)
+ {
+ position = index;
+ IPACMDBG_H("The client is found at position %d.\n", position);
+ break;
+ }
+ }
+ if (index == wlan_client_rt_from_wlan_info_count_v4)
+ {
+ IPACMERR("The client is not found.\n");
+ return IPACM_FAILURE;
+ }
+ }
+ else
+ {
+ for (index =0 ; index < wlan_client_rt_from_wlan_info_count_v6; index++)
+ {
+ if (memcmp(eth_bridge_get_client_rt_info_ptr(index, src_iface, IPA_IP_v6)->mac, mac,
+ sizeof(eth_bridge_get_client_rt_info_ptr(index, src_iface, IPA_IP_v6)->mac)) == 0)
+ {
+ position = index;
+ IPACMDBG_H("The client is found at position %d.\n", position);
+ break;
+ }
+ }
+ if (index == wlan_client_rt_from_wlan_info_count_v6)
+ {
+ IPACMERR("The client is not found.\n");
+ return IPACM_FAILURE;
+ }
+ }
+ }
+ else
+ {
+ if (iptype == IPA_IP_v4)
+ {
+ for (index = 0; index < wlan_client_rt_from_usb_info_count_v4; index++)
+ {
+ if (memcmp(eth_bridge_get_client_rt_info_ptr(index, src_iface, IPA_IP_v4)->mac, mac,
+ sizeof(eth_bridge_get_client_rt_info_ptr(index, src_iface, IPA_IP_v4)->mac)) == 0)
+ {
+ position = index;
+ IPACMDBG_H("The client is found at position %d.\n", position);
+ break;
+ }
+ }
+ if (index == wlan_client_rt_from_usb_info_count_v4)
+ {
+ IPACMERR("The client is not found.\n");
+ return IPACM_FAILURE;
+ }
+ }
+ else
+ {
+ for (index = 0; index < wlan_client_rt_from_usb_info_count_v6; index++)
+ {
+ if (memcmp(eth_bridge_get_client_rt_info_ptr(index, src_iface, IPA_IP_v6)->mac, mac,
+ sizeof(eth_bridge_get_client_rt_info_ptr(index, src_iface, IPA_IP_v6)->mac)) == 0)
+ {
+ position = index;
+ IPACMDBG_H("The client is found at position %d.\n", position);
+ break;
+ }
+ }
+ if (index == wlan_client_rt_from_usb_info_count_v6)
+ {
+ IPACMERR("The client is not found.\n");
+ return IPACM_FAILURE;
+ }
+ }
+ }
+
+ rt_rule = (struct ipa_ioc_mdfy_rt_rule *)
+ calloc(1, sizeof(struct ipa_ioc_mdfy_rt_rule) +
+ (num_rt_rule) * sizeof(struct ipa_rt_rule_mdfy));
+
+ if (rt_rule == NULL)
+ {
+ IPACMERR("Unable to allocate memory for modify rt rule\n");
+ return IPACM_FAILURE;
+ }
+ IPACMDBG("Allocated memory for %d rules successfully\n", num_rt_rule);
+
+ rt_rule->commit = 1;
+ rt_rule->num_rules = 0;
+ rt_rule->ip = iptype;
+
+ for (index = 0; index < tx_prop->num_tx_props; index++)
+ {
+ if (tx_prop->tx[index].ip == iptype)
+ {
+ if (rt_rule->num_rules >= num_rt_rule)
+ {
+ IPACMERR("Number of routing rules exceeds limit.\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+
+ rt_rule_entry = &rt_rule->rules[rt_rule->num_rules];
+
+ if (IPACM_Iface::ipacmcfg->isMCC_Mode)
+ {
+ IPACMDBG_H("In MCC mode, use alt dst pipe: %d\n",
+ tx_prop->tx[index].alt_dst_pipe);
+ rt_rule_entry->rule.dst = tx_prop->tx[index].alt_dst_pipe;
+ }
+ else
+ {
+ rt_rule_entry->rule.dst = tx_prop->tx[index].dst_pipe;
+ }
+
+ rt_rule_entry->rule.hdr_hdl = 0;
+
+ if (src_iface == SRC_WLAN)
+ {
+ rt_rule_entry->rule.hdr_proc_ctx_hdl =
+ IPACM_Lan::wlan_to_wlan_hdr_proc_ctx.proc_ctx_hdl;
+ }
+ else
+ {
+ rt_rule_entry->rule.hdr_proc_ctx_hdl =
+ IPACM_Lan::usb_to_wlan_hdr_proc_ctx.proc_ctx_hdl;
+ }
+
+ memcpy(&rt_rule_entry->rule.attrib,
+ &tx_prop->tx[index].attrib,
+ sizeof(rt_rule_entry->rule.attrib));
+
+ if (src_iface == SRC_WLAN) //src is WLAN means packet is from WLAN
+ {
+ if (IPACM_Lan::wlan_hdr_type == IPA_HDR_L2_ETHERNET_II)
+ {
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_ETHER_II;
+ }
+ else
+ {
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_802_3;
+ }
+ }
+ else //packet is from USB
+ {
+ if (IPACM_Lan::usb_hdr_type == IPA_HDR_L2_ETHERNET_II)
+ {
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_ETHER_II;
+ }
+ else
+ {
+ rt_rule_entry->rule.attrib.attrib_mask |= IPA_FLT_MAC_DST_ADDR_802_3;
+ }
+ }
+ memcpy(rt_rule_entry->rule.attrib.dst_mac_addr, mac,
+ sizeof(rt_rule_entry->rule.attrib.dst_mac_addr));
+ memset(rt_rule_entry->rule.attrib.dst_mac_addr_mask, 0xFF,
+ sizeof(rt_rule_entry->rule.attrib.dst_mac_addr_mask));
+
+ rt_rule_entry->rt_rule_hdl =
+ eth_bridge_get_client_rt_info_ptr(position, src_iface, iptype)->rt_rule_hdl[rt_rule->num_rules];
+ IPACMDBG_H("tx:%d, rt rule hdl=%x ip-type: %d\n", index,
+ eth_bridge_get_client_rt_info_ptr(position, src_iface, iptype)->rt_rule_hdl[rt_rule->num_rules], iptype);
+
+ rt_rule->num_rules++;
+ }
+ }
+
+ if (rt_rule->num_rules > 0)
+ {
+ if (false == m_routing.ModifyRoutingRule(rt_rule))
+ {
+ IPACMERR("Routing rule modify failed!\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+ if (false == m_routing.Commit(iptype))
+ {
+ IPACMERR("Routing rule modify commit failed!\n");
+ free(rt_rule);
+ return IPACM_FAILURE;
+ }
+ IPACMDBG("Routing rule modified successfully \n");
+ }
+
+ if (rt_rule)
+ {
+ free(rt_rule);
+ }
+ return IPACM_SUCCESS;
+}