/* * Copyright 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "packet_dependency.h" #include #include #include PacketDependency::PacketDependency(const ParentDef* root) { std::map> initial_parse_and_match_fields; std::vector available_fields; CollectInitialParseAndMatchFields(root, initial_parse_and_match_fields); FinalizeParseAndMatchFields(root, initial_parse_and_match_fields, available_fields); } std::vector& PacketDependency::GetDependencies(const std::string& packet_name) { return dependencies[packet_name]; } std::vector& PacketDependency::GetChildrenDependencies( const std::string& packet_name) { return children_dependencies[packet_name]; } std::set PacketDependency::CollectInitialParseAndMatchFields( const ParentDef* parent, std::map>& initial_parse_and_match_fields) const { // Case Leaf Packet: Return all of its constraints if (parent->children_.empty()) { auto constraints = parent->GetAllConstraints(); auto constraints_set = std::set{}; for (auto& c : constraints) { constraints_set.insert(c.first); } return constraints_set; } auto children_constraints = std::set{}; auto parent_constraints = parent->GetAllConstraints(); auto parent_fields = parent->fields_; for (const auto child : parent->children_) { auto constraints = CollectInitialParseAndMatchFields(child, initial_parse_and_match_fields); auto child_only_constraints = std::set{}; for (auto c : constraints) { // __PARENT__ // c1/ c2| \c3 // / | \. // CH1 CH2 CH3 // c4| // | // CH11 // GetAllConstraints on leaf packet CH11 will return (C4, c1) // GetAllConstraints on packet CH1 will return C1 // Thus CH11 only constraint is: (C4, C1) - (C1) => (C4) if (parent_constraints.find(c) == parent_constraints.end()) { child_only_constraints.insert(c); } // If the constraint can be satisfied by the immediate parent, no need to accumulate it if (parent_fields.GetField(c) != nullptr) { continue; } // Accumulate constraints from all the children so parent packet can accurately // figure out which constraints it should be getting from its parents. children_constraints.insert(c); } // child_only_constraints contains the variables required to be passed in when calling parse initial_parse_and_match_fields[child->name_] = child_only_constraints; } return children_constraints; } void PacketDependency::FinalizeParseAndMatchFields( const ParentDef* parent, std::map>& initial_parse_and_match_fields, std::vector& available_fields) { // Root does not have any constraints on anything if (parent->parent_ == nullptr) { dependencies[parent->name_] = std::vector{}; children_dependencies[parent->name_] = std::vector{}; } // Collect the available fields, required to fix the order of pass and match vectors for (auto& pf : parent->fields_) { available_fields.push_back(pf->GetName()); } auto children_constraints_to_me = std::set{}; children_dependencies[parent->name_] = std::vector{}; // Accumulate direct constraints from all the children to parent // __PARENT__ // c1/ c2| \c3 // / | \. // CH1 CH2 CH3 // c4| // | // CH11 // For this case: children_constraints_to_me = (c1, c2, c3) for (auto& child : parent->children_) { for (auto pcons : child->parent_constraints_) { children_constraints_to_me.insert(pcons.first); } } // If children constraints to the parent are (c1, c2, c3) and so far parent has // fields (c1, c2) available, then parent will match its children on (c1, c2) for (auto avf : available_fields) { if (children_constraints_to_me.find(avf) != children_constraints_to_me.end()) { auto& match_variables = children_dependencies[parent->name_]; if (std::find(match_variables.begin(), match_variables.end(), avf) == match_variables.end()) { match_variables.push_back(avf); } } } for (auto& child : parent->children_) { auto child_initial_parse_params = initial_parse_and_match_fields[child->name_]; auto child_actual_parse_params = std::vector{}; // Remove all the params from parse method of this child // if these variables are the ones parent will match its children. for (auto pcons : child->parent_constraints_) { child_initial_parse_params.erase(pcons.first); } // Store unique vars from child_initial_parse_params to child_actual_parse_params // in the same order as fields are defined in the packets for (auto avf : available_fields) { if (child_initial_parse_params.find(avf) != child_initial_parse_params.end()) { child_actual_parse_params.push_back(avf); } } dependencies[child->name_] = child_actual_parse_params; FinalizeParseAndMatchFields(child, initial_parse_and_match_fields, available_fields); } }