This reverts commit 98c3540df1
.
Revert needed due Wifi Offload service crashing device and cause soft reboot
385 lines
10 KiB
C++
385 lines
10 KiB
C++
/*
|
|
Copyright (c) 2013, 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_Routing.cpp
|
|
|
|
@brief
|
|
This file implements the IPACM routing functionality.
|
|
|
|
@Author
|
|
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <sys/ioctl.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "IPACM_Routing.h"
|
|
#include <IPACM_Log.h>
|
|
|
|
const char *IPACM_Routing::DEVICE_NAME = "/dev/ipa";
|
|
|
|
IPACM_Routing::IPACM_Routing()
|
|
{
|
|
m_fd = open(DEVICE_NAME, O_RDWR);
|
|
if (0 == m_fd)
|
|
{
|
|
IPACMERR("Failed opening %s.\n", DEVICE_NAME);
|
|
}
|
|
}
|
|
|
|
IPACM_Routing::~IPACM_Routing()
|
|
{
|
|
close(m_fd);
|
|
}
|
|
|
|
bool IPACM_Routing::DeviceNodeIsOpened()
|
|
{
|
|
int res = fcntl(m_fd, F_GETFL);
|
|
|
|
if (m_fd > 0 && res >= 0) return true;
|
|
else return false;
|
|
|
|
}
|
|
|
|
bool IPACM_Routing::AddRoutingRule(struct ipa_ioc_add_rt_rule *ruleTable)
|
|
{
|
|
int retval = 0, cnt=0;
|
|
bool isInvalid = false;
|
|
|
|
if (!DeviceNodeIsOpened())
|
|
{
|
|
IPACMERR("Device is not opened\n");
|
|
return false;
|
|
}
|
|
|
|
for(cnt=0; cnt<ruleTable->num_rules; cnt++)
|
|
{
|
|
if(ruleTable->rules[cnt].rule.dst > IPA_CLIENT_MAX)
|
|
{
|
|
IPACMERR("Invalid dst pipe, Rule:%d dst_pipe:%d\n", cnt, ruleTable->rules[cnt].rule.dst);
|
|
isInvalid = true;
|
|
}
|
|
}
|
|
|
|
if(isInvalid)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
retval = ioctl(m_fd, IPA_IOC_ADD_RT_RULE, ruleTable);
|
|
if (retval)
|
|
{
|
|
IPACMERR("Failed adding routing rule %p\n", ruleTable);
|
|
return false;
|
|
}
|
|
|
|
for(cnt=0; cnt<ruleTable->num_rules; cnt++)
|
|
{
|
|
IPACMDBG("Rule:%d dst_pipe:%d\n", cnt, ruleTable->rules[cnt].rule.dst);
|
|
}
|
|
|
|
IPACMDBG_H("Added routing rule %p\n", ruleTable);
|
|
return true;
|
|
}
|
|
|
|
#ifdef IPA_IOCTL_SET_FNR_COUNTER_INFO
|
|
bool IPACM_Routing::AddRoutingRule_hw_index(struct ipa_ioc_add_rt_rule *ruleTable, int hw_counter_index)
|
|
{
|
|
int retval = 0, cnt = 0, len = 0;
|
|
struct ipa_ioc_add_rt_rule_v2 *ruleTable_v2;
|
|
struct ipa_rt_rule_add_v2 rt_rule_entry;
|
|
bool ret = true;
|
|
|
|
IPACMDBG("Printing routing add attributes\n");
|
|
IPACMDBG("ip type: %d\n", ruleTable->ip);
|
|
IPACMDBG("rt tbl type: %s\n", ruleTable->rt_tbl_name);
|
|
IPACMDBG("Number of rules: %d\n", ruleTable->num_rules);
|
|
IPACMDBG("commit value: %d\n", ruleTable->commit);
|
|
|
|
/* change to v2 format*/
|
|
len = sizeof(struct ipa_ioc_add_rt_rule_v2);
|
|
ruleTable_v2 = (struct ipa_ioc_add_rt_rule_v2*)malloc(len);
|
|
if (ruleTable_v2 == NULL)
|
|
{
|
|
IPACMERR("Error Locate ipa_ioc_add_rt_rule_v2 memory...\n");
|
|
return false;
|
|
}
|
|
memset(ruleTable_v2, 0, len);
|
|
ruleTable_v2->rules = (uint64_t)calloc(ruleTable->num_rules, sizeof(struct ipa_rt_rule_add_v2));
|
|
if (!ruleTable_v2->rules) {
|
|
IPACMERR("Failed to allocate memory for routing rules\n");
|
|
ret = false;
|
|
goto fail_tbl;
|
|
}
|
|
|
|
ruleTable_v2->commit = ruleTable->commit;
|
|
ruleTable_v2->ip = ruleTable->ip;
|
|
ruleTable_v2->num_rules = ruleTable->num_rules;
|
|
ruleTable_v2->rule_add_size = sizeof(struct ipa_rt_rule_add_v2);
|
|
memcpy(ruleTable_v2->rt_tbl_name,
|
|
ruleTable->rt_tbl_name,
|
|
sizeof(ruleTable_v2->rt_tbl_name));
|
|
|
|
for (cnt=0; cnt < ruleTable->num_rules; cnt++)
|
|
{
|
|
memset(&rt_rule_entry, 0, sizeof(struct ipa_rt_rule_add_v2));
|
|
rt_rule_entry.at_rear = ruleTable->rules[cnt].at_rear;
|
|
rt_rule_entry.rule.dst = ruleTable->rules[cnt].rule.dst;
|
|
rt_rule_entry.rule.hdr_hdl = ruleTable->rules[cnt].rule.hdr_hdl;
|
|
rt_rule_entry.rule.hdr_proc_ctx_hdl = ruleTable->rules[cnt].rule.hdr_proc_ctx_hdl;
|
|
rt_rule_entry.rule.max_prio = ruleTable->rules[cnt].rule.max_prio;
|
|
rt_rule_entry.rule.hashable = ruleTable->rules[cnt].rule.hashable;
|
|
rt_rule_entry.rule.retain_hdr = ruleTable->rules[cnt].rule.retain_hdr;
|
|
rt_rule_entry.rule.coalesce = ruleTable->rules[cnt].rule.coalesce;
|
|
memcpy(&rt_rule_entry.rule.attrib,
|
|
&ruleTable->rules[cnt].rule.attrib,
|
|
sizeof(rt_rule_entry.rule.attrib));
|
|
IPACMDBG("RT rule:%d attrib mask: 0x%x\n", cnt,
|
|
ruleTable->rules[cnt].rule.attrib.attrib_mask);
|
|
/* 0 means disable hw-counter-sats */
|
|
if (hw_counter_index != 0)
|
|
{
|
|
rt_rule_entry.rule.enable_stats = 1;
|
|
rt_rule_entry.rule.cnt_idx = hw_counter_index;
|
|
}
|
|
|
|
/* copy to v2 table*/
|
|
memcpy((void *)(ruleTable_v2->rules + (cnt * sizeof(struct ipa_rt_rule_add_v2))),
|
|
&rt_rule_entry, sizeof(rt_rule_entry));
|
|
}
|
|
|
|
retval = ioctl(m_fd, IPA_IOC_ADD_RT_RULE_V2, ruleTable_v2);
|
|
if (retval != 0)
|
|
{
|
|
IPACMERR("Failed adding Routing rule %pK\n", ruleTable_v2);
|
|
PERROR("unable to add routing rule:");
|
|
|
|
for (int cnt = 0; cnt < ruleTable_v2->num_rules; cnt++)
|
|
{
|
|
if (((struct ipa_rt_rule_add_v2 *)ruleTable_v2->rules)[cnt].status != 0)
|
|
{
|
|
IPACMERR("Adding Routing rule:%d failed with status:%d\n",
|
|
cnt, ((struct ipa_rt_rule_add_v2 *)ruleTable_v2->rules)[cnt].status);
|
|
}
|
|
}
|
|
ret = false;
|
|
goto fail_rule;
|
|
}
|
|
|
|
/* copy results from v2 to v1 format */
|
|
for (int cnt = 0; cnt < ruleTable->num_rules; cnt++)
|
|
{
|
|
/* copy status to v1 format */
|
|
ruleTable->rules[cnt].status = ((struct ipa_rt_rule_add_v2 *)ruleTable_v2->rules)[cnt].status;
|
|
ruleTable->rules[cnt].rt_rule_hdl = ((struct ipa_rt_rule_add_v2 *)ruleTable_v2->rules)[cnt].rt_rule_hdl;
|
|
|
|
if(((struct ipa_rt_rule_add_v2 *)ruleTable_v2->rules)[cnt].status != 0)
|
|
{
|
|
IPACMERR("Adding Routing rule:%d failed with status:%d\n",
|
|
cnt, ((struct ipa_rt_rule_add_v2 *) ruleTable_v2->rules)[cnt].status);
|
|
}
|
|
}
|
|
IPACMDBG("Added Routing rule %pK\n", ruleTable_v2);
|
|
fail_rule:
|
|
if((void *)ruleTable_v2->rules != NULL)
|
|
free((void *)ruleTable_v2->rules);
|
|
fail_tbl:
|
|
if (ruleTable_v2 != NULL)
|
|
free(ruleTable_v2);
|
|
return ret;
|
|
}
|
|
#endif //IPA_IOCTL_SET_FNR_COUNTER_INFO
|
|
|
|
|
|
bool IPACM_Routing::DeleteRoutingRule(struct ipa_ioc_del_rt_rule *ruleTable)
|
|
{
|
|
int retval = 0;
|
|
|
|
if (!DeviceNodeIsOpened()) return false;
|
|
|
|
retval = ioctl(m_fd, IPA_IOC_DEL_RT_RULE, ruleTable);
|
|
if (retval)
|
|
{
|
|
IPACMERR("Failed deleting routing rule table %p\n", ruleTable);
|
|
return false;
|
|
}
|
|
|
|
IPACMDBG_H("Deleted routing rule %p\n", ruleTable);
|
|
return true;
|
|
}
|
|
|
|
bool IPACM_Routing::Commit(enum ipa_ip_type ip)
|
|
{
|
|
int retval = 0;
|
|
|
|
if (!DeviceNodeIsOpened()) return false;
|
|
|
|
retval = ioctl(m_fd, IPA_IOC_COMMIT_RT, ip);
|
|
if (retval)
|
|
{
|
|
IPACMERR("Failed commiting routing rules.\n");
|
|
return false;
|
|
}
|
|
|
|
IPACMDBG_H("Commited routing rules to IPA HW.\n");
|
|
return true;
|
|
}
|
|
|
|
bool IPACM_Routing::Reset(enum ipa_ip_type ip)
|
|
{
|
|
int retval = 0;
|
|
|
|
if (!DeviceNodeIsOpened()) return false;
|
|
|
|
retval = ioctl(m_fd, IPA_IOC_RESET_RT, ip);
|
|
retval |= ioctl(m_fd, IPA_IOC_COMMIT_RT, ip);
|
|
if (retval)
|
|
{
|
|
IPACMERR("Failed resetting routing block.\n");
|
|
return false;
|
|
}
|
|
|
|
IPACMDBG_H("Reset command issued to IPA routing block.\n");
|
|
return true;
|
|
}
|
|
|
|
bool IPACM_Routing::GetRoutingTable(struct ipa_ioc_get_rt_tbl *routingTable)
|
|
{
|
|
int retval = 0;
|
|
|
|
if (!DeviceNodeIsOpened()) return false;
|
|
|
|
retval = ioctl(m_fd, IPA_IOC_GET_RT_TBL, routingTable);
|
|
if (retval)
|
|
{
|
|
IPACMERR("IPA_IOCTL_GET_RT_TBL ioctl failed, routingTable =0x%p, retval=0x%x.\n", routingTable, retval);
|
|
return false;
|
|
}
|
|
IPACMDBG_H("IPA_IOCTL_GET_RT_TBL ioctl issued to IPA routing block.\n");
|
|
/* put routing table right after successfully get routing table */
|
|
PutRoutingTable(routingTable->hdl);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool IPACM_Routing::PutRoutingTable(uint32_t routingTableHandle)
|
|
{
|
|
int retval = 0;
|
|
|
|
if (!DeviceNodeIsOpened()) return false;
|
|
|
|
retval = ioctl(m_fd, IPA_IOC_PUT_RT_TBL, routingTableHandle);
|
|
if (retval)
|
|
{
|
|
IPACMERR("IPA_IOCTL_PUT_RT_TBL ioctl failed.\n");
|
|
return false;
|
|
}
|
|
|
|
IPACMDBG_H("IPA_IOCTL_PUT_RT_TBL ioctl issued to IPA routing block.\n");
|
|
return true;
|
|
}
|
|
|
|
bool IPACM_Routing::DeleteRoutingHdl(uint32_t rt_rule_hdl, ipa_ip_type ip)
|
|
{
|
|
const uint8_t NUM_RULES = 1;
|
|
struct ipa_ioc_del_rt_rule *rt_rule;
|
|
struct ipa_rt_rule_del *rt_rule_entry;
|
|
bool res = true;
|
|
int len = 0;
|
|
|
|
if (rt_rule_hdl == 0)
|
|
{
|
|
IPACMERR(" No route handle passed. Ignoring it\n");
|
|
return res;
|
|
}
|
|
|
|
len = (sizeof(struct ipa_ioc_del_rt_rule)) + (NUM_RULES * sizeof(struct ipa_rt_rule_del));
|
|
rt_rule = (struct ipa_ioc_del_rt_rule *)malloc(len);
|
|
if (rt_rule == NULL)
|
|
{
|
|
IPACMERR("unable to allocate memory for del route rule\n");
|
|
return false;
|
|
}
|
|
|
|
memset(rt_rule, 0, len);
|
|
rt_rule->commit = 1;
|
|
rt_rule->num_hdls = NUM_RULES;
|
|
rt_rule->ip = ip;
|
|
|
|
rt_rule_entry = &rt_rule->hdl[0];
|
|
rt_rule_entry->status = -1;
|
|
rt_rule_entry->hdl = rt_rule_hdl;
|
|
|
|
IPACMDBG_H("Deleting Route hdl:(0x%x) with ip type: %d\n", rt_rule_entry->hdl, ip);
|
|
if ((false == DeleteRoutingRule(rt_rule)) ||
|
|
(rt_rule_entry->status))
|
|
{
|
|
PERROR("Routing rule deletion failed!\n");
|
|
goto fail;
|
|
res = false;
|
|
}
|
|
|
|
fail:
|
|
free(rt_rule);
|
|
|
|
return res;
|
|
}
|
|
|
|
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;
|
|
}
|