void ipset_bdd_iterator_advance(struct ipset_bdd_iterator *iterator) { /* If we're already at the end of the iterator, don't do anything. */ if (CORK_UNLIKELY(iterator->finished)) { return; } /* We look at the last node in the stack. If it's currently * assigned a false value, then we track down its true branch. If * it's got a true branch, then we pop it off and check the next to * last node. */ DEBUG("Advancing BDD iterator"); while (cork_array_size(&iterator->stack) > 0) { ipset_node_id last_node_id = cork_array_at (&iterator->stack, cork_array_size(&iterator->stack) - 1); struct ipset_node *last_node = ipset_node_cache_get_nonterminal(iterator->cache, last_node_id); enum ipset_tribool current_value = ipset_assignment_get(iterator->assignment, last_node->variable); /* The current value can't be EITHER, because we definitely * assign a TRUE or FALSE to the variables of the nodes that we * encounter. */ if (current_value == IPSET_TRUE) { /* We've checked both outgoing edges for this node, so pop * it off and look at its parent. */ iterator->stack.size--; /* Before continuing, reset this node's variable to * indeterminate in the assignment. */ ipset_assignment_set (iterator->assignment, last_node->variable, IPSET_EITHER); } else { /* We've checked this node's low edge, but not its high * edge. Set the variable to TRUE in the assignment, and * add the high edge's node to the node stack. */ ipset_assignment_set (iterator->assignment, last_node->variable, IPSET_TRUE); add_node(iterator, last_node->high); return; } } /* If we fall through then we ran out of nodes to check. That means * the iterator is done! */ iterator->finished = true; }
/** * Find the highest non-EITHER bit in an assignment, starting from the * given bit index. */ static unsigned int find_last_non_either_bit(struct ipset_assignment *assignment, unsigned int starting_bit) { unsigned int i; for (i = starting_bit; i >= 1; i--) { enum ipset_tribool value = ipset_assignment_get(assignment, i); if (value != IPSET_EITHER) { return i; } } return 0; }
static guint find_last_non_either_bit(ipset_assignment_t *assignment, guint starting_bit) { guint i; for (i = starting_bit; i >= 1; i--) { ipset_tribool_t value = ipset_assignment_get(assignment, i); if (value != IPSET_EITHER) { return i; } } return 0; }
static void process_assignment(struct ipset_iterator *iterator) { while (!iterator->bdd_iterator->finished) { if (iterator->bdd_iterator->value == iterator->desired_value) { /* If the BDD iterator hasn't finished, and the result of * the function with this assignment matches what the caller * wants, then we've found an assignment to generate IP * addresses from. * * Try to expand this assignment, and process the first * expanded assignment. We want 32 + 1 variables if the * current address is IPv4; 128 + 1 if it's IPv6. */ DEBUG("Got a matching BDD assignment"); enum ipset_tribool address_type = ipset_assignment_get (iterator->bdd_iterator->assignment, 0); if (address_type == IPSET_FALSE) { /* FALSE means IPv6*/ DEBUG("Assignment is IPv6"); iterator->multiple_expansion_state = IPSET_ITERATOR_NORMAL; expand_ipv6(iterator); return; } else if (address_type == IPSET_TRUE) { /* TRUE means IPv4*/ DEBUG("Assignment is IPv4"); iterator->multiple_expansion_state = IPSET_ITERATOR_NORMAL; expand_ipv4(iterator); return; } else { /* EITHER means that this assignment contains both IPv4 * and IPv6 addresses. Expand it as IPv4 first. */ DEBUG("Assignment is both IPv4 and IPv6"); DEBUG("Expanding IPv4 first"); iterator->multiple_expansion_state = IPSET_ITERATOR_MULTIPLE_IPV4; ipset_assignment_set (iterator->bdd_iterator->assignment, 0, IPSET_TRUE); expand_ipv4(iterator); return; } } /* The BDD iterator has a value, but it doesn't match the one we * want. Advance the BDD iterator and try again. */ DEBUG("Value is %d, skipping", iterator->bdd_iterator->value); ipset_bdd_iterator_advance(iterator->bdd_iterator); } /* If we fall through, then the BDD iterator has finished. That * means there's nothing left for the set iterator. */ DEBUG("Set iterator is finished"); ipset_expanded_assignment_free(iterator->assignment_iterator); iterator->assignment_iterator = NULL; ipset_bdd_iterator_free(iterator->bdd_iterator); iterator->bdd_iterator = NULL; iterator->finished = true; }