1 /*
2 Copyright (c) 2013, The Linux Foundation. All rights reserved.
3 
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are
6 met:
7 		* Redistributions of source code must retain the above copyright
8 			notice, this list of conditions and the following disclaimer.
9 		* Redistributions in binary form must reproduce the above
10 			copyright notice, this list of conditions and the following
11 			disclaimer in the documentation and/or other materials provided
12 			with the distribution.
13 		* Neither the name of The Linux Foundation nor the names of its
14 			contributors may be used to endorse or promote products derived
15 			from this software without specific prior written permission.
16 
17 THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 /*!
30 	@file
31 	IPACM_Routing.cpp
32 
33 	@brief
34 	This file implements the IPACM routing functionality.
35 
36 	@Author
37 
38 */
39 
40 #include <unistd.h>
41 #include <sys/ioctl.h>
42 #include <fcntl.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 
46 #include "IPACM_Routing.h"
47 #include <IPACM_Log.h>
48 
49 const char *IPACM_Routing::DEVICE_NAME = "/dev/ipa";
50 
IPACM_Routing()51 IPACM_Routing::IPACM_Routing()
52 {
53 	m_fd = open(DEVICE_NAME, O_RDWR);
54 	if (0 == m_fd)
55 	{
56 		IPACMERR("Failed opening %s.\n", DEVICE_NAME);
57 	}
58 }
59 
~IPACM_Routing()60 IPACM_Routing::~IPACM_Routing()
61 {
62 	close(m_fd);
63 }
64 
DeviceNodeIsOpened()65 bool IPACM_Routing::DeviceNodeIsOpened()
66 {
67 	int res = fcntl(m_fd, F_GETFL);
68 
69 	if (m_fd > 0 && res >= 0) return true;
70 	else return false;
71 
72 }
73 
AddRoutingRule(struct ipa_ioc_add_rt_rule * ruleTable)74 bool IPACM_Routing::AddRoutingRule(struct ipa_ioc_add_rt_rule *ruleTable)
75 {
76 	int retval = 0, cnt=0;
77 	bool isInvalid = false;
78 
79 	if (!DeviceNodeIsOpened())
80 	{
81 		IPACMERR("Device is not opened\n");
82 		return false;
83 	}
84 
85 	for(cnt=0; cnt<ruleTable->num_rules; cnt++)
86 	{
87 		if(ruleTable->rules[cnt].rule.dst > IPA_CLIENT_MAX)
88 		{
89 			IPACMERR("Invalid dst pipe, Rule:%d  dst_pipe:%d\n", cnt, ruleTable->rules[cnt].rule.dst);
90 			isInvalid = true;
91 		}
92 	}
93 
94 	if(isInvalid)
95 	{
96 		return false;
97 	}
98 
99 	retval = ioctl(m_fd, IPA_IOC_ADD_RT_RULE, ruleTable);
100 	if (retval)
101 	{
102 		IPACMERR("Failed adding routing rule %p\n", ruleTable);
103 		return false;
104 	}
105 
106 	for(cnt=0; cnt<ruleTable->num_rules; cnt++)
107 	{
108 		IPACMDBG("Rule:%d  dst_pipe:%d\n", cnt, ruleTable->rules[cnt].rule.dst);
109 	}
110 
111 	IPACMDBG_H("Added routing rule %p\n", ruleTable);
112 	return true;
113 }
114 
DeleteRoutingRule(struct ipa_ioc_del_rt_rule * ruleTable)115 bool IPACM_Routing::DeleteRoutingRule(struct ipa_ioc_del_rt_rule *ruleTable)
116 {
117 	int retval = 0;
118 
119 	if (!DeviceNodeIsOpened()) return false;
120 
121 	retval = ioctl(m_fd, IPA_IOC_DEL_RT_RULE, ruleTable);
122 	if (retval)
123 	{
124 		IPACMERR("Failed deleting routing rule table %p\n", ruleTable);
125 		return false;
126 	}
127 
128 	IPACMDBG_H("Deleted routing rule %p\n", ruleTable);
129 	return true;
130 }
131 
Commit(enum ipa_ip_type ip)132 bool IPACM_Routing::Commit(enum ipa_ip_type ip)
133 {
134 	int retval = 0;
135 
136 	if (!DeviceNodeIsOpened()) return false;
137 
138 	retval = ioctl(m_fd, IPA_IOC_COMMIT_RT, ip);
139 	if (retval)
140 	{
141 		IPACMERR("Failed commiting routing rules.\n");
142 		return false;
143 	}
144 
145 	IPACMDBG_H("Commited routing rules to IPA HW.\n");
146 	return true;
147 }
148 
Reset(enum ipa_ip_type ip)149 bool IPACM_Routing::Reset(enum ipa_ip_type ip)
150 {
151 	int retval = 0;
152 
153 	if (!DeviceNodeIsOpened()) return false;
154 
155 	retval = ioctl(m_fd, IPA_IOC_RESET_RT, ip);
156 	retval |= ioctl(m_fd, IPA_IOC_COMMIT_RT, ip);
157 	if (retval)
158 	{
159 		IPACMERR("Failed resetting routing block.\n");
160 		return false;
161 	}
162 
163 	IPACMDBG_H("Reset command issued to IPA routing block.\n");
164 	return true;
165 }
166 
GetRoutingTable(struct ipa_ioc_get_rt_tbl * routingTable)167 bool IPACM_Routing::GetRoutingTable(struct ipa_ioc_get_rt_tbl *routingTable)
168 {
169 	int retval = 0;
170 
171 	if (!DeviceNodeIsOpened()) return false;
172 
173 	retval = ioctl(m_fd, IPA_IOC_GET_RT_TBL, routingTable);
174 	if (retval)
175 	{
176 		IPACMERR("IPA_IOCTL_GET_RT_TBL ioctl failed, routingTable =0x%p, retval=0x%x.\n", routingTable, retval);
177 		return false;
178 	}
179 	IPACMDBG_H("IPA_IOCTL_GET_RT_TBL ioctl issued to IPA routing block.\n");
180 	/* put routing table right after successfully get routing table */
181 	PutRoutingTable(routingTable->hdl);
182 
183 	return true;
184 }
185 
PutRoutingTable(uint32_t routingTableHandle)186 bool IPACM_Routing::PutRoutingTable(uint32_t routingTableHandle)
187 {
188 	int retval = 0;
189 
190 	if (!DeviceNodeIsOpened()) return false;
191 
192 	retval = ioctl(m_fd, IPA_IOC_PUT_RT_TBL, routingTableHandle);
193 	if (retval)
194 	{
195 		IPACMERR("IPA_IOCTL_PUT_RT_TBL ioctl failed.\n");
196 		return false;
197 	}
198 
199 	IPACMDBG_H("IPA_IOCTL_PUT_RT_TBL ioctl issued to IPA routing block.\n");
200 	return true;
201 }
202 
DeleteRoutingHdl(uint32_t rt_rule_hdl,ipa_ip_type ip)203 bool IPACM_Routing::DeleteRoutingHdl(uint32_t rt_rule_hdl, ipa_ip_type ip)
204 {
205 	const uint8_t NUM_RULES = 1;
206 	struct ipa_ioc_del_rt_rule *rt_rule;
207 	struct ipa_rt_rule_del *rt_rule_entry;
208 	bool res = true;
209 	int len = 0;
210 
211 	if (rt_rule_hdl == 0)
212 	{
213 		IPACMERR(" No route handle passed. Ignoring it\n");
214 		return res;
215 	}
216 
217 	len = (sizeof(struct ipa_ioc_del_rt_rule)) + (NUM_RULES * sizeof(struct ipa_rt_rule_del));
218 	rt_rule = (struct ipa_ioc_del_rt_rule *)malloc(len);
219 	if (rt_rule == NULL)
220 	{
221 		IPACMERR("unable to allocate memory for del route rule\n");
222 		return false;
223 	}
224 
225 	memset(rt_rule, 0, len);
226 	rt_rule->commit = 1;
227 	rt_rule->num_hdls = NUM_RULES;
228 	rt_rule->ip = ip;
229 
230 	rt_rule_entry = &rt_rule->hdl[0];
231 	rt_rule_entry->status = -1;
232 	rt_rule_entry->hdl = rt_rule_hdl;
233 
234 	IPACMDBG_H("Deleting Route hdl:(0x%x) with ip type: %d\n", rt_rule_entry->hdl, ip);
235 	if ((false == DeleteRoutingRule(rt_rule)) ||
236 			(rt_rule_entry->status))
237 	{
238 		PERROR("Routing rule deletion failed!\n");
239 		goto fail;
240 		res = false;
241 	}
242 
243 fail:
244 	free(rt_rule);
245 
246 	return res;
247 }
248 
ModifyRoutingRule(struct ipa_ioc_mdfy_rt_rule * mdfyRules)249 bool IPACM_Routing::ModifyRoutingRule(struct ipa_ioc_mdfy_rt_rule *mdfyRules)
250 {
251 	int retval = 0, cnt;
252 
253 	if (!DeviceNodeIsOpened())
254 	{
255 		IPACMERR("Device is not opened\n");
256 		return false;
257 	}
258 
259 	retval = ioctl(m_fd, IPA_IOC_MDFY_RT_RULE, mdfyRules);
260 	if (retval)
261 	{
262 		IPACMERR("Failed modifying routing rules %p\n", mdfyRules);
263 		return false;
264 	}
265 
266 	for(cnt=0; cnt<mdfyRules->num_rules; cnt++)
267 	{
268 		if(mdfyRules->rules[cnt].status != 0)
269 		{
270 			IPACMERR("Unable to modify rule: %d\n", cnt);
271 		}
272 	}
273 
274 	IPACMDBG_H("Modified routing rules %p\n", mdfyRules);
275 	return true;
276 }
277