1 /*
2  * Copyright 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "packet_dependency.h"
18 
19 #include <algorithm>
20 #include <list>
21 #include <set>
22 
PacketDependency(const ParentDef * root)23 PacketDependency::PacketDependency(const ParentDef* root) {
24   std::map<std::string, std::set<std::string>> initial_parse_and_match_fields;
25   std::vector<std::string> available_fields;
26   CollectInitialParseAndMatchFields(root, initial_parse_and_match_fields);
27   FinalizeParseAndMatchFields(root, initial_parse_and_match_fields, available_fields);
28 }
29 
GetDependencies(const std::string & packet_name)30 std::vector<std::string>& PacketDependency::GetDependencies(const std::string& packet_name) {
31   return dependencies[packet_name];
32 }
33 
GetChildrenDependencies(const std::string & packet_name)34 std::vector<std::string>& PacketDependency::GetChildrenDependencies(
35     const std::string& packet_name) {
36   return children_dependencies[packet_name];
37 }
38 
CollectInitialParseAndMatchFields(const ParentDef * parent,std::map<std::string,std::set<std::string>> & initial_parse_and_match_fields) const39 std::set<std::string> PacketDependency::CollectInitialParseAndMatchFields(
40     const ParentDef* parent,
41     std::map<std::string, std::set<std::string>>& initial_parse_and_match_fields) const {
42   // Case Leaf Packet: Return all of its constraints
43   if (parent->children_.empty()) {
44     auto constraints = parent->GetAllConstraints();
45     auto constraints_set = std::set<std::string>{};
46     for (auto& c : constraints) {
47       constraints_set.insert(c.first);
48     }
49     return constraints_set;
50   }
51 
52   auto children_constraints = std::set<std::string>{};
53   auto parent_constraints = parent->GetAllConstraints();
54   auto parent_fields = parent->fields_;
55 
56   for (const auto child : parent->children_) {
57     auto constraints = CollectInitialParseAndMatchFields(child, initial_parse_and_match_fields);
58     auto child_only_constraints = std::set<std::string>{};
59     for (auto c : constraints) {
60       //             __PARENT__
61       //          c1/   c2|     \c3
62       //           /      |      \.
63       //         CH1     CH2     CH3
64       //        c4|
65       //          |
66       //        CH11
67       // GetAllConstraints on leaf packet CH11 will return (C4, c1)
68       // GetAllConstraints on packet CH1 will return C1
69       // Thus CH11 only constraint is: (C4, C1) - (C1) => (C4)
70       if (parent_constraints.find(c) == parent_constraints.end()) {
71         child_only_constraints.insert(c);
72       }
73       // If the constraint can be satisfied by the immediate parent, no need to accumulate it
74       if (parent_fields.GetField(c) != nullptr) {
75         continue;
76       }
77       // Accumulate constraints from all the children so parent packet can accurately
78       // figure out which constraints it should be getting from its parents.
79       children_constraints.insert(c);
80     }
81     // child_only_constraints contains the variables required to be passed in when calling parse
82     initial_parse_and_match_fields[child->name_] = child_only_constraints;
83   }
84   return children_constraints;
85 }
86 
FinalizeParseAndMatchFields(const ParentDef * parent,std::map<std::string,std::set<std::string>> & initial_parse_and_match_fields,std::vector<std::string> & available_fields)87 void PacketDependency::FinalizeParseAndMatchFields(
88     const ParentDef* parent,
89     std::map<std::string, std::set<std::string>>& initial_parse_and_match_fields,
90     std::vector<std::string>& available_fields) {
91   // Root does not have any constraints on anything
92   if (parent->parent_ == nullptr) {
93     dependencies[parent->name_] = std::vector<std::string>{};
94     children_dependencies[parent->name_] = std::vector<std::string>{};
95   }
96 
97   // Collect the available fields, required to fix the order of pass and match vectors
98   for (auto& pf : parent->fields_) {
99     available_fields.push_back(pf->GetName());
100   }
101 
102   auto children_constraints_to_me = std::set<std::string>{};
103   children_dependencies[parent->name_] = std::vector<std::string>{};
104 
105   // Accumulate direct constraints from all the children to parent
106   //             __PARENT__
107   //          c1/   c2|     \c3
108   //           /      |      \.
109   //         CH1     CH2     CH3
110   //        c4|
111   //          |
112   //        CH11
113   // For this case: children_constraints_to_me = (c1, c2, c3)
114   for (auto& child : parent->children_) {
115     for (auto pcons : child->parent_constraints_) {
116       children_constraints_to_me.insert(pcons.first);
117     }
118   }
119 
120   // If children constraints to the parent are (c1, c2, c3) and so far parent has
121   // fields (c1, c2) available, then parent will match its children on (c1, c2)
122   for (auto avf : available_fields) {
123     if (children_constraints_to_me.find(avf) != children_constraints_to_me.end()) {
124       auto& match_variables = children_dependencies[parent->name_];
125       if (std::find(match_variables.begin(), match_variables.end(), avf) == match_variables.end()) {
126         match_variables.push_back(avf);
127       }
128     }
129   }
130 
131   for (auto& child : parent->children_) {
132     auto child_initial_parse_params = initial_parse_and_match_fields[child->name_];
133     auto child_actual_parse_params = std::vector<std::string>{};
134 
135     // Remove all the params from parse method of this child
136     // if these variables are the ones parent will match its children.
137     for (auto pcons : child->parent_constraints_) {
138       child_initial_parse_params.erase(pcons.first);
139     }
140 
141     // Store unique vars from child_initial_parse_params to child_actual_parse_params
142     // in the same order as fields are defined in the packets
143     for (auto avf : available_fields) {
144       if (child_initial_parse_params.find(avf) != child_initial_parse_params.end()) {
145         child_actual_parse_params.push_back(avf);
146       }
147     }
148     dependencies[child->name_] = child_actual_parse_params;
149     FinalizeParseAndMatchFields(child, initial_parse_and_match_fields, available_fields);
150   }
151 }
152