diff options
author | Bruno Martins <bgcngm@gmail.com> | 2018-01-08 12:51:07 +0000 |
---|---|---|
committer | Davide Garberi <dade.garberi@gmail.com> | 2018-01-20 09:30:21 +0100 |
commit | 1c67f47d4a205e12650dcb6255c00bafc0046082 (patch) | |
tree | 72bb48ca2152cb2295b0f8de39497490d8616f6f /data-ipa-cfg-mgr/ipacm/src/IPACM_OffloadManager.cpp | |
parent | 6b0c862328f58e523e2a6efa667a2f4b3a609bf3 (diff) |
msm8996-common: Import IPACM back
* QC package: LA.UM.6.5.r1-05300-8x96.0
* Squashed with commits 08e2a5b9b, 055b183 and 8fcf57b
Change-Id: I2f7a792dc0155986e065d1bf79e1f08370c3d79c
Signed-off-by: Davide Garberi <dade.garberi@gmail.com>
Diffstat (limited to 'data-ipa-cfg-mgr/ipacm/src/IPACM_OffloadManager.cpp')
-rw-r--r-- | data-ipa-cfg-mgr/ipacm/src/IPACM_OffloadManager.cpp | 745 |
1 files changed, 745 insertions, 0 deletions
diff --git a/data-ipa-cfg-mgr/ipacm/src/IPACM_OffloadManager.cpp b/data-ipa-cfg-mgr/ipacm/src/IPACM_OffloadManager.cpp new file mode 100644 index 0000000..853cc89 --- /dev/null +++ b/data-ipa-cfg-mgr/ipacm/src/IPACM_OffloadManager.cpp @@ -0,0 +1,745 @@ +/* +Copyright (c) 2017, 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.Z +*/ +/*! + @file + IPACM_OffloadManager.cpp + + @brief + This file implements the basis Iface functionality. + + @Author + Skylar Chang + +*/ +#include <IPACM_OffloadManager.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <string.h> +#include "IPACM_ConntrackClient.h" +#include "IPACM_ConntrackListener.h" +#include "IPACM_Iface.h" +#include "IPACM_Config.h" +#include <unistd.h> + +const char *IPACM_OffloadManager::DEVICE_NAME = "/dev/wwan_ioctl"; + +/* NatApp class Implementation */ +IPACM_OffloadManager *IPACM_OffloadManager::pInstance = NULL; + +IPACM_OffloadManager::IPACM_OffloadManager() +{ + default_gw_index = INVALID_IFACE; + upstream_v4_up = false; + upstream_v6_up = false; + memset(event_cache, 0, MAX_EVENT_CACHE*sizeof(framework_event_cache)); + latest_cache_index = 0; + elrInstance = NULL; + touInstance = NULL; + return ; +} + +RET IPACM_OffloadManager::registerEventListener(IpaEventListener* eventlistener) +{ + RET result = SUCCESS; + if (elrInstance == NULL) { + IPACMDBG_H("get registerEventListener \n"); + elrInstance = eventlistener; + } else { + IPACMDBG_H("already have EventListener previously, override \n"); + elrInstance = eventlistener; + result = FAIL_INPUT_CHECK; + } + return SUCCESS; +} + +RET IPACM_OffloadManager::unregisterEventListener(IpaEventListener* ) +{ + RET result = SUCCESS; + if (elrInstance) + elrInstance = NULL; + else { + IPACMDBG_H("already unregisterEventListener previously \n"); + result = SUCCESS_DUPLICATE_CONFIG; + } + return SUCCESS; +} + +RET IPACM_OffloadManager::registerCtTimeoutUpdater(ConntrackTimeoutUpdater* timeoutupdater) +{ + RET result = SUCCESS; + if (touInstance == NULL) + { + IPACMDBG_H("get ConntrackTimeoutUpdater \n"); + touInstance = timeoutupdater; + } else { + IPACMDBG_H("already have ConntrackTimeoutUpdater previously, override \n"); + touInstance = timeoutupdater; + result = FAIL_INPUT_CHECK; + } + return SUCCESS; +} + +RET IPACM_OffloadManager::unregisterCtTimeoutUpdater(ConntrackTimeoutUpdater* ) +{ + RET result = SUCCESS; + if (touInstance) + touInstance = NULL; + else { + IPACMDBG_H("already unregisterCtTimeoutUpdater previously \n"); + result = SUCCESS_DUPLICATE_CONFIG; + } + return SUCCESS; +} + +RET IPACM_OffloadManager::provideFd(int fd, unsigned int groups) +{ + IPACM_ConntrackClient *cc; + int on = 1, rel; + struct sockaddr_nl local; + unsigned int addr_len; + + cc = IPACM_ConntrackClient::GetInstance(); + + if(!cc) + { + IPACMERR("Init failed: cc %p\n", cc); + return FAIL_HARDWARE; + } + + /* check socket name */ + memset(&local, 0, sizeof(struct sockaddr_nl)); + addr_len = sizeof(local); + getsockname(fd, (struct sockaddr *)&local, (socklen_t *)&addr_len); + IPACMDBG_H(" FD %d, nl_pad %d nl_pid %u\n", fd, local.nl_pad, local.nl_pid); + + /* add the check if getting FDs already or not */ + if(cc->fd_tcp > -1 && cc->fd_udp > -1) { + IPACMDBG_H("has valid FDs fd_tcp %d, fd_udp %d, ignore fd %d.\n", cc->fd_tcp, cc->fd_udp, fd); + return SUCCESS; + } + + if (groups == cc->subscrips_tcp) { + cc->fd_tcp = dup(fd); + IPACMDBG_H("Received fd %d with groups %d.\n", fd, groups); + /* set netlink buf */ + rel = setsockopt(cc->fd_tcp, SOL_NETLINK, NETLINK_NO_ENOBUFS, &on, sizeof(int) ); + if (rel == -1) + { + IPACMERR( "setsockopt returned error code %d ( %s )", errno, strerror( errno ) ); + } + } else if (groups == cc->subscrips_udp) { + cc->fd_udp = dup(fd); + IPACMDBG_H("Received fd %d with groups %d.\n", fd, groups); + /* set netlink buf */ + rel = setsockopt(cc->fd_tcp, SOL_NETLINK, NETLINK_NO_ENOBUFS, &on, sizeof(int) ); + if (rel == -1) + { + IPACMERR( "setsockopt returned error code %d ( %s )", errno, strerror( errno ) ); + } + } else { + IPACMERR("Received unexpected fd with groups %d.\n", groups); + } + if(cc->fd_tcp >0 && cc->fd_udp >0) { + IPACMDBG_H(" Got both fds from framework, start conntrack listener thread.\n"); + CtList->CreateConnTrackThreads(); + } + return SUCCESS; +} + +RET IPACM_OffloadManager::clearAllFds() +{ + + /* IPACM needs to kee old FDs, can't clear */ + IPACMDBG_H("Still use old Fds, can't clear \n"); + return SUCCESS; +} + +bool IPACM_OffloadManager::isStaApSupported() +{ + return true; +} + + +RET IPACM_OffloadManager::setLocalPrefixes(std::vector<Prefix> &/* prefixes */) +{ + return SUCCESS; +} + +RET IPACM_OffloadManager::addDownstream(const char * downstream_name, const Prefix &prefix) +{ + int index; + ipacm_cmd_q_data evt; + ipacm_event_ipahal_stream *evt_data; + + IPACMDBG_H("addDownstream name(%s), ip-family(%d) \n", downstream_name, prefix.fam); + + if (prefix.fam == V4) { + IPACMDBG_H("subnet info v4Addr (%x) v4Mask (%x)\n", prefix.v4Addr, prefix.v4Mask); + } else { + IPACMDBG_H("subnet info v6Addr: %08x:%08x:%08x:%08x \n", + prefix.v6Addr[0], prefix.v6Addr[1], prefix.v6Addr[2], prefix.v6Addr[3]); + IPACMDBG_H("subnet info v6Mask: %08x:%08x:%08x:%08x \n", + prefix.v6Mask[0], prefix.v6Mask[1], prefix.v6Mask[2], prefix.v6Mask[3]); + } + + /* check if netdev valid on device */ + if(ipa_get_if_index(downstream_name, &index)) + { + IPACMERR("fail to get iface index.\n"); + return FAIL_INPUT_CHECK; + } + /* Iface is valid, add to list if not present */ + if (std::find(valid_ifaces.begin(), valid_ifaces.end(), std::string(downstream_name)) == valid_ifaces.end()) + { + /* Iface is new, add it to the list */ + valid_ifaces.push_back(downstream_name); + IPACMDBG_H("add iface(%s) to list\n", downstream_name); + } + + /* check if downstream netdev driver finished its configuration on IPA-HW */ + if (IPACM_Iface::ipacmcfg->CheckNatIfaces(downstream_name)) + { + IPACMDBG_H("addDownstream name(%s) currently not support in ipa \n", downstream_name); + /* copy to the cache */ + for(int i = 0; i < MAX_EVENT_CACHE ;i++) + { + if(event_cache[latest_cache_index].valid == false) + { + //do the copy + event_cache[latest_cache_index].valid = true; + event_cache[latest_cache_index].event = IPA_DOWNSTREAM_ADD; + memcpy(event_cache[latest_cache_index].dev_name, downstream_name, sizeof(event_cache[latest_cache_index].dev_name)); + memcpy(&event_cache[latest_cache_index].prefix_cache, &prefix, sizeof(event_cache[latest_cache_index].prefix_cache)); + if (prefix.fam == V4) { + IPACMDBG_H("cache event(%d) subnet info v4Addr (%x) v4Mask (%x) dev(%s) on entry (%d)\n", + event_cache[latest_cache_index].event, + event_cache[latest_cache_index].prefix_cache.v4Addr, + event_cache[latest_cache_index].prefix_cache.v4Mask, + event_cache[latest_cache_index].dev_name, + latest_cache_index); + } else { + IPACMDBG_H("cache event (%d) v6Addr: %08x:%08x:%08x:%08x \n", + event_cache[latest_cache_index].event, + event_cache[latest_cache_index].prefix_cache.v6Addr[0], + event_cache[latest_cache_index].prefix_cache.v6Addr[1], + event_cache[latest_cache_index].prefix_cache.v6Addr[2], + event_cache[latest_cache_index].prefix_cache.v6Addr[3]); + IPACMDBG_H("subnet v6Mask: %08x:%08x:%08x:%08x dev(%s) on entry(%d), \n", + event_cache[latest_cache_index].prefix_cache.v6Mask[0], + event_cache[latest_cache_index].prefix_cache.v6Mask[1], + event_cache[latest_cache_index].prefix_cache.v6Mask[2], + event_cache[latest_cache_index].prefix_cache.v6Mask[3], + event_cache[latest_cache_index].dev_name, + latest_cache_index); + } + latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE; + break; + } + latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE; + if(i == MAX_EVENT_CACHE - 1) + { + IPACMDBG_H(" run out of event cache (%d)\n", i); + return FAIL_HARDWARE; + } + } + + return SUCCESS; + } + + evt_data = (ipacm_event_ipahal_stream*)malloc(sizeof(ipacm_event_ipahal_stream)); + if(evt_data == NULL) + { + IPACMERR("Failed to allocate memory.\n"); + return FAIL_HARDWARE; + } + memset(evt_data, 0, sizeof(*evt_data)); + + evt_data->if_index = index; + memcpy(&evt_data->prefix, &prefix, sizeof(evt_data->prefix)); + + memset(&evt, 0, sizeof(ipacm_cmd_q_data)); + evt.evt_data = (void*)evt_data; + evt.event = IPA_DOWNSTREAM_ADD; + + IPACMDBG_H("Posting event IPA_DOWNSTREAM_ADD\n"); + IPACM_EvtDispatcher::PostEvt(&evt); + + return SUCCESS; +} + +RET IPACM_OffloadManager::removeDownstream(const char * downstream_name, const Prefix &prefix) +{ + int index; + ipacm_cmd_q_data evt; + ipacm_event_ipahal_stream *evt_data; + + IPACMDBG_H("removeDownstream name(%s), ip-family(%d) \n", downstream_name, prefix.fam); + if(strnlen(downstream_name, sizeof(downstream_name)) == 0) + { + IPACMERR("iface length is 0.\n"); + return FAIL_HARDWARE; + } + if (std::find(valid_ifaces.begin(), valid_ifaces.end(), std::string(downstream_name)) == valid_ifaces.end()) + { + IPACMERR("iface is not present in list.\n"); + return FAIL_HARDWARE; + } + + if(ipa_get_if_index(downstream_name, &index)) + { + IPACMERR("netdev(%s) already removed, ignored\n", downstream_name); + return SUCCESS; + } + + evt_data = (ipacm_event_ipahal_stream*)malloc(sizeof(ipacm_event_ipahal_stream)); + if(evt_data == NULL) + { + IPACMERR("Failed to allocate memory.\n"); + return FAIL_HARDWARE; + } + memset(evt_data, 0, sizeof(*evt_data)); + + evt_data->if_index = index; + memcpy(&evt_data->prefix, &prefix, sizeof(evt_data->prefix)); + + memset(&evt, 0, sizeof(ipacm_cmd_q_data)); + evt.evt_data = (void*)evt_data; + evt.event = IPA_DOWNSTREAM_DEL; + + IPACMDBG_H("Posting event IPA_DOWNSTREAM_DEL\n"); + IPACM_EvtDispatcher::PostEvt(&evt); + + return SUCCESS; +} + +RET IPACM_OffloadManager::setUpstream(const char *upstream_name, const Prefix& gw_addr_v4 , const Prefix& gw_addr_v6) +{ + int index; + RET result = SUCCESS; + + /* if interface name is NULL, default route is removed */ + if(upstream_name != NULL) + { + IPACMDBG_H("setUpstream upstream_name(%s), ipv4-fam(%d) ipv6-fam(%d)\n", upstream_name, gw_addr_v4.fam, gw_addr_v6.fam); + } + else + { + IPACMDBG_H("setUpstream clean upstream_name for ipv4-fam(%d) ipv6-fam(%d)\n", gw_addr_v4.fam, gw_addr_v6.fam); + } + if(upstream_name == NULL) + { + if (default_gw_index == INVALID_IFACE) { + IPACMERR("no previous upstream set before\n"); + return FAIL_INPUT_CHECK; + } + if (gw_addr_v4.fam == V4 && upstream_v4_up == true) { + IPACMDBG_H("clean upstream for ipv4-fam(%d) upstream_v4_up(%d)\n", gw_addr_v4.fam, upstream_v4_up); + post_route_evt(IPA_IP_v4, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v4); + upstream_v4_up = false; + } + if (gw_addr_v6.fam == V6 && upstream_v6_up == true) { + IPACMDBG_H("clean upstream for ipv6-fam(%d) upstream_v6_up(%d)\n", gw_addr_v6.fam, upstream_v6_up); + post_route_evt(IPA_IP_v6, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v6); + upstream_v6_up = false; + } + default_gw_index = INVALID_IFACE; + } + else + { + /* check if netdev valid on device */ + if(ipa_get_if_index(upstream_name, &index)) + { + IPACMERR("fail to get iface index.\n"); + return FAIL_INPUT_CHECK; + } + + /* check if downstream netdev driver finished its configuration on IPA-HW */ + if (IPACM_Iface::ipacmcfg->CheckNatIfaces(upstream_name)) + { + IPACMDBG_H("setUpstream name(%s) currently not support in ipa \n", upstream_name); + /* copy to the cache */ + for(int i = 0; i < MAX_EVENT_CACHE ;i++) + { + if(event_cache[latest_cache_index].valid == false) + { + //do the copy + event_cache[latest_cache_index].valid = true; + event_cache[latest_cache_index].event = IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT; + memcpy(event_cache[latest_cache_index].dev_name, upstream_name, sizeof(event_cache[latest_cache_index].dev_name)); + memcpy(&event_cache[latest_cache_index].prefix_cache, &gw_addr_v4, sizeof(event_cache[latest_cache_index].prefix_cache)); + memcpy(&event_cache[latest_cache_index].prefix_cache_v6, &gw_addr_v6, sizeof(event_cache[latest_cache_index].prefix_cache_v6)); + if (gw_addr_v4.fam == V4) { + IPACMDBG_H("cache event(%d) ipv4 fateway: (%x) dev(%s) on entry (%d)\n", + event_cache[latest_cache_index].event, + event_cache[latest_cache_index].prefix_cache.v4Addr, + event_cache[latest_cache_index].dev_name, + latest_cache_index); + } + + if (gw_addr_v6.fam == V6) + { + IPACMDBG_H("cache event (%d) ipv6 gateway: %08x:%08x:%08x:%08x dev(%s) on entry(%d)\n", + event_cache[latest_cache_index].event, + event_cache[latest_cache_index].prefix_cache_v6.v6Addr[0], + event_cache[latest_cache_index].prefix_cache_v6.v6Addr[1], + event_cache[latest_cache_index].prefix_cache_v6.v6Addr[2], + event_cache[latest_cache_index].prefix_cache_v6.v6Addr[3], + event_cache[latest_cache_index].dev_name, + latest_cache_index); + } + latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE; + break; + } + latest_cache_index = (latest_cache_index + 1)% MAX_EVENT_CACHE; + if(i == MAX_EVENT_CACHE - 1) + { + IPACMDBG_H(" run out of event cache (%d) \n", i); + return FAIL_HARDWARE; + } + } + return SUCCESS; + } + + /* reset the stats when switch from LTE->STA */ + if (index != default_gw_index) { + IPACMDBG_H(" interface switched to %s\n", upstream_name); + if(memcmp(upstream_name, "wlan0", sizeof("wlan0")) == 0) + { + IPACMDBG_H("switch to STA mode, need reset wlan-fw stats\n"); + resetTetherStats(upstream_name); + } + } + + if (gw_addr_v4.fam == V4 && gw_addr_v6.fam == V6) { + + if (upstream_v4_up == false) { + IPACMDBG_H("IPV4 gateway: 0x%x \n", gw_addr_v4.v4Addr); + /* posting route add event for both IPv4 and IPv6 */ + post_route_evt(IPA_IP_v4, index, IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, gw_addr_v4); + upstream_v4_up = true; + } else { + IPACMDBG_H("already setupstream iface(%s) ipv4 previously\n", upstream_name); + } + + if (upstream_v6_up == false) { + IPACMDBG_H("IPV6 gateway: %08x:%08x:%08x:%08x \n", + gw_addr_v6.v6Addr[0], gw_addr_v6.v6Addr[1], gw_addr_v6.v6Addr[2], gw_addr_v6.v6Addr[3]); + /* check v6-address valid or not */ + if((gw_addr_v6.v6Addr[0] == 0) && (gw_addr_v6.v6Addr[1] ==0) && (gw_addr_v6.v6Addr[2] == 0) && (gw_addr_v6.v6Addr[3] == 0)) + { + IPACMDBG_H("Invliad ipv6-address, ignored v6-setupstream\n"); + } else { + post_route_evt(IPA_IP_v6, index, IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, gw_addr_v6); + upstream_v6_up = true; + } + } else { + IPACMDBG_H("already setupstream iface(%s) ipv6 previously\n", upstream_name); + } + } else if (gw_addr_v4.fam == V4 ) { + IPACMDBG_H("check upstream_v6_up (%d) v4_up (%d), default gw index (%d)\n", upstream_v6_up, upstream_v4_up, default_gw_index); + if (upstream_v6_up == true && default_gw_index != INVALID_IFACE ) { + /* clean up previous V6 upstream event */ + IPACMDBG_H(" Post clean-up v6 default gw on iface %d\n", default_gw_index); + post_route_evt(IPA_IP_v6, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v6); + upstream_v6_up = false; + } + + if (upstream_v4_up == false) { + IPACMDBG_H("IPV4 gateway: %x \n", gw_addr_v4.v4Addr); + /* posting route add event for both IPv4 and IPv6 */ + post_route_evt(IPA_IP_v4, index, IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, gw_addr_v4); + upstream_v4_up = true; + } else { + IPACMDBG_H("already setupstream iface(%s) ipv4 previously\n", upstream_name); + result = SUCCESS_DUPLICATE_CONFIG; + } + } else if (gw_addr_v6.fam == V6) { + IPACMDBG_H("check upstream_v6_up (%d) v4_up (%d), default gw index (%d)\n", upstream_v6_up, upstream_v4_up, default_gw_index); + if (upstream_v4_up == true && default_gw_index != INVALID_IFACE ) { + /* clean up previous V4 upstream event */ + IPACMDBG_H(" Post clean-up v4 default gw on iface %d\n", default_gw_index); + post_route_evt(IPA_IP_v4, default_gw_index, IPA_WAN_UPSTREAM_ROUTE_DEL_EVENT, gw_addr_v4); + upstream_v4_up = false; + } + + if (upstream_v6_up == false) { + IPACMDBG_H("IPV6 gateway: %08x:%08x:%08x:%08x \n", + gw_addr_v6.v6Addr[0], gw_addr_v6.v6Addr[1], gw_addr_v6.v6Addr[2], gw_addr_v6.v6Addr[3]); + /* check v6-address valid or not */ + if((gw_addr_v6.v6Addr[0] == 0) && (gw_addr_v6.v6Addr[1] ==0) && (gw_addr_v6.v6Addr[2] == 0) && (gw_addr_v6.v6Addr[3] == 0)) + { + IPACMDBG_H("Invliad ipv6-address, ignored v6-setupstream\n"); + } else { + post_route_evt(IPA_IP_v6, index, IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT, gw_addr_v6); + upstream_v6_up = true; + } + } else { + IPACMDBG_H("already setupstream iface(%s) ipv6 previously\n", upstream_name); + result = SUCCESS_DUPLICATE_CONFIG; + } + } + default_gw_index = index; + IPACMDBG_H("Change degault_gw netdev to (%s)\n", upstream_name); + } + return result; +} + +RET IPACM_OffloadManager::stopAllOffload() +{ + Prefix v4gw, v6gw; + RET result = SUCCESS; + + memset(&v4gw, 0, sizeof(v4gw)); + memset(&v6gw, 0, sizeof(v6gw)); + v4gw.fam = V4; + v6gw.fam = V6; + IPACMDBG_H("posting setUpstream(NULL), ipv4-fam(%d) ipv6-fam(%d)\n", v4gw.fam, v6gw.fam); + result = setUpstream(NULL, v4gw, v6gw); + + /* reset the event cache */ + default_gw_index = INVALID_IFACE; + upstream_v4_up = false; + upstream_v6_up = false; + memset(event_cache, 0, MAX_EVENT_CACHE*sizeof(framework_event_cache)); + latest_cache_index = 0; + valid_ifaces.clear(); + return result; +} + +RET IPACM_OffloadManager::setQuota(const char * upstream_name /* upstream */, uint64_t mb/* limit */) +{ + wan_ioctl_set_data_quota quota; + int fd = -1; + + if ((fd = open(DEVICE_NAME, O_RDWR)) < 0) + { + IPACMERR("Failed opening %s.\n", DEVICE_NAME); + return FAIL_HARDWARE; + } + + quota.quota_mbytes = mb; + quota.set_quota = true; + + memset(quota.interface_name, 0, IFNAMSIZ); + if (strlcpy(quota.interface_name, upstream_name, IFNAMSIZ) >= IFNAMSIZ) { + IPACMERR("String truncation occurred on upstream"); + close(fd); + return FAIL_INPUT_CHECK; + } + + IPACMDBG_H("SET_DATA_QUOTA %s %llu", quota.interface_name, (long long)mb); + + if (ioctl(fd, WAN_IOC_SET_DATA_QUOTA, "a) < 0) { + IPACMERR("IOCTL WAN_IOCTL_SET_DATA_QUOTA call failed: %s", strerror(errno)); + close(fd); + return FAIL_TRY_AGAIN; + } + + close(fd); + return SUCCESS; +} + +RET IPACM_OffloadManager::getStats(const char * upstream_name /* upstream */, + bool reset /* reset */, OffloadStatistics& offload_stats/* ret */) +{ + int fd = -1; + wan_ioctl_query_tether_stats_all stats; + + if ((fd = open(DEVICE_NAME, O_RDWR)) < 0) { + IPACMERR("Failed opening %s.\n", DEVICE_NAME); + return FAIL_HARDWARE; + } + + memset(&stats, 0, sizeof(stats)); + if (strlcpy(stats.upstreamIface, upstream_name, IFNAMSIZ) >= IFNAMSIZ) { + IPACMERR("String truncation occurred on upstream\n"); + close(fd); + return FAIL_INPUT_CHECK; + } + stats.reset_stats = reset; + stats.ipa_client = IPACM_CLIENT_MAX; + + if (ioctl(fd, WAN_IOC_QUERY_TETHER_STATS_ALL, &stats) < 0) { + IPACMERR("IOCTL WAN_IOC_QUERY_TETHER_STATS_ALL call failed: %s \n", strerror(errno)); + close(fd); + return FAIL_TRY_AGAIN; + } + /* feedback to IPAHAL*/ + offload_stats.tx = stats.tx_bytes; + offload_stats.rx = stats.rx_bytes; + + IPACMDBG_H("send getStats tx:%llu rx:%llu \n", (long long)offload_stats.tx, (long long)offload_stats.rx); + close(fd); + return SUCCESS; +} + +int IPACM_OffloadManager::post_route_evt(enum ipa_ip_type iptype, int index, ipa_cm_event_id event, const Prefix &gw_addr) +{ + ipacm_cmd_q_data evt; + ipacm_event_data_iptype *evt_data_route; + + evt_data_route = (ipacm_event_data_iptype*)malloc(sizeof(ipacm_event_data_iptype)); + if(evt_data_route == NULL) + { + IPACMERR("Failed to allocate memory.\n"); + return -EFAULT; + } + memset(evt_data_route, 0, sizeof(*evt_data_route)); + + evt_data_route->if_index = index; + evt_data_route->if_index_tether = 0; + evt_data_route->iptype = iptype; + + IPACMDBG_H("gw_addr.v4Addr: %d, gw_addr.v6Addr: %08x:%08x:%08x:%08x \n", + gw_addr.v4Addr,gw_addr.v6Addr[0],gw_addr.v6Addr[1],gw_addr.v6Addr[2],gw_addr.v6Addr[3]); + +#ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN + evt_data_route->ipv4_addr_gw = gw_addr.v4Addr; + evt_data_route->ipv6_addr_gw[0] = gw_addr.v6Addr[0]; + evt_data_route->ipv6_addr_gw[1] = gw_addr.v6Addr[1]; + evt_data_route->ipv6_addr_gw[2] = gw_addr.v6Addr[2]; + evt_data_route->ipv6_addr_gw[3] = gw_addr.v6Addr[3]; + IPACMDBG_H("default gw ipv4 (%x)\n", evt_data_route->ipv4_addr_gw); + IPACMDBG_H("IPV6 gateway: %08x:%08x:%08x:%08x \n", + evt_data_route->ipv6_addr_gw[0], evt_data_route->ipv6_addr_gw[1], evt_data_route->ipv6_addr_gw[2], evt_data_route->ipv6_addr_gw[3]); +#endif + IPACMDBG_H("Received WAN_UPSTREAM_ROUTE_ADD: fid(%d) tether_fid(%d) ip-type(%d)\n", evt_data_route->if_index, + evt_data_route->if_index_tether, evt_data_route->iptype); + + memset(&evt, 0, sizeof(evt)); + evt.evt_data = (void*)evt_data_route; + evt.event = event; + + IPACM_EvtDispatcher::PostEvt(&evt); + + return 0; +} + +int IPACM_OffloadManager::ipa_get_if_index(const char * if_name, int * if_index) +{ + int fd; + struct ifreq ifr; + + if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + IPACMERR("get interface index socket create failed \n"); + return IPACM_FAILURE; + } + + if(strnlen(if_name, sizeof(if_name)) >= sizeof(ifr.ifr_name)) { + IPACMERR("interface name overflows: len %zu\n", strnlen(if_name, sizeof(if_name))); + close(fd); + return IPACM_FAILURE; + } + + memset(&ifr, 0, sizeof(struct ifreq)); + (void)strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)); + IPACMDBG_H("interface name (%s)\n", if_name); + + if(ioctl(fd,SIOCGIFINDEX , &ifr) < 0) + { + IPACMERR("call_ioctl_on_dev: ioctl failed, interface name (%s):\n", ifr.ifr_name); + close(fd); + return IPACM_FAILURE; + } + + *if_index = ifr.ifr_ifindex; + IPACMDBG_H("Interface netdev index %d\n", *if_index); + close(fd); + return IPACM_SUCCESS; +} + +int IPACM_OffloadManager::resetTetherStats(const char * upstream_name /* upstream */) +{ + int fd = -1; + wan_ioctl_reset_tether_stats stats; + + if ((fd = open(DEVICE_NAME, O_RDWR)) < 0) { + IPACMERR("Failed opening %s.\n", DEVICE_NAME); + return FAIL_HARDWARE; + } + + memset(stats.upstreamIface, 0, IFNAMSIZ); + if (strlcpy(stats.upstreamIface, upstream_name, IFNAMSIZ) >= IFNAMSIZ) { + IPACMERR("String truncation occurred on upstream\n"); + close(fd); + return FAIL_INPUT_CHECK; + } + stats.reset_stats = true; + + if (ioctl(fd, WAN_IOC_RESET_TETHER_STATS, &stats) < 0) { + IPACMERR("IOCTL WAN_IOC_RESET_TETHER_STATS call failed: %s", strerror(errno)); + close(fd); + return FAIL_HARDWARE; + } + IPACMDBG_H("Reset Interface %s stats\n", upstream_name); + close(fd); + return IPACM_SUCCESS; +} + +IPACM_OffloadManager* IPACM_OffloadManager::GetInstance() +{ + if(pInstance == NULL) + pInstance = new IPACM_OffloadManager(); + + return pInstance; +} + +bool IPACM_OffloadManager::search_framwork_cache(char * interface_name) +{ + bool rel = false; + + /* IPACM needs to kee old FDs, can't clear */ + IPACMDBG_H("check netdev(%s)\n", interface_name); + + for(int i = 0; i < MAX_EVENT_CACHE ;i++) + { + if(event_cache[i].valid == true) + { + //do the compare + if (strncmp(event_cache[i].dev_name, + interface_name, + sizeof(event_cache[i].dev_name)) == 0) + { + IPACMDBG_H("found netdev (%s) in entry (%d) with event (%d)\n", interface_name, i, event_cache[i].event); + /* post event again */ + if (event_cache[i].event == IPA_DOWNSTREAM_ADD) + addDownstream(interface_name, event_cache[i].prefix_cache); + else if (event_cache[i].event == IPA_WAN_UPSTREAM_ROUTE_ADD_EVENT) + setUpstream(interface_name, event_cache[i].prefix_cache, event_cache[i].prefix_cache_v6); + else + IPACMERR("wrong event cached (%d)", event_cache[i].event); + event_cache[i].valid = false; + rel = true; + } + } + } + IPACMDBG_H(" not found netdev (%s) has cached event\n", interface_name); + return rel; +} |