loci: validate fixed-offset non-field-length lists
This is enough to pass all the existing unit tests.
diff --git a/c_gen/templates/loci_validator.c b/c_gen/templates/loci_validator.c
index 3f80982..92846c2 100644
--- a/c_gen/templates/loci_validator.c
+++ b/c_gen/templates/loci_validator.c
@@ -43,12 +43,13 @@
#define VALIDATOR_LOG(...) LOCI_LOG_ERROR("Validator Error: " __VA_ARGS__)
+:: raw_validator_name = lambda cls, version: "loci_validate_%s_%s" % (cls, version.constant_version(prefix='OF_VERSION_'))
:: validator_name = lambda ofclass: "loci_validate_%s_%s" % (ofclass.name, ofclass.protocol.version.constant_version(prefix='OF_VERSION_'))
/* Forward declarations */
:: for version, proto in loxi_globals.ir.items():
:: for ofclass in proto.classes:
-static int __attribute__((unused)) ${validator_name(ofclass)}(uint8_t *data, int len);
+static int __attribute__((unused)) ${validator_name(ofclass)}(uint8_t *data, int len, int *out_len);
:: #endfor
:: #endfor
@@ -56,15 +57,51 @@
:: types = { 1: 'uint8_t', 2: 'uint16_t', 4: 'uint32_t' }
:: for version, proto in loxi_globals.ir.items():
+
+:: # Identify classes in lists and generate list validators
+:: seen_lists = set()
+:: for ofclass in proto.classes:
+:: for m in ofclass.members:
+:: if type(m) == OFDataMember and m.oftype.startswith('list'):
+:: element_name = m.oftype[8:-3]
+:: if element_name in seen_lists:
+:: continue
+:: #endif
+:: seen_lists.add(element_name)
+:: list_validator_name = raw_validator_name('of_list_' + element_name, version)
+static int __attribute__((unused))
+${list_validator_name}(uint8_t *data, int len, int *out_len)
+{
+ while (len > 0) {
+ int cur_len = 0xffff;
+ if (${raw_validator_name('of_' + element_name, version)}(data, len, &cur_len) < 0) {
+ return -1;
+ }
+ len -= cur_len;
+ data += cur_len;
+ }
+
+ return 0;
+}
+
+:: #endif
+:: #endfor
+:: #endfor
+
:: for ofclass in proto.classes:
static int
-${validator_name(ofclass)}(uint8_t *data, int len)
+${validator_name(ofclass)}(uint8_t *data, int len, int *out_len)
{
if (len < ${ofclass.base_length}) {
return -1;
}
+:: if ofclass.is_fixed_length:
+ len = ${ofclass.base_length};
+:: #endif
+
:: # Read and validate length fields
+:: field_length_members = {}
:: for m in ofclass.members:
:: if type(m) == OFLengthMember:
${types[m.length]} wire_len;
@@ -74,6 +111,8 @@
}
len = wire_len;
+:: elif type(m) == OFFieldLengthMember:
+:: field_length_members[m.field_name] = m
:: #endif
:: #endfor
@@ -86,12 +125,30 @@
:: for subclass in proto.classes:
:: if subclass.superclass == ofclass:
case ${subclass.member_by_name(discriminator.name).value}:
- return ${validator_name(subclass)}(data, len);
+ return ${validator_name(subclass)}(data, len, out_len);
:: #endif
:: #endfor
}
:: #endif
+:: # Validate fixed-offset lists
+:: for m in ofclass.members:
+:: if type(m) == OFDataMember and m.oftype.startswith('list') and m.offset is not None:
+:: if m.name in field_length_members:
+:: continue # TODO handle field length members
+:: #endif
+:: element_name = m.oftype[8:-3]
+:: list_validator_name = raw_validator_name('of_list_' + element_name, version)
+ if (${list_validator_name}(data + ${m.offset}, len - ${m.offset}, out_len) < 0) {
+ return -1;
+ }
+
+:: #endif
+:: #endfor
+
+:: # TODO handle non-fixed-offset lists
+
+ *out_len = len;
return 0;
}
@@ -110,10 +167,11 @@
}
version = of_message_version_get(msg);
+ int out_len;
switch (version) {
:: for version, proto in loxi_globals.ir.items():
case ${version.constant_version(prefix='OF_VERSION_')}:
- return ${validator_name(proto.class_by_name('of_header'))}(msg, len);
+ return ${validator_name(proto.class_by_name('of_header'))}(msg, len, &out_len);
:: #endfor
default:
VALIDATOR_LOG("Bad version %d", OF_VERSION_1_3);
diff --git a/c_gen/templates/locitest/test_validator.c b/c_gen/templates/locitest/test_validator.c
index 81beb5d..a4b55eb 100644
--- a/c_gen/templates/locitest/test_validator.c
+++ b/c_gen/templates/locitest/test_validator.c
@@ -71,10 +71,8 @@
TEST_ASSERT(of_validate_message(msg, of_message_length_get(msg)) == 0);
-#if 0
of_message_length_set(msg, of_message_length_get(msg) - 1);
TEST_ASSERT(of_validate_message(msg, of_message_length_get(msg)) == -1);
-#endif
of_table_stats_reply_delete(obj);
return TEST_PASS;
@@ -97,13 +95,11 @@
TEST_ASSERT(of_validate_message(msg, of_message_length_get(msg)) == 0);
-#if 0
of_message_length_set(msg, of_message_length_get(msg) - 1);
TEST_ASSERT(of_validate_message(msg, of_message_length_get(msg)) == -1);
of_message_length_set(msg, of_message_length_get(msg) + 2);
TEST_ASSERT(of_validate_message(msg, of_message_length_get(msg)) == -1);
-#endif
of_flow_modify_delete(obj);
return TEST_PASS;