summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--trafgen_l3.c33
-rw-r--r--trafgen_proto.h1
2 files changed, 28 insertions, 6 deletions
diff --git a/trafgen_l3.c b/trafgen_l3.c
index 2eabef1..9bb0de9 100644
--- a/trafgen_l3.c
+++ b/trafgen_l3.c
@@ -43,6 +43,30 @@ static void ipv4_header_init(struct proto_hdr *hdr)
proto_field_set_default_dev_ipv4(hdr, IP4_SADDR);
}
+static void ipv4_field_changed(struct proto_field *field)
+{
+ field->hdr->is_csum_valid = false;
+}
+
+static void ipv4_csum_update(struct proto_hdr *hdr)
+{
+ struct packet *pkt;
+ uint16_t csum;
+
+ if (hdr->is_csum_valid)
+ return;
+ if (proto_field_is_set(hdr, IP4_CSUM))
+ return;
+
+ pkt = packet_get(hdr->pkt_id);
+
+ proto_field_set_default_u16(hdr, IP4_CSUM, 0);
+ csum = htons(calc_csum(&pkt->payload[hdr->pkt_offset], hdr->len));
+ proto_field_set_default_u16(hdr, IP4_CSUM, bswap_16(csum));
+
+ hdr->is_csum_valid = true;
+}
+
static void ipv4_packet_finish(struct proto_hdr *hdr)
{
struct packet *pkt = current_packet();
@@ -51,12 +75,7 @@ static void ipv4_packet_finish(struct proto_hdr *hdr)
total_len = pkt->len - hdr->pkt_offset;
proto_field_set_default_be16(hdr, IP4_LEN, total_len);
- if (!proto_field_is_set(hdr, IP4_CSUM)) {
- uint16_t csum;
-
- csum = htons(calc_csum(&pkt->payload[hdr->pkt_offset], hdr->len));
- proto_field_set_u16(hdr, IP4_CSUM, bswap_16(csum));
- }
+ ipv4_csum_update(hdr);
}
static void ipv4_set_next_proto(struct proto_hdr *hdr, enum proto_id pid)
@@ -90,6 +109,8 @@ static const struct proto_ops ipv4_proto_ops = {
.id = PROTO_IP4,
.layer = PROTO_L3,
.header_init = ipv4_header_init,
+ .packet_update = ipv4_csum_update,
+ .field_changed = ipv4_field_changed,
.packet_finish = ipv4_packet_finish,
.set_next_proto = ipv4_set_next_proto,
};
diff --git a/trafgen_proto.h b/trafgen_proto.h
index 41e9383..000938c 100644
--- a/trafgen_proto.h
+++ b/trafgen_proto.h
@@ -48,6 +48,7 @@ struct proto_hdr {
uint32_t pkt_id;
struct proto_field *fields;
size_t fields_count;
+ bool is_csum_valid;
size_t len;
};