diff options
author | Vadim Kochan <vadim4j@gmail.com> | 2016-08-13 02:11:11 +0300 |
---|---|---|
committer | Tobias Klauser <tklauser@distanz.ch> | 2016-09-21 09:53:42 +0200 |
commit | 208db0e4a3ceb21a65527d87198cf6f49c4b06dc (patch) | |
tree | 98b5a9105a0ac701ca659af655218303e9e8936e | |
parent | e7dd63060e448bf6667c92a3b774cec0feeff452 (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.c | 54 | ||||
-rw-r--r-- | trafgen_proto.h | 11 |
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); }; |