summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Kochan <vadim4j@gmail.com>2016-08-13 02:11:11 +0300
committerTobias Klauser <tklauser@distanz.ch>2016-09-21 09:53:42 +0200
commit208db0e4a3ceb21a65527d87198cf6f49c4b06dc (patch)
tree98b5a9105a0ac701ca659af655218303e9e8936e
parente7dd63060e448bf6667c92a3b774cec0feeff452 (diff)
trafgen: proto: Increment proto field at runtime
Implement incrementing of proto field at runtime with min & max parameters, by default if the 'min' parameter is not specified then original value is used. For fields which len is greater than 4 - last 4 bytes are incremented as 4 byte value (this trick is used to increment MAC/IPv6 addresses). Signed-off-by: Vadim Kochan <vadim4j@gmail.com> Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
-rw-r--r--trafgen_proto.c54
-rw-r--r--trafgen_proto.h11
2 files changed, 65 insertions, 0 deletions
diff --git a/trafgen_proto.c b/trafgen_proto.c
index 96fd6da..6c37b21 100644
--- a/trafgen_proto.c
+++ b/trafgen_proto.c
@@ -438,6 +438,37 @@ void proto_packet_finish(void)
}
}
+static inline uint32_t field_inc(struct proto_field *field)
+{
+ uint32_t min = field->func.min;
+ uint32_t max = field->func.max;
+ uint32_t val = field->func.val;
+ uint32_t inc = field->func.inc;
+ uint32_t next;
+
+ next = (val + inc) % (max + 1);
+ field->func.val = max(next, min);
+
+ return val;
+}
+
+static void field_inc_func(struct proto_field *field)
+{
+ if (field->len == 1) {
+ proto_field_set_u8(field->hdr, field->id, field_inc(field));
+ } else if (field->len == 2) {
+ proto_field_set_be16(field->hdr, field->id, field_inc(field));
+ } else if (field->len == 4) {
+ proto_field_set_be32(field->hdr, field->id, field_inc(field));
+ } else if (field->len > 4) {
+ uint8_t *bytes = __proto_field_get_bytes(field);
+
+ bytes += field->len - 4;
+
+ *(uint32_t *)bytes = bswap_32(field_inc(field));
+ }
+}
+
void proto_field_func_add(struct proto_hdr *hdr, uint32_t fid,
struct proto_field_func *func)
{
@@ -446,6 +477,29 @@ void proto_field_func_add(struct proto_hdr *hdr, uint32_t fid,
bug_on(!func);
field->func.update_field = func->update_field;
+ field->func.type = func->type;
+ field->func.max = func->max ?: UINT32_MAX - 1;
+ field->func.min = func->min;
+ field->func.inc = func->inc;
+
+ if (func->type & PROTO_FIELD_FUNC_INC) {
+ if (func->type & PROTO_FIELD_FUNC_MIN)
+ field->func.val = func->min;
+ else if (field->len == 1)
+ field->func.val = proto_field_get_u8(hdr, fid);
+ else if (field->len == 2)
+ field->func.val = proto_field_get_u16(hdr, fid);
+ else if (field->len == 4)
+ field->func.val = proto_field_get_u32(hdr, fid);
+ else if (field->len > 4) {
+ uint8_t *bytes = __proto_field_get_bytes(field);
+
+ bytes += field->len - 4;
+ field->func.val = bswap_32(*(uint32_t *)bytes);
+ }
+
+ field->func.update_field = field_inc_func;
+ }
}
void proto_field_dyn_apply(struct proto_field *field)
diff --git a/trafgen_proto.h b/trafgen_proto.h
index 6cdc51f..0a1c3de 100644
--- a/trafgen_proto.h
+++ b/trafgen_proto.h
@@ -51,7 +51,18 @@ struct proto_hdr {
size_t len;
};
+enum proto_field_func_t {
+ PROTO_FIELD_FUNC_INC = 1 << 0,
+ PROTO_FIELD_FUNC_MIN = 1 << 1,
+};
+
struct proto_field_func {
+ enum proto_field_func_t type;
+ uint32_t min;
+ uint32_t max;
+ int32_t inc;
+ uint32_t val;
+
void (*update_field)(struct proto_field *field);
};