| /* |
| Copyright (c) 2014, The Linux Foundation. All rights reserved. |
| |
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the following conditions are |
| met: |
| * Redistributions of source code must retain the above copyright |
| notice, this list of conditions and the following disclaimer. |
| * Redistributions in binary form must reproduce the above |
| copyright notice, this list of conditions and the following |
| disclaimer in the documentation and/or other materials provided |
| with the distribution. |
| * Neither the name of The Linux Foundation nor the names of its |
| contributors may be used to endorse or promote products derived |
| from this software without specific prior written permission. |
| |
| THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED |
| WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT |
| ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS |
| BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| /*! |
| @file |
| IPACM_LanToLan.cpp |
| |
| @brief |
| This file implements the functionality of offloading LAN to LAN traffic. |
| |
| @Author |
| Shihuan Liu |
| |
| */ |
| |
| #include <stdlib.h> |
| #include <assert.h> |
| #include "IPACM_LanToLan.h" |
| #include "IPACM_Wlan.h" |
| |
| IPACM_LanToLan* IPACM_LanToLan::p_instance = NULL; |
| |
| IPACM_LanToLan::IPACM_LanToLan() |
| { |
| num_offload_pair_v4_ = 0; |
| num_offload_pair_v6_ = 0; |
| client_info_v4_.reserve(IPA_LAN_TO_LAN_MAX_WLAN_CLIENT + IPA_LAN_TO_LAN_MAX_USB_CLIENT); |
| client_info_v6_.reserve(3*(IPA_LAN_TO_LAN_MAX_WLAN_CLIENT + IPA_LAN_TO_LAN_MAX_USB_CLIENT)); |
| |
| p_instance = this; |
| |
| IPACM_EvtDispatcher::registr(IPA_LAN_CLIENT_ACTIVE, this); |
| IPACM_EvtDispatcher::registr(IPA_LAN_CLIENT_INACTIVE, this); |
| IPACM_EvtDispatcher::registr(IPA_LAN_CLIENT_DISCONNECT, this); |
| IPACM_EvtDispatcher::registr(IPA_LAN_CLIENT_POWER_SAVE, this); |
| IPACM_EvtDispatcher::registr(IPA_LAN_CLIENT_POWER_RECOVER, this); |
| IPACM_EvtDispatcher::registr(IPA_LAN_TO_LAN_NEW_CONNECTION, this); |
| IPACM_EvtDispatcher::registr(IPA_LAN_TO_LAN_DEL_CONNECTION, this); |
| return; |
| } |
| |
| IPACM_LanToLan::~IPACM_LanToLan() |
| { |
| client_table_v4::iterator it_v4; |
| for(it_v4 = client_info_v4_.begin(); it_v4 != client_info_v4_.end(); it_v4++) |
| { |
| turnoff_offload_links(IPA_IP_v4, &(it_v4->second)); |
| clear_peer_list(&(it_v4->second)); |
| } |
| client_info_v4_.clear(); |
| IPACMDBG("Clear IPv4 hash table in Lan2Lan distructor.\n"); |
| |
| client_table_v6::iterator it_v6; |
| for(it_v6 = client_info_v6_.begin(); it_v6 != client_info_v6_.end(); it_v6++) |
| { |
| turnoff_offload_links(IPA_IP_v6, &(it_v6->second)); |
| clear_peer_list(&(it_v6->second)); |
| } |
| client_info_v6_.clear(); |
| IPACMDBG("Clear IPv4 hash table in Lan2Lan distructor.\n"); |
| |
| return; |
| } |
| |
| void IPACM_LanToLan::event_callback(ipa_cm_event_id event, void* param) |
| { |
| switch(event) |
| { |
| case IPA_LAN_CLIENT_ACTIVE: |
| { |
| IPACMDBG("Get IPA_LAN_CLIENT_ACTIVE event.\n"); |
| ipacm_event_lan_client* data = (ipacm_event_lan_client*)param; |
| handle_client_active(data); |
| break; |
| } |
| |
| case IPA_LAN_CLIENT_INACTIVE: |
| { |
| IPACMDBG("Get IPA_LAN_CLIENT_INACTIVE event.\n"); |
| ipacm_event_lan_client* data = (ipacm_event_lan_client*)param; |
| handle_client_inactive(data); |
| break; |
| } |
| |
| case IPA_LAN_CLIENT_DISCONNECT: |
| { |
| IPACMDBG("Get IPA_LAN_CLIENT_DISCONNECT event.\n"); |
| ipacm_event_lan_client* data = (ipacm_event_lan_client*)param; |
| handle_client_disconnect(data); |
| break; |
| } |
| |
| case IPA_LAN_TO_LAN_NEW_CONNECTION: |
| { |
| IPACMDBG("Get IPA_LAN_TO_LAN_NEW_CONNECTION event.\n"); |
| ipacm_event_connection* data = (ipacm_event_connection*)param; |
| handle_new_lan2lan_connection(data); |
| break; |
| } |
| |
| case IPA_LAN_TO_LAN_DEL_CONNECTION: |
| { |
| IPACMDBG("Get IPA_LAN_TO_LAN_DEL_CONNECTION event.\n"); |
| ipacm_event_connection* data = (ipacm_event_connection*)param; |
| handle_del_lan2lan_connection(data); |
| break; |
| } |
| case IPA_LAN_CLIENT_POWER_SAVE: |
| { |
| IPACMDBG("Get IPA_LAN_CLIENT_POWER_SAVE event.\n"); |
| ipacm_event_lan_client* data = (ipacm_event_lan_client*)param; |
| handle_client_power_save(data); |
| break; |
| } |
| case IPA_LAN_CLIENT_POWER_RECOVER: |
| { |
| IPACMDBG("Get IPA_LAN_CLIENT_POWER_RECOVER event.\n"); |
| ipacm_event_lan_client* data = (ipacm_event_lan_client*)param; |
| handle_client_power_recover(data); |
| break; |
| } |
| default: |
| break; |
| } |
| 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("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("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("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); |
| } |
| else //the client is found |
| { |
| if(client_ptr->is_active == true) //the client is active |
| { |
| IPACMDBG("The client is active.\n"); |
| if(memcmp(client_ptr->mac_addr, data->mac_addr, sizeof(client_ptr->mac_addr)) == 0) |
| { |
| IPACMDBG("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); |
| } |
| } |
| else //the client is inactive |
| { |
| IPACMDBG("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); |
| } |
| } |
| IPACMDBG("There are %d clients in v4 table and %d clients in v6 table.\n", client_info_v4_.size(), client_info_v6_.size()); |
| return; |
| } |
| |
| void IPACM_LanToLan::check_potential_link(ipa_ip_type iptype, client_info* client) |
| { |
| if(client == NULL) |
| { |
| IPACMERR("Client is NULL.\n"); |
| return; |
| } |
| |
| IPACMDBG("Check client's peer list.\n"); |
| IPACMDBG("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("Now the number of v4 offload links is %d.\n", num_offload_pair_v4_); |
| } |
| else |
| { |
| num_offload_pair_v6_ ++; |
| IPACMDBG("Now the number of v6 offload links is %d.\n", num_offload_pair_v6_); |
| } |
| num++; |
| } |
| } |
| } |
| IPACMDBG("Added %d offload links in total.\n", num); |
| 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("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("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("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("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("Created %d lan2lan rt rules.\n", rt_rule_hdl.num_rule); |
| IPACMDBG("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("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; |
| } |
| |
| void IPACM_LanToLan::handle_client_inactive(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("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("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("The client is found.\n"); |
| client_info& client = client_info_v6_[v6_addr]; |
| client_ptr = &client; |
| } |
| |
| turnoff_offload_links(data->iptype, client_ptr); |
| client_ptr->is_active = false; |
| if(client_ptr->peer.size() == 0) |
| { |
| IPACMDBG("Peer list is empty, remove client entry.\n"); |
| if(data->iptype == IPA_IP_v4) |
| { |
| client_info_v4_.erase(data->ipv4_addr); |
| } |
| else |
| { |
| client_info_v6_.erase(v6_addr); |
| } |
| } |
| return; |
| } |
| |
| 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("Now the number of v4 offload pair is %d\n", num_offload_pair_v4_); |
| } |
| else |
| { |
| num_offload_pair_v6_ --; |
| IPACMDBG("Now the number of v6 offload pair is %d\n", num_offload_pair_v6_); |
| } |
| } |
| |
| client->link.clear(); |
| return IPACM_SUCCESS; |
| } |
| |
| 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("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::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("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("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("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; |
| } |
| |
| 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; |
| } |
| |
| 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("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("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("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; |
| } |
| |
| void IPACM_LanToLan::handle_new_lan2lan_connection(ipacm_event_connection* data) |
| { |
| IPACMDBG("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("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("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("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("Added offload links, now num_offload_pair_v4_: %d\n", num_offload_pair_v4_); |
| } |
| else |
| { |
| num_offload_pair_v6_ ++; |
| IPACMDBG("Added offload links, now num_offload_pair_v6_: %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("Find dst client entry in peer list, connection count: %d\n", it->num_connection); |
| break; |
| } |
| } |
| if(it == src_client->peer.end()) |
| { |
| IPACMDBG("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("Find dst client entry in peer list, connection count: %d\n", it->num_connection); |
| break; |
| } |
| } |
| if(it == dst_client->peer.end()) |
| { |
| IPACMDBG("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; |
| } |
| |
| void IPACM_LanToLan::handle_del_lan2lan_connection(ipacm_event_connection* data) |
| { |
| IPACMDBG("Del 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("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]); |
| |
| bool res; |
| uint64_t src_ipv6_addr, dst_ipv6_addr; |
| 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) //if not found the client |
| { |
| IPACMDBG("Not found either source or dest client, return.\n"); |
| return; |
| } |
| client_info& src_client = client_info_v4_[data->src_ipv4_addr]; |
| client_info& dst_client = client_info_v4_[data->dst_ipv4_addr]; |
| src_client_ptr = &src_client; |
| dst_client_ptr = &dst_client; |
| } |
| else |
| { |
| 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)//if not found the client |
| { |
| IPACMDBG("Not found either source or dest client, return.\n"); |
| return; |
| } |
| client_info& src_client = client_info_v6_[src_ipv6_addr]; |
| client_info& dst_client = client_info_v6_[dst_ipv6_addr]; |
| src_client_ptr = &src_client; |
| dst_client_ptr = &dst_client; |
| } |
| |
| res = remove_connection(src_client_ptr, dst_client_ptr); |
| |
| if(res && src_client_ptr->is_active && dst_client_ptr->is_active) |
| { |
| IPACMDBG("Erase link info for both src and dst entries.\n"); |
| erase_offload_link(data->iptype, src_client_ptr, dst_client_ptr); |
| } |
| else |
| { |
| if(res && src_client_ptr->is_powersave && (dst_client_ptr->is_active || dst_client_ptr->is_powersave)) |
| { |
| IPACMDBG("Erase link info for both src and dst entries due to src powersave.\n"); |
| erase_offload_link(data->iptype, src_client_ptr, dst_client_ptr); |
| } |
| if(res && dst_client_ptr->is_powersave && (src_client_ptr->is_active || src_client_ptr->is_powersave)) |
| { |
| IPACMDBG("Erase link info for both src and dst entries due to dst powersave.\n"); |
| erase_offload_link(data->iptype, dst_client_ptr, src_client_ptr); |
| } |
| } |
| |
| //if the src client is not active and not powersave mode, if peer list is empty, remove client entry |
| if(res && src_client_ptr->is_active == false && src_client_ptr->is_powersave == false && src_client_ptr->peer.size() == 0) |
| { |
| IPACMDBG("Peer list of src is empty, remove src entry.\n"); |
| if(data->iptype == IPA_IP_v4) |
| { |
| client_info_v4_.erase(data->src_ipv4_addr); |
| } |
| else |
| { |
| client_info_v6_.erase(src_ipv6_addr); |
| } |
| } |
| |
| //if the dst client is not active and not powersave mode, if peer list is empty, remove client entry |
| if(res && dst_client_ptr->is_active == false && dst_client_ptr->is_powersave == false && dst_client_ptr->peer.size() == 0) |
| { |
| IPACMDBG("Peer list of dst is empty, remove dst entry.\n"); |
| if(data->iptype == IPA_IP_v4) |
| { |
| client_info_v4_.erase(data->dst_ipv4_addr); |
| } |
| else |
| { |
| client_info_v6_.erase(dst_ipv6_addr); |
| } |
| } |
| 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("Find dst client entry in src peer list, connection count: %d\n", it->num_connection); |
| if(it->num_connection == 0) |
| { |
| IPACMDBG("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("Find src client entry in dst peer list, connection count: %d\n", it->num_connection); |
| if(it->num_connection == 0) |
| { |
| IPACMDBG("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("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("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("Decrease num of v4 offload pairs to %d\n", num_offload_pair_v4_); |
| } |
| else |
| { |
| num_offload_pair_v6_ --; |
| IPACMDBG("Decrease num of v6 offload pairs to %d\n", num_offload_pair_v6_); |
| } |
| } |
| return; |
| } |
| |
| void IPACM_LanToLan::generate_new_connection(ipa_ip_type iptype, client_info* client) |
| { |
| #ifndef CT_OPT |
| if(client == NULL) |
| { |
| IPACMERR("Client is NULL.\n"); |
| return; |
| } |
| |
| IPACMDBG("Generate new connection events for IP type %d\n", iptype); |
| |
| int num = 0; |
| ipacm_cmd_q_data evt; |
| ipacm_event_connection* new_conn; |
| ipacm_iface_type client_type, peer_type; |
| client_type = IPACM_Iface::ipacmcfg->iface_table[client->p_iface->ipa_if_num].if_cat; |
| |
| IPACMDBG("Client's iface type is %d.\n", client_type); |
| |
| if(iptype == IPA_IP_v4) |
| { |
| client_table_v4::iterator it; |
| for(it = client_info_v4_.begin(); it != client_info_v4_.end(); it++) |
| { |
| peer_type = IPACM_Iface::ipacmcfg->iface_table[it->second.p_iface->ipa_if_num].if_cat; |
| if(peer_type != client_type && it->second.is_active == true) |
| { |
| IPACMDBG("Find a qualified peer to generate new_conn event.\n"); |
| IPACMDBG("Peer's iface type is %d.\n", peer_type); |
| new_conn = (ipacm_event_connection*)malloc(sizeof(ipacm_event_connection)); |
| if(new_conn == NULL) |
| { |
| IPACMERR("Failed to allocate memory for new_connection event.\n"); |
| return; |
| } |
| memset(new_conn, 0, sizeof(ipacm_event_connection)); |
| new_conn->iptype = IPA_IP_v4; |
| new_conn->src_ipv4_addr = client->ip.ipv4_addr; |
| new_conn->dst_ipv4_addr = it->second.ip.ipv4_addr; |
| |
| memset(&evt, 0, sizeof(evt)); |
| evt.event = IPA_LAN_TO_LAN_NEW_CONNECTION; |
| evt.evt_data = (void*)new_conn; |
| IPACM_EvtDispatcher::PostEvt(&evt); |
| num++; |
| } |
| } |
| } |
| else if(iptype == IPA_IP_v6) |
| { |
| client_table_v6::iterator it; |
| for(it = client_info_v6_.begin(); it != client_info_v6_.end(); it++) |
| { |
| peer_type = IPACM_Iface::ipacmcfg->iface_table[it->second.p_iface->ipa_if_num].if_cat; |
| if(peer_type != client_type && it->second.is_active == true) |
| { |
| IPACMDBG("Find a qualified peer to generate new_conn event.\n"); |
| IPACMDBG("Peer's iface type is %d.\n", peer_type); |
| new_conn = (ipacm_event_connection*)malloc(sizeof(ipacm_event_connection)); |
| if(new_conn == NULL) |
| { |
| IPACMERR("Failed to allocate memory for new_connection event.\n"); |
| return; |
| } |
| memset(new_conn, 0, sizeof(ipacm_event_connection)); |
| new_conn->iptype = IPA_IP_v6; |
| memcpy(new_conn->src_ipv6_addr, client->ip.ipv6_addr, sizeof(client->ip.ipv6_addr)); |
| memcpy(new_conn->dst_ipv6_addr, it->second.ip.ipv6_addr, sizeof(it->second.ip.ipv6_addr)); |
| |
| memset(&evt, 0, sizeof(evt)); |
| evt.event = IPA_LAN_TO_LAN_NEW_CONNECTION; |
| evt.evt_data = (void*)new_conn; |
| IPACM_EvtDispatcher::PostEvt(&evt); |
| num++; |
| } |
| } |
| } |
| else |
| { |
| IPACMERR("IP type is not expected.\n"); |
| } |
| IPACMDBG("Generate %d new connection events in total.\n", num); |
| #endif |
| return; |
| } |
| |
| void IPACM_LanToLan::handle_client_power_recover(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("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]); |
| |
| client_info* client_ptr; |
| if(data->iptype == IPA_IP_v4) |
| { |
| if(client_info_v4_.count(data->ipv4_addr) == 0) |
| { |
| IPACMERR("Client is not found.\n"); |
| return; |
| } |
| 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)); |
| if(client_info_v6_.count(v6_addr) == 0) |
| { |
| IPACMERR("Client is not found.\n"); |
| return; |
| } |
| client_info& client = client_info_v6_[v6_addr]; |
| client_ptr = &client; |
| } |
| |
| if(client_ptr->is_active == true || client_ptr->is_powersave != true) //the client is in wrong state |
| { |
| IPACMERR("The client is in wrong state: active %d, powersave %d.\n", client_ptr->is_active, client_ptr->is_powersave); |
| return; |
| } |
| else |
| { |
| if(add_flt_rules(data->iptype, client_ptr) == IPACM_FAILURE) |
| { |
| IPACMERR("Failed to add back flt rules when power recovery.\n"); |
| return; |
| } |
| client_ptr->is_active = true; |
| client_ptr->is_powersave = false; |
| |
| check_potential_link(data->iptype, client_ptr); |
| generate_new_connection(data->iptype, client_ptr); |
| } |
| IPACMDBG("There are %d clients in v4 table and %d clients in v6 table.\n", client_info_v4_.size(), client_info_v6_.size()); |
| return; |
| } |
| |
| //This function is called when power save: remove filtering rules only |
| int IPACM_LanToLan::remove_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++) |
| { |
| if(client->p_iface->del_lan2lan_flt_rule(iptype, client_it->flt_rule_hdl) == IPACM_FAILURE) |
| { |
| IPACMERR("Failed to delete client's filtering rule.\n"); |
| } |
| |
| err_flag = true; |
| peer = client_it->peer_pointer; |
| for(peer_it = peer->link.begin(); peer_it != peer->link.end(); peer_it++) |
| { |
| if(peer_it->peer_pointer == client) |
| { |
| if(peer->p_iface->del_lan2lan_flt_rule(iptype, peer_it->flt_rule_hdl) == IPACM_FAILURE) |
| { |
| IPACMERR("Failed to delete peer's offload link.\n"); |
| } |
| 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; |
| } |
| |
| 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; |
| } |
| |
| void IPACM_LanToLan::handle_new_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("New 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("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("The connection is not lan2lan connection.\n"); |
| 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 new_connection event.\n"); |
| return; |
| } |
| memcpy(conn, new_conn, 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); |
| #endif |
| 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("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("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("The connection is not lan2lan connection.\n"); |
| 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_LanToLan::is_lan2lan_connection(ipacm_event_connection* data) |
| { |
| 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) |
| { |
| IPACMDBG("Either source or destination is not in client table\n"); |
| return false; |
| } |
| |
| ipacm_iface_type src_type, dst_type; |
| src_type = IPACM_Iface::ipacmcfg->iface_table[client_info_v4_[data->src_ipv4_addr].p_iface->ipa_if_num].if_cat; |
| dst_type = IPACM_Iface::ipacmcfg->iface_table[client_info_v4_[data->dst_ipv4_addr].p_iface->ipa_if_num].if_cat; |
| |
| return (src_type != dst_type); |
| } |
| else |
| { |
| uint64_t src_v6_addr, dst_v6_addr; |
| memcpy(&src_v6_addr, &(data->src_ipv6_addr[2]), sizeof(uint64_t)); |
| memcpy(&dst_v6_addr, &(data->dst_ipv6_addr[2]), sizeof(uint64_t)); |
| |
| if(client_info_v6_.count(src_v6_addr) == 0 || client_info_v6_.count(dst_v6_addr) == 0) |
| { |
| IPACMDBG("Either source or destination is not in client table\n"); |
| return false; |
| } |
| |
| ipacm_iface_type src_type, dst_type; |
| src_type = IPACM_Iface::ipacmcfg->iface_table[client_info_v6_[src_v6_addr].p_iface->ipa_if_num].if_cat; |
| dst_type = IPACM_Iface::ipacmcfg->iface_table[client_info_v6_[dst_v6_addr].p_iface->ipa_if_num].if_cat; |
| |
| return (src_type != dst_type); |
| } |
| } |
| |
| IPACM_LanToLan* IPACM_LanToLan::getLan2LanInstance() |
| { |
| return p_instance; |
| } |