You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

138 lines
4.3 KiB

10 years ago
  1. /* -*- coding: utf-8 -*-
  2. * ----------------------------------------------------------------------
  3. * Copyright © 2010-2012, RedJack, LLC.
  4. * All rights reserved.
  5. *
  6. * Please see the LICENSE.txt file in this distribution for license
  7. * details.
  8. * ----------------------------------------------------------------------
  9. */
  10. #include <string.h>
  11. #include <libcork/core.h>
  12. #include "ipset/bdd/nodes.h"
  13. #include "ipset/bits.h"
  14. #include "ipset/logging.h"
  15. static void
  16. initialize(struct ipset_expanded_assignment *exp,
  17. const struct ipset_assignment *assignment,
  18. ipset_variable var_count)
  19. {
  20. /* First loop through all of the variables in the assignment vector,
  21. * making sure not to go further than the caller requested. */
  22. ipset_variable last_assignment = cork_array_size(&assignment->values);
  23. if (var_count < last_assignment) {
  24. last_assignment = var_count;
  25. }
  26. ipset_variable var;
  27. for (var = 0; var < last_assignment; var++) {
  28. enum ipset_tribool curr_value =
  29. cork_array_at(&assignment->values, var);
  30. if (curr_value == IPSET_EITHER) {
  31. /* If this variable is EITHER, start it off as FALSE, and
  32. * add it to the eithers list. */
  33. DEBUG("Variable %u is EITHER", var);
  34. IPSET_BIT_SET(exp->values.buf, var, false);
  35. cork_array_append(&exp->eithers, var);
  36. } else {
  37. /* Otherwise set the variable to the same value in the
  38. * expanded assignment as it is in the non-expanded one. */
  39. DEBUG("Variable %u is %s", var, curr_value? "true": "false");
  40. IPSET_BIT_SET(exp->values.buf, var, curr_value);
  41. }
  42. }
  43. /* If the caller requested more variables than there are in the
  44. * assignment vector, add them to the eithers list. */
  45. for (var = last_assignment; var < var_count; var++) {
  46. DEBUG("Variable %u is implicitly EITHER", var);
  47. cork_array_append(&exp->eithers, var);
  48. }
  49. }
  50. struct ipset_expanded_assignment *
  51. ipset_assignment_expand(const struct ipset_assignment *assignment,
  52. ipset_variable var_count)
  53. {
  54. /* First allocate the iterator itself, and all of its contained
  55. * fields. */
  56. struct ipset_expanded_assignment *exp;
  57. unsigned int values_size = (var_count / 8) + ((var_count % 8) != 0);
  58. exp = cork_new(struct ipset_expanded_assignment);
  59. exp->finished = false;
  60. cork_buffer_init(&exp->values);
  61. cork_buffer_ensure_size(&exp->values, values_size);
  62. memset(exp->values.buf, 0, values_size);
  63. cork_array_init(&exp->eithers);
  64. /* Then initialize the values and eithers fields. */
  65. initialize(exp, assignment, var_count);
  66. return exp;
  67. }
  68. void
  69. ipset_expanded_assignment_free(struct ipset_expanded_assignment *exp)
  70. {
  71. if (exp == NULL) {
  72. return;
  73. }
  74. cork_buffer_done(&exp->values);
  75. cork_array_done(&exp->eithers);
  76. free(exp);
  77. }
  78. void
  79. ipset_expanded_assignment_advance(struct ipset_expanded_assignment *exp)
  80. {
  81. /* If we're already at the end of the iterator, don't do anything. */
  82. if (CORK_UNLIKELY(exp->finished)) {
  83. return;
  84. }
  85. DEBUG("Advancing iterator");
  86. /* Look at the last EITHER bit in the assignment. If it's 0, then
  87. * set it to 1 and return. Otherwise we set it to 0 and carry up to
  88. * the previous indeterminate bit. */
  89. size_t i;
  90. for (i = cork_array_size(&exp->eithers); i > 0; i--) {
  91. size_t idx = i - 1;
  92. ipset_variable either_var = cork_array_at(&exp->eithers, idx);
  93. DEBUG("Checking EITHER variable %u", either_var);
  94. if (IPSET_BIT_GET(exp->values.buf, either_var)) {
  95. /* This variable is currently true, so set it back to false
  96. * and carry. */
  97. DEBUG(" Variable %u is true, changing to false and carrying",
  98. either_var);
  99. IPSET_BIT_SET(exp->values.buf, either_var, false);
  100. } else {
  101. /* This variable is currently false, so set it to true and
  102. * return. */
  103. DEBUG(" Variable %u is false, changing to true",
  104. either_var);
  105. IPSET_BIT_SET(exp->values.buf, either_var, true);
  106. return;
  107. }
  108. }
  109. /* If we fall through then we've made it through all of the expanded
  110. * assignments. */
  111. exp->finished = true;
  112. }