1 /*
2 Copyright (c) 2013-2016, 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_Filtering.cpp
32
33 @brief
34 This file implements the IPACM filtering functionality.
35
36 @Author
37 Skylar Chang
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_Filtering.h"
47 #include <IPACM_Log.h>
48 #include "IPACM_Defs.h"
49
50
51 const char *IPACM_Filtering::DEVICE_NAME = "/dev/ipa";
52
IPACM_Filtering()53 IPACM_Filtering::IPACM_Filtering()
54 {
55 fd = open(DEVICE_NAME, O_RDWR);
56 if (fd < 0)
57 {
58 IPACMERR("Failed opening %s.\n", DEVICE_NAME);
59 }
60 }
61
~IPACM_Filtering()62 IPACM_Filtering::~IPACM_Filtering()
63 {
64 close(fd);
65 }
66
DeviceNodeIsOpened()67 bool IPACM_Filtering::DeviceNodeIsOpened()
68 {
69 return fd;
70 }
71
AddFilteringRule(struct ipa_ioc_add_flt_rule const * ruleTable)72 bool IPACM_Filtering::AddFilteringRule(struct ipa_ioc_add_flt_rule const *ruleTable)
73 {
74 int retval = 0;
75
76 IPACMDBG("Printing filter add attributes\n");
77 IPACMDBG("ip type: %d\n", ruleTable->ip);
78 IPACMDBG("Number of rules: %d\n", ruleTable->num_rules);
79 IPACMDBG("End point: %d and global value: %d\n", ruleTable->ep, ruleTable->global);
80 IPACMDBG("commit value: %d\n", ruleTable->commit);
81 for (int cnt=0; cnt<ruleTable->num_rules; cnt++)
82 {
83 IPACMDBG("Filter rule:%d attrib mask: 0x%x\n", cnt,
84 ruleTable->rules[cnt].rule.attrib.attrib_mask);
85 }
86
87 retval = ioctl(fd, IPA_IOC_ADD_FLT_RULE, ruleTable);
88 if (retval != 0)
89 {
90 IPACMERR("Failed adding Filtering rule %p\n", ruleTable);
91 PERROR("unable to add filter rule:");
92
93 for (int cnt = 0; cnt < ruleTable->num_rules; cnt++)
94 {
95 if (ruleTable->rules[cnt].status != 0)
96 {
97 IPACMERR("Adding Filter rule:%d failed with status:%d\n",
98 cnt, ruleTable->rules[cnt].status);
99 }
100 }
101 return false;
102 }
103
104 for (int cnt = 0; cnt<ruleTable->num_rules; cnt++)
105 {
106 if(ruleTable->rules[cnt].status != 0)
107 {
108 IPACMERR("Adding Filter rule:%d failed with status:%d\n",
109 cnt, ruleTable->rules[cnt].status);
110 }
111 }
112
113 IPACMDBG("Added Filtering rule %p\n", ruleTable);
114 return true;
115 }
116
AddFilteringRuleAfter(struct ipa_ioc_add_flt_rule_after const * ruleTable)117 bool IPACM_Filtering::AddFilteringRuleAfter(struct ipa_ioc_add_flt_rule_after const *ruleTable)
118 {
119 #ifdef FEATURE_IPA_V3
120 int retval = 0;
121
122 IPACMDBG("Printing filter add attributes\n");
123 IPACMDBG("ip type: %d\n", ruleTable->ip);
124 IPACMDBG("Number of rules: %d\n", ruleTable->num_rules);
125 IPACMDBG("End point: %d\n", ruleTable->ep);
126 IPACMDBG("commit value: %d\n", ruleTable->commit);
127
128 retval = ioctl(fd, IPA_IOC_ADD_FLT_RULE_AFTER, ruleTable);
129
130 for (int cnt = 0; cnt<ruleTable->num_rules; cnt++)
131 {
132 if(ruleTable->rules[cnt].status != 0)
133 {
134 IPACMERR("Adding Filter rule:%d failed with status:%d\n",
135 cnt, ruleTable->rules[cnt].status);
136 }
137 }
138
139 if (retval != 0)
140 {
141 IPACMERR("Failed adding Filtering rule %p\n", ruleTable);
142 return false;
143 }
144 IPACMDBG("Added Filtering rule %p\n", ruleTable);
145 #endif
146 return true;
147 }
148
DeleteFilteringRule(struct ipa_ioc_del_flt_rule * ruleTable)149 bool IPACM_Filtering::DeleteFilteringRule(struct ipa_ioc_del_flt_rule *ruleTable)
150 {
151 int retval = 0;
152
153 retval = ioctl(fd, IPA_IOC_DEL_FLT_RULE, ruleTable);
154 if (retval != 0)
155 {
156 IPACMERR("Failed deleting Filtering rule %p\n", ruleTable);
157 return false;
158 }
159
160 IPACMDBG("Deleted Filtering rule %p\n", ruleTable);
161 return true;
162 }
163
Commit(enum ipa_ip_type ip)164 bool IPACM_Filtering::Commit(enum ipa_ip_type ip)
165 {
166 int retval = 0;
167
168 retval = ioctl(fd, IPA_IOC_COMMIT_FLT, ip);
169 if (retval != 0)
170 {
171 IPACMERR("failed committing Filtering rules.\n");
172 return false;
173 }
174
175 IPACMDBG("Committed Filtering rules to IPA HW.\n");
176 return true;
177 }
178
Reset(enum ipa_ip_type ip)179 bool IPACM_Filtering::Reset(enum ipa_ip_type ip)
180 {
181 int retval = 0;
182
183 retval = ioctl(fd, IPA_IOC_RESET_FLT, ip);
184 retval |= ioctl(fd, IPA_IOC_COMMIT_FLT, ip);
185 if (retval)
186 {
187 IPACMERR("failed resetting Filtering block.\n");
188 return false;
189 }
190
191 IPACMDBG("Reset command issued to IPA Filtering block.\n");
192 return true;
193 }
194
DeleteFilteringHdls(uint32_t * flt_rule_hdls,ipa_ip_type ip,uint8_t num_rules)195 bool IPACM_Filtering::DeleteFilteringHdls
196 (
197 uint32_t *flt_rule_hdls,
198 ipa_ip_type ip,
199 uint8_t num_rules
200 )
201 {
202 struct ipa_ioc_del_flt_rule *flt_rule;
203 bool res = true;
204 int len = 0, cnt = 0;
205 const uint8_t UNIT_RULES = 1;
206
207 len = (sizeof(struct ipa_ioc_del_flt_rule)) + (UNIT_RULES * sizeof(struct ipa_flt_rule_del));
208 flt_rule = (struct ipa_ioc_del_flt_rule *)malloc(len);
209 if (flt_rule == NULL)
210 {
211 IPACMERR("unable to allocate memory for del filter rule\n");
212 return false;
213 }
214
215 for (cnt = 0; cnt < num_rules; cnt++)
216 {
217 memset(flt_rule, 0, len);
218 flt_rule->commit = 1;
219 flt_rule->num_hdls = UNIT_RULES;
220 flt_rule->ip = ip;
221
222 if (flt_rule_hdls[cnt] == 0)
223 {
224 IPACMERR("invalid filter handle passed, ignoring it: %d\n", cnt)
225 }
226 else
227 {
228
229 flt_rule->hdl[0].status = -1;
230 flt_rule->hdl[0].hdl = flt_rule_hdls[cnt];
231 IPACMDBG("Deleting filter hdl:(0x%x) with ip type: %d\n", flt_rule_hdls[cnt], ip);
232
233 if (DeleteFilteringRule(flt_rule) == false)
234 {
235 PERROR("Filter rule deletion failed!\n");
236 res = false;
237 goto fail;
238 }
239 else
240 {
241
242 if (flt_rule->hdl[0].status != 0)
243 {
244 IPACMERR("Filter rule hdl 0x%x deletion failed with error:%d\n",
245 flt_rule->hdl[0].hdl, flt_rule->hdl[0].status);
246 res = false;
247 goto fail;
248 }
249 }
250 }
251 }
252
253 fail:
254 free(flt_rule);
255
256 return res;
257 }
258
AddWanDLFilteringRule(struct ipa_ioc_add_flt_rule const * rule_table_v4,struct ipa_ioc_add_flt_rule const * rule_table_v6,uint8_t mux_id)259 bool IPACM_Filtering::AddWanDLFilteringRule(struct ipa_ioc_add_flt_rule const *rule_table_v4, struct ipa_ioc_add_flt_rule const * rule_table_v6, uint8_t mux_id)
260 {
261 int ret = 0, cnt, num_rules = 0, pos = 0;
262 ipa_install_fltr_rule_req_msg_v01 qmi_rule_msg;
263 #ifdef FEATURE_IPA_V3
264 ipa_install_fltr_rule_req_ex_msg_v01 qmi_rule_ex_msg;
265 #endif
266
267 memset(&qmi_rule_msg, 0, sizeof(qmi_rule_msg));
268 int fd_wwan_ioctl = open(WWAN_QMI_IOCTL_DEVICE_NAME, O_RDWR);
269 if(fd_wwan_ioctl < 0)
270 {
271 IPACMERR("Failed to open %s.\n",WWAN_QMI_IOCTL_DEVICE_NAME);
272 return false;
273 }
274
275 if(rule_table_v4 != NULL)
276 {
277 num_rules += rule_table_v4->num_rules;
278 IPACMDBG_H("Get %d WAN DL IPv4 filtering rules.\n", rule_table_v4->num_rules);
279 }
280 if(rule_table_v6 != NULL)
281 {
282 num_rules += rule_table_v6->num_rules;
283 IPACMDBG_H("Get %d WAN DL IPv6 filtering rules.\n", rule_table_v6->num_rules);
284 }
285
286 /* if it is not IPA v3, use old QMI format */
287 #ifndef FEATURE_IPA_V3
288 if(num_rules > QMI_IPA_MAX_FILTERS_V01)
289 {
290 IPACMERR("The number of filtering rules exceed limit.\n");
291 close(fd_wwan_ioctl);
292 return false;
293 }
294 else
295 {
296 if (num_rules > 0)
297 {
298 qmi_rule_msg.filter_spec_list_valid = true;
299 }
300 else
301 {
302 qmi_rule_msg.filter_spec_list_valid = false;
303 }
304
305 qmi_rule_msg.filter_spec_list_len = num_rules;
306 qmi_rule_msg.source_pipe_index_valid = 0;
307
308 IPACMDBG_H("Get %d WAN DL filtering rules in total.\n", num_rules);
309
310 if(rule_table_v4 != NULL)
311 {
312 for(cnt = rule_table_v4->num_rules - 1; cnt >= 0; cnt--)
313 {
314 if (pos < QMI_IPA_MAX_FILTERS_V01)
315 {
316 qmi_rule_msg.filter_spec_list[pos].filter_spec_identifier = pos;
317 qmi_rule_msg.filter_spec_list[pos].ip_type = QMI_IPA_IP_TYPE_V4_V01;
318 qmi_rule_msg.filter_spec_list[pos].filter_action = GetQmiFilterAction(rule_table_v4->rules[cnt].rule.action);
319 qmi_rule_msg.filter_spec_list[pos].is_routing_table_index_valid = 1;
320 qmi_rule_msg.filter_spec_list[pos].route_table_index = rule_table_v4->rules[cnt].rule.rt_tbl_idx;
321 qmi_rule_msg.filter_spec_list[pos].is_mux_id_valid = 1;
322 qmi_rule_msg.filter_spec_list[pos].mux_id = mux_id;
323 memcpy(&qmi_rule_msg.filter_spec_list[pos].filter_rule,
324 &rule_table_v4->rules[cnt].rule.eq_attrib,
325 sizeof(struct ipa_filter_rule_type_v01));
326 pos++;
327 }
328 else
329 {
330 IPACMERR(" QMI only support max %d rules, current (%d)\n ",QMI_IPA_MAX_FILTERS_V01, pos);
331 }
332 }
333 }
334
335 if(rule_table_v6 != NULL)
336 {
337 for(cnt = rule_table_v6->num_rules - 1; cnt >= 0; cnt--)
338 {
339 if (pos < QMI_IPA_MAX_FILTERS_V01)
340 {
341 qmi_rule_msg.filter_spec_list[pos].filter_spec_identifier = pos;
342 qmi_rule_msg.filter_spec_list[pos].ip_type = QMI_IPA_IP_TYPE_V6_V01;
343 qmi_rule_msg.filter_spec_list[pos].filter_action = GetQmiFilterAction(rule_table_v6->rules[cnt].rule.action);
344 qmi_rule_msg.filter_spec_list[pos].is_routing_table_index_valid = 1;
345 qmi_rule_msg.filter_spec_list[pos].route_table_index = rule_table_v6->rules[cnt].rule.rt_tbl_idx;
346 qmi_rule_msg.filter_spec_list[pos].is_mux_id_valid = 1;
347 qmi_rule_msg.filter_spec_list[pos].mux_id = mux_id;
348 memcpy(&qmi_rule_msg.filter_spec_list[pos].filter_rule,
349 &rule_table_v6->rules[cnt].rule.eq_attrib,
350 sizeof(struct ipa_filter_rule_type_v01));
351 pos++;
352 }
353 else
354 {
355 IPACMERR(" QMI only support max %d rules, current (%d)\n ",QMI_IPA_MAX_FILTERS_V01, pos);
356 }
357 }
358 }
359
360 ret = ioctl(fd_wwan_ioctl, WAN_IOC_ADD_FLT_RULE, &qmi_rule_msg);
361 if (ret != 0)
362 {
363 IPACMERR("Failed adding Filtering rule %p with ret %d\n ", &qmi_rule_msg, ret);
364 close(fd_wwan_ioctl);
365 return false;
366 }
367 }
368 /* if it is IPA v3, use new QMI format */
369 #else
370 if(num_rules > QMI_IPA_MAX_FILTERS_EX_V01)
371 {
372 IPACMERR("The number of filtering rules exceed limit.\n");
373 close(fd_wwan_ioctl);
374 return false;
375 }
376 else
377 {
378 memset(&qmi_rule_ex_msg, 0, sizeof(qmi_rule_ex_msg));
379
380 if (num_rules > 0)
381 {
382 qmi_rule_ex_msg.filter_spec_ex_list_valid = true;
383 }
384 else
385 {
386 qmi_rule_ex_msg.filter_spec_ex_list_valid = false;
387 }
388 qmi_rule_ex_msg.filter_spec_ex_list_len = num_rules;
389 qmi_rule_ex_msg.source_pipe_index_valid = 0;
390
391 IPACMDBG_H("Get %d WAN DL filtering rules in total.\n", num_rules);
392
393 if(rule_table_v4 != NULL)
394 {
395 for(cnt = rule_table_v4->num_rules - 1; cnt >= 0; cnt--)
396 {
397 if (pos < QMI_IPA_MAX_FILTERS_EX_V01)
398 {
399 qmi_rule_ex_msg.filter_spec_ex_list[pos].ip_type = QMI_IPA_IP_TYPE_V4_V01;
400 qmi_rule_ex_msg.filter_spec_ex_list[pos].filter_action = GetQmiFilterAction(rule_table_v4->rules[cnt].rule.action);
401 qmi_rule_ex_msg.filter_spec_ex_list[pos].is_routing_table_index_valid = 1;
402 qmi_rule_ex_msg.filter_spec_ex_list[pos].route_table_index = rule_table_v4->rules[cnt].rule.rt_tbl_idx;
403 qmi_rule_ex_msg.filter_spec_ex_list[pos].is_mux_id_valid = 1;
404 qmi_rule_ex_msg.filter_spec_ex_list[pos].mux_id = mux_id;
405 qmi_rule_ex_msg.filter_spec_ex_list[pos].rule_id = rule_table_v4->rules[cnt].rule.rule_id;
406 qmi_rule_ex_msg.filter_spec_ex_list[pos].is_rule_hashable = rule_table_v4->rules[cnt].rule.hashable;
407 memcpy(&qmi_rule_ex_msg.filter_spec_ex_list[pos].filter_rule,
408 &rule_table_v4->rules[cnt].rule.eq_attrib,
409 sizeof(struct ipa_filter_rule_type_v01));
410
411 pos++;
412 }
413 else
414 {
415 IPACMERR(" QMI only support max %d rules, current (%d)\n ",QMI_IPA_MAX_FILTERS_EX_V01, pos);
416 }
417 }
418 }
419
420 if(rule_table_v6 != NULL)
421 {
422 for(cnt = rule_table_v6->num_rules - 1; cnt >= 0; cnt--)
423 {
424 if (pos < QMI_IPA_MAX_FILTERS_EX_V01)
425 {
426 qmi_rule_ex_msg.filter_spec_ex_list[pos].ip_type = QMI_IPA_IP_TYPE_V6_V01;
427 qmi_rule_ex_msg.filter_spec_ex_list[pos].filter_action = GetQmiFilterAction(rule_table_v6->rules[cnt].rule.action);
428 qmi_rule_ex_msg.filter_spec_ex_list[pos].is_routing_table_index_valid = 1;
429 qmi_rule_ex_msg.filter_spec_ex_list[pos].route_table_index = rule_table_v6->rules[cnt].rule.rt_tbl_idx;
430 qmi_rule_ex_msg.filter_spec_ex_list[pos].is_mux_id_valid = 1;
431 qmi_rule_ex_msg.filter_spec_ex_list[pos].mux_id = mux_id;
432 qmi_rule_ex_msg.filter_spec_ex_list[pos].rule_id = rule_table_v6->rules[cnt].rule.rule_id;
433 qmi_rule_ex_msg.filter_spec_ex_list[pos].is_rule_hashable = rule_table_v6->rules[cnt].rule.hashable;
434 memcpy(&qmi_rule_ex_msg.filter_spec_ex_list[pos].filter_rule,
435 &rule_table_v6->rules[cnt].rule.eq_attrib,
436 sizeof(struct ipa_filter_rule_type_v01));
437
438 pos++;
439 }
440 else
441 {
442 IPACMERR(" QMI only support max %d rules, current (%d)\n ",QMI_IPA_MAX_FILTERS_EX_V01, pos);
443 }
444 }
445 }
446
447 ret = ioctl(fd_wwan_ioctl, WAN_IOC_ADD_FLT_RULE_EX, &qmi_rule_ex_msg);
448 if (ret != 0)
449 {
450 IPACMERR("Failed adding Filtering rule %p with ret %d\n ", &qmi_rule_ex_msg, ret);
451 close(fd_wwan_ioctl);
452 return false;
453 }
454 }
455 #endif
456
457 close(fd_wwan_ioctl);
458 return true;
459 }
460
SendFilteringRuleIndex(struct ipa_fltr_installed_notif_req_msg_v01 * table)461 bool IPACM_Filtering::SendFilteringRuleIndex(struct ipa_fltr_installed_notif_req_msg_v01* table)
462 {
463 int ret = 0;
464 int fd_wwan_ioctl = open(WWAN_QMI_IOCTL_DEVICE_NAME, O_RDWR);
465 if(fd_wwan_ioctl < 0)
466 {
467 IPACMERR("Failed to open %s.\n",WWAN_QMI_IOCTL_DEVICE_NAME);
468 return false;
469 }
470
471 ret = ioctl(fd_wwan_ioctl, WAN_IOC_ADD_FLT_RULE_INDEX, table);
472 if (ret != 0)
473 {
474 IPACMERR("Failed adding filtering rule index %p with ret %d\n", table, ret);
475 close(fd_wwan_ioctl);
476 return false;
477 }
478
479 IPACMDBG("Added Filtering rule index %p\n", table);
480 close(fd_wwan_ioctl);
481 return true;
482 }
483
GetQmiFilterAction(ipa_flt_action action)484 ipa_filter_action_enum_v01 IPACM_Filtering::GetQmiFilterAction(ipa_flt_action action)
485 {
486 switch(action)
487 {
488 case IPA_PASS_TO_ROUTING:
489 return QMI_IPA_FILTER_ACTION_ROUTING_V01;
490
491 case IPA_PASS_TO_SRC_NAT:
492 return QMI_IPA_FILTER_ACTION_SRC_NAT_V01;
493
494 case IPA_PASS_TO_DST_NAT:
495 return QMI_IPA_FILTER_ACTION_DST_NAT_V01;
496
497 case IPA_PASS_TO_EXCEPTION:
498 return QMI_IPA_FILTER_ACTION_EXCEPTION_V01;
499
500 default:
501 return IPA_FILTER_ACTION_ENUM_MAX_ENUM_VAL_V01;
502 }
503 }
504
ModifyFilteringRule(struct ipa_ioc_mdfy_flt_rule * ruleTable)505 bool IPACM_Filtering::ModifyFilteringRule(struct ipa_ioc_mdfy_flt_rule* ruleTable)
506 {
507 int i, ret = 0;
508
509 IPACMDBG("Printing filtering add attributes\n");
510 IPACMDBG("IP type: %d Number of rules: %d commit value: %d\n", ruleTable->ip, ruleTable->num_rules, ruleTable->commit);
511
512 for (i=0; i<ruleTable->num_rules; i++)
513 {
514 IPACMDBG("Filter rule:%d attrib mask: 0x%x\n", i, ruleTable->rules[i].rule.attrib.attrib_mask);
515 }
516
517 ret = ioctl(fd, IPA_IOC_MDFY_FLT_RULE, ruleTable);
518 if (ret != 0)
519 {
520 IPACMERR("Failed modifying filtering rule %p\n", ruleTable);
521
522 for (i = 0; i < ruleTable->num_rules; i++)
523 {
524 if (ruleTable->rules[i].status != 0)
525 {
526 IPACMERR("Modifying filter rule %d failed\n", i);
527 }
528 }
529 return false;
530 }
531
532 IPACMDBG("Modified filtering rule %p\n", ruleTable);
533 return true;
534 }
535
536