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 
115 #ifdef IPA_IOCTL_SET_FNR_COUNTER_INFO
AddRoutingRule_hw_index(struct ipa_ioc_add_rt_rule * ruleTable,int hw_counter_index)116 bool IPACM_Routing::AddRoutingRule_hw_index(struct ipa_ioc_add_rt_rule *ruleTable, int hw_counter_index)
117 {
118 	int retval = 0, cnt = 0, len = 0;
119 	struct ipa_ioc_add_rt_rule_v2 *ruleTable_v2;
120 	struct ipa_rt_rule_add_v2 rt_rule_entry;
121 	bool ret = true;
122 
123 	IPACMDBG("Printing routing add attributes\n");
124 	IPACMDBG("ip type: %d\n", ruleTable->ip);
125 	IPACMDBG("rt tbl type: %s\n", ruleTable->rt_tbl_name);
126 	IPACMDBG("Number of rules: %d\n", ruleTable->num_rules);
127 	IPACMDBG("commit value: %d\n", ruleTable->commit);
128 
129 	/* change to v2 format*/
130 	len = sizeof(struct ipa_ioc_add_rt_rule_v2);
131 	ruleTable_v2 = (struct ipa_ioc_add_rt_rule_v2*)malloc(len);
132 	if (ruleTable_v2 == NULL)
133 	{
134 		IPACMERR("Error Locate ipa_ioc_add_rt_rule_v2 memory...\n");
135 		return false;
136 	}
137 	memset(ruleTable_v2, 0, len);
138 	ruleTable_v2->rules = (uint64_t)calloc(ruleTable->num_rules, sizeof(struct ipa_rt_rule_add_v2));
139 	if (!ruleTable_v2->rules) {
140 		IPACMERR("Failed to allocate memory for routing rules\n");
141 		ret = false;
142 		goto fail_tbl;
143 	}
144 
145 	ruleTable_v2->commit = ruleTable->commit;
146 	ruleTable_v2->ip = ruleTable->ip;
147 	ruleTable_v2->num_rules = ruleTable->num_rules;
148 	ruleTable_v2->rule_add_size = sizeof(struct ipa_rt_rule_add_v2);
149 	memcpy(ruleTable_v2->rt_tbl_name,
150 		 ruleTable->rt_tbl_name,
151 		 sizeof(ruleTable_v2->rt_tbl_name));
152 
153 	for (cnt=0; cnt < ruleTable->num_rules; cnt++)
154 	{
155 		memset(&rt_rule_entry, 0, sizeof(struct ipa_rt_rule_add_v2));
156 		rt_rule_entry.at_rear = ruleTable->rules[cnt].at_rear;
157 		rt_rule_entry.rule.dst = ruleTable->rules[cnt].rule.dst;
158 		rt_rule_entry.rule.hdr_hdl = ruleTable->rules[cnt].rule.hdr_hdl;
159 		rt_rule_entry.rule.hdr_proc_ctx_hdl = ruleTable->rules[cnt].rule.hdr_proc_ctx_hdl;
160 		rt_rule_entry.rule.max_prio = ruleTable->rules[cnt].rule.max_prio;
161 		rt_rule_entry.rule.hashable = ruleTable->rules[cnt].rule.hashable;
162 		rt_rule_entry.rule.retain_hdr = ruleTable->rules[cnt].rule.retain_hdr;
163 		rt_rule_entry.rule.coalesce = ruleTable->rules[cnt].rule.coalesce;
164 		memcpy(&rt_rule_entry.rule.attrib,
165 					 &ruleTable->rules[cnt].rule.attrib,
166 					 sizeof(rt_rule_entry.rule.attrib));
167 		IPACMDBG("RT rule:%d attrib mask: 0x%x\n", cnt,
168 				ruleTable->rules[cnt].rule.attrib.attrib_mask);
169 		/* 0 means disable hw-counter-sats */
170 		if (hw_counter_index != 0)
171 		{
172 			rt_rule_entry.rule.enable_stats = 1;
173 			rt_rule_entry.rule.cnt_idx = hw_counter_index;
174 		}
175 
176 		/* copy to v2 table*/
177 		memcpy((void *)(ruleTable_v2->rules + (cnt * sizeof(struct ipa_rt_rule_add_v2))),
178 			&rt_rule_entry, sizeof(rt_rule_entry));
179 	}
180 
181 	retval = ioctl(m_fd, IPA_IOC_ADD_RT_RULE_V2, ruleTable_v2);
182 	if (retval != 0)
183 	{
184 		IPACMERR("Failed adding Routing rule %pK\n", ruleTable_v2);
185 		PERROR("unable to add routing rule:");
186 
187 		for (int cnt = 0; cnt < ruleTable_v2->num_rules; cnt++)
188 		{
189 			if (((struct ipa_rt_rule_add_v2 *)ruleTable_v2->rules)[cnt].status != 0)
190 			{
191 				IPACMERR("Adding Routing rule:%d failed with status:%d\n",
192 								 cnt, ((struct ipa_rt_rule_add_v2 *)ruleTable_v2->rules)[cnt].status);
193 			}
194 		}
195 		ret = false;
196 		goto fail_rule;
197 	}
198 
199 	/* copy results from v2 to v1 format */
200 	for (int cnt = 0; cnt < ruleTable->num_rules; cnt++)
201 	{
202 		/* copy status to v1 format */
203 		ruleTable->rules[cnt].status = ((struct ipa_rt_rule_add_v2 *)ruleTable_v2->rules)[cnt].status;
204 		ruleTable->rules[cnt].rt_rule_hdl = ((struct ipa_rt_rule_add_v2 *)ruleTable_v2->rules)[cnt].rt_rule_hdl;
205 
206 		if(((struct ipa_rt_rule_add_v2 *)ruleTable_v2->rules)[cnt].status != 0)
207 		{
208 			IPACMERR("Adding Routing rule:%d failed with status:%d\n",
209 							 cnt, ((struct ipa_rt_rule_add_v2 *) ruleTable_v2->rules)[cnt].status);
210 		}
211 	}
212 	IPACMDBG("Added Routing rule %pK\n", ruleTable_v2);
213 fail_rule:
214 	if((void *)ruleTable_v2->rules != NULL)
215 		free((void *)ruleTable_v2->rules);
216 fail_tbl:
217 	if (ruleTable_v2 != NULL)
218 		free(ruleTable_v2);
219 	return ret;
220 }
221 #endif //IPA_IOCTL_SET_FNR_COUNTER_INFO
222 
223 
DeleteRoutingRule(struct ipa_ioc_del_rt_rule * ruleTable)224 bool IPACM_Routing::DeleteRoutingRule(struct ipa_ioc_del_rt_rule *ruleTable)
225 {
226 	int retval = 0;
227 
228 	if (!DeviceNodeIsOpened()) return false;
229 
230 	retval = ioctl(m_fd, IPA_IOC_DEL_RT_RULE, ruleTable);
231 	if (retval)
232 	{
233 		IPACMERR("Failed deleting routing rule table %p\n", ruleTable);
234 		return false;
235 	}
236 
237 	IPACMDBG_H("Deleted routing rule %p\n", ruleTable);
238 	return true;
239 }
240 
Commit(enum ipa_ip_type ip)241 bool IPACM_Routing::Commit(enum ipa_ip_type ip)
242 {
243 	int retval = 0;
244 
245 	if (!DeviceNodeIsOpened()) return false;
246 
247 	retval = ioctl(m_fd, IPA_IOC_COMMIT_RT, ip);
248 	if (retval)
249 	{
250 		IPACMERR("Failed commiting routing rules.\n");
251 		return false;
252 	}
253 
254 	IPACMDBG_H("Commited routing rules to IPA HW.\n");
255 	return true;
256 }
257 
Reset(enum ipa_ip_type ip)258 bool IPACM_Routing::Reset(enum ipa_ip_type ip)
259 {
260 	int retval = 0;
261 
262 	if (!DeviceNodeIsOpened()) return false;
263 
264 	retval = ioctl(m_fd, IPA_IOC_RESET_RT, ip);
265 	retval |= ioctl(m_fd, IPA_IOC_COMMIT_RT, ip);
266 	if (retval)
267 	{
268 		IPACMERR("Failed resetting routing block.\n");
269 		return false;
270 	}
271 
272 	IPACMDBG_H("Reset command issued to IPA routing block.\n");
273 	return true;
274 }
275 
GetRoutingTable(struct ipa_ioc_get_rt_tbl * routingTable)276 bool IPACM_Routing::GetRoutingTable(struct ipa_ioc_get_rt_tbl *routingTable)
277 {
278 	int retval = 0;
279 
280 	if (!DeviceNodeIsOpened()) return false;
281 
282 	retval = ioctl(m_fd, IPA_IOC_GET_RT_TBL, routingTable);
283 	if (retval)
284 	{
285 		IPACMERR("IPA_IOCTL_GET_RT_TBL ioctl failed, routingTable =0x%p, retval=0x%x.\n", routingTable, retval);
286 		return false;
287 	}
288 	IPACMDBG_H("IPA_IOCTL_GET_RT_TBL ioctl issued to IPA routing block.\n");
289 	/* put routing table right after successfully get routing table */
290 	PutRoutingTable(routingTable->hdl);
291 
292 	return true;
293 }
294 
PutRoutingTable(uint32_t routingTableHandle)295 bool IPACM_Routing::PutRoutingTable(uint32_t routingTableHandle)
296 {
297 	int retval = 0;
298 
299 	if (!DeviceNodeIsOpened()) return false;
300 
301 	retval = ioctl(m_fd, IPA_IOC_PUT_RT_TBL, routingTableHandle);
302 	if (retval)
303 	{
304 		IPACMERR("IPA_IOCTL_PUT_RT_TBL ioctl failed.\n");
305 		return false;
306 	}
307 
308 	IPACMDBG_H("IPA_IOCTL_PUT_RT_TBL ioctl issued to IPA routing block.\n");
309 	return true;
310 }
311 
DeleteRoutingHdl(uint32_t rt_rule_hdl,ipa_ip_type ip)312 bool IPACM_Routing::DeleteRoutingHdl(uint32_t rt_rule_hdl, ipa_ip_type ip)
313 {
314 	const uint8_t NUM_RULES = 1;
315 	struct ipa_ioc_del_rt_rule *rt_rule;
316 	struct ipa_rt_rule_del *rt_rule_entry;
317 	bool res = true;
318 	int len = 0;
319 
320 	if (rt_rule_hdl == 0)
321 	{
322 		IPACMERR(" No route handle passed. Ignoring it\n");
323 		return res;
324 	}
325 
326 	len = (sizeof(struct ipa_ioc_del_rt_rule)) + (NUM_RULES * sizeof(struct ipa_rt_rule_del));
327 	rt_rule = (struct ipa_ioc_del_rt_rule *)malloc(len);
328 	if (rt_rule == NULL)
329 	{
330 		IPACMERR("unable to allocate memory for del route rule\n");
331 		return false;
332 	}
333 
334 	memset(rt_rule, 0, len);
335 	rt_rule->commit = 1;
336 	rt_rule->num_hdls = NUM_RULES;
337 	rt_rule->ip = ip;
338 
339 	rt_rule_entry = &rt_rule->hdl[0];
340 	rt_rule_entry->status = -1;
341 	rt_rule_entry->hdl = rt_rule_hdl;
342 
343 	IPACMDBG_H("Deleting Route hdl:(0x%x) with ip type: %d\n", rt_rule_entry->hdl, ip);
344 	if ((false == DeleteRoutingRule(rt_rule)) ||
345 			(rt_rule_entry->status))
346 	{
347 		PERROR("Routing rule deletion failed!\n");
348 		goto fail;
349 		res = false;
350 	}
351 
352 fail:
353 	free(rt_rule);
354 
355 	return res;
356 }
357 
ModifyRoutingRule(struct ipa_ioc_mdfy_rt_rule * mdfyRules)358 bool IPACM_Routing::ModifyRoutingRule(struct ipa_ioc_mdfy_rt_rule *mdfyRules)
359 {
360 	int retval = 0, cnt;
361 
362 	if (!DeviceNodeIsOpened())
363 	{
364 		IPACMERR("Device is not opened\n");
365 		return false;
366 	}
367 
368 	retval = ioctl(m_fd, IPA_IOC_MDFY_RT_RULE, mdfyRules);
369 	if (retval)
370 	{
371 		IPACMERR("Failed modifying routing rules %p\n", mdfyRules);
372 		return false;
373 	}
374 
375 	for(cnt=0; cnt<mdfyRules->num_rules; cnt++)
376 	{
377 		if(mdfyRules->rules[cnt].status != 0)
378 		{
379 			IPACMERR("Unable to modify rule: %d\n", cnt);
380 		}
381 	}
382 
383 	IPACMDBG_H("Modified routing rules %p\n", mdfyRules);
384 	return true;
385 }
386