Extend proto field expression to:

    proto_field[{index}:{len}] = {func}

which allows to specify function/value on the part of the field via index
and value length (default is 1 - 1 byte). This rule is optional.

It was needed to keep of proto_field's copies in packet_dyn->fields
instead of original fields which allows to scpecify different functions
on the different parts of same field, also the copy of original
proto_field allows to set custom length/pkt_offset which makes such
field behave as virtual sub-field of the original one with different
length/pkt_offset but point to the same piece of header.

Signed-off-by: Vadim Kochan <vadi...@gmail.com>
---
 trafgen_parser.y | 96 +++++++++++++++++++++++++++++++++++++++++++++++---------
 trafgen_proto.c  | 27 +++++++---------
 trafgen_proto.h  |  8 +++--
 3 files changed, 98 insertions(+), 33 deletions(-)

diff --git a/trafgen_parser.y b/trafgen_parser.y
index a1b8b0c..4d570e0 100644
--- a/trafgen_parser.y
+++ b/trafgen_parser.y
@@ -387,20 +387,30 @@ static void proto_add(enum proto_id pid)
 
 static void proto_field_set(uint32_t fid)
 {
+       memset(&field_expr, 0, sizeof(field_expr));
        field_expr.field = proto_hdr_field_by_id(hdr, fid);
 }
 
 static void proto_field_func_setup(struct proto_field *field, struct 
proto_field_func *func)
 {
+       struct proto_field *field_copy;
        struct packet_dyn *pkt_dyn;
 
-       proto_hdr_field_func_add(field->hdr, field->id, func);
+       field_copy = xmalloc(sizeof(*field));
+       memcpy(field_copy, field, sizeof(*field));
+
+       field_copy->pkt_offset += func->offset;
+       if (func->len)
+               field_copy->len = func->len;
+
+       proto_field_func_add(field_copy, func);
 
        pkt_dyn = &packet_dyn[packetd_last];
        pkt_dyn->flen++;
        pkt_dyn->fields = xrealloc(pkt_dyn->fields, pkt_dyn->flen *
                                   sizeof(struct proto_field *));
-       pkt_dyn->fields[pkt_dyn->flen - 1] = field;
+
+       pkt_dyn->fields[pkt_dyn->flen - 1] = field_copy;
 }
 
 static void proto_field_expr_eval(void)
@@ -450,6 +460,19 @@ static void proto_field_expr_eval(void)
        memset(&field_expr, 0, sizeof(field_expr));
 }
 
+static void field_index_validate(struct proto_field *field, uint16_t index, 
size_t len)
+{
+       if (field_expr.field->len <= index) {
+               yyerror("Invalid [index] parameter");
+               panic("Index (%u) is bigger than field's length (%zu)\n",
+                      index, field->len);
+       }
+       if (len != 1 && len != 2 && len != 4) {
+               yyerror("Invalid [index:len] parameter");
+               panic("Invalid index length - 1,2 or 4 is only allowed\n");
+       }
+}
+
 %}
 
 %union {
@@ -718,6 +741,17 @@ proto
        | tcp_proto { }
        ;
 
+field_expr
+       : '[' skip_white number skip_white ']'
+               { field_index_validate(field_expr.field, $3, 1);
+                 field_expr.val.func.offset = $3;
+                 field_expr.val.func.len = 1; }
+       | '[' skip_white number skip_white ':' skip_white number skip_white ']'
+               { field_index_validate(field_expr.field, $3, $7);
+                 field_expr.val.func.offset = $3;
+                 field_expr.val.func.len = $7; }
+       ;
+
 field_value_expr
        : number { field_expr.type = FIELD_EXPR_NUMB;
                   field_expr.val.number = $1; }
@@ -783,7 +817,9 @@ eth_field
        | eth_type { proto_field_set(ETH_TYPE); }
 
 eth_expr
-       : eth_field skip_white '=' skip_white field_value_expr
+       : eth_field field_expr skip_white '=' skip_white field_value_expr
+               { proto_field_expr_eval(); }
+       | eth_field skip_white '=' skip_white field_value_expr
                { proto_field_expr_eval(); }
        ;
 
@@ -807,7 +843,9 @@ pause_field
        ;
 
 pause_expr
-       : pause_field skip_white '=' skip_white field_value_expr
+       : pause_field field_expr skip_white '=' skip_white field_value_expr
+               { proto_field_expr_eval(); }
+       | pause_field skip_white '=' skip_white field_value_expr
                { proto_field_expr_eval(); }
        ;
 
@@ -843,7 +881,9 @@ pfc_field
        ;
 
 pfc_expr
-       : pfc_field skip_white '=' skip_white field_value_expr
+       : pfc_field field_expr skip_white '=' skip_white field_value_expr
+               { proto_field_expr_eval(); }
+       | pfc_field skip_white '=' skip_white field_value_expr
                { proto_field_expr_eval(); }
        ;
 
@@ -875,7 +915,9 @@ vlan_field
        ;
 
 vlan_expr
-       : vlan_field skip_white '=' skip_white field_value_expr
+       : vlan_field field_expr skip_white '=' skip_white field_value_expr
+               { proto_field_expr_eval(); }
+       | vlan_field skip_white '=' skip_white field_value_expr
                { proto_field_expr_eval(); }
        | K_1Q
                { proto_hdr_field_set_be16(hdr, VLAN_TPID, ETH_P_8021Q); }
@@ -910,7 +952,9 @@ mpls_field
        ;
 
 mpls_expr
-       : mpls_field skip_white '=' skip_white field_value_expr
+       : mpls_field field_expr skip_white '=' skip_white field_value_expr
+               { proto_field_expr_eval(); }
+       | mpls_field skip_white '=' skip_white field_value_expr
                { proto_field_expr_eval(); }
 
 arp_proto
@@ -939,8 +983,13 @@ arp_field
        ;
 
 arp_expr
-       : arp_field skip_white '=' skip_white field_value_expr
+       : arp_field field_expr skip_white '=' skip_white field_value_expr
+               { proto_field_expr_eval(); }
+       | arp_field skip_white '=' skip_white field_value_expr
                { proto_field_expr_eval(); }
+       | K_OPER field_expr skip_white '=' skip_white field_value_expr
+               { proto_field_set(ARP_OPER);
+                 proto_field_expr_eval(); }
        | K_OPER skip_white '=' skip_white field_value_expr
                { proto_field_set(ARP_OPER);
                  proto_field_expr_eval(); }
@@ -985,7 +1034,9 @@ ip4_field
        ;
 
 ip4_expr
-       : ip4_field skip_white '=' skip_white field_value_expr
+       : ip4_field field_expr skip_white '=' skip_white field_value_expr
+               { proto_field_expr_eval(); }
+       | ip4_field skip_white '=' skip_white field_value_expr
                { proto_field_expr_eval(); }
        | K_DF  { proto_hdr_field_set_be16(hdr, IP4_DF, 1); }
        | K_MF  { proto_hdr_field_set_be16(hdr, IP4_MF, 1); }
@@ -1022,7 +1073,9 @@ ip6_field
        ;
 
 ip6_expr
-       : ip6_field skip_white '=' skip_white field_value_expr
+       : ip6_field field_expr skip_white '=' skip_white field_value_expr
+               { proto_field_expr_eval(); }
+       | ip6_field skip_white '=' skip_white field_value_expr
                { proto_field_expr_eval(); }
        ;
 
@@ -1050,7 +1103,9 @@ icmp4_field
        ;
 
 icmp4_expr
-       : icmp4_field skip_white '=' skip_white field_value_expr
+       : icmp4_field field_expr skip_white '=' skip_white field_value_expr
+               { proto_field_expr_eval(); }
+       | icmp4_field skip_white '=' skip_white field_value_expr
                { proto_field_expr_eval(); }
        | K_ECHO_REQUEST
                { proto_hdr_field_set_u8(hdr, ICMPV4_TYPE, ICMP_ECHO);
@@ -1079,8 +1134,13 @@ icmp6_field
        ;
 
 icmp6_expr
-       : icmp6_field skip_white '=' skip_white field_value_expr
+       : icmp6_field field_expr skip_white '=' skip_white field_value_expr
                { proto_field_expr_eval(); }
+       | icmp6_field skip_white '=' skip_white field_value_expr
+               { proto_field_expr_eval(); }
+       | K_TYPE field_expr skip_white '=' skip_white field_value_expr
+               { proto_field_set(ICMPV6_TYPE);
+                 proto_field_expr_eval(); }
        | K_TYPE skip_white '=' skip_white field_value_expr
                { proto_field_set(ICMPV6_TYPE);
                  proto_field_expr_eval(); }
@@ -1115,7 +1175,9 @@ udp_field
        ;
 
 udp_expr
-       : udp_field skip_white '=' skip_white field_value_expr
+       : udp_field field_expr skip_white '=' skip_white field_value_expr
+               { proto_field_expr_eval(); }
+       | udp_field skip_white '=' skip_white field_value_expr
                { proto_field_expr_eval(); }
        ;
 
@@ -1145,7 +1207,9 @@ tcp_field
        ;
 
 tcp_expr
-       : tcp_field skip_white '=' skip_white field_value_expr
+       : tcp_field field_expr skip_white '=' skip_white field_value_expr
+               { proto_field_expr_eval(); }
+       | tcp_field skip_white '=' skip_white field_value_expr
                { proto_field_expr_eval(); }
        | K_CWR { proto_hdr_field_set_be16(hdr, TCP_CWR, 1); }
        | K_ECE { proto_hdr_field_set_be16(hdr, TCP_ECE, 1); }
@@ -1225,6 +1289,10 @@ void cleanup_packets(void)
        for (i = 0; i < dlen; ++i) {
                free(packet_dyn[i].cnt);
                free(packet_dyn[i].rnd);
+
+               for (j = 0; j < packet_dyn[j].flen; j++)
+                       xfree(packet_dyn[i].fields[j]);
+
                free(packet_dyn[i].fields);
        }
 
diff --git a/trafgen_proto.c b/trafgen_proto.c
index e2b80d4..88e0846 100644
--- a/trafgen_proto.c
+++ b/trafgen_proto.c
@@ -532,11 +532,11 @@ static inline uint32_t field_inc(struct proto_field 
*field)
 static void field_inc_func(struct proto_field *field)
 {
        if (field->len == 1) {
-               proto_hdr_field_set_u8(field->hdr, field->id, field_inc(field));
+               proto_field_set_u8(field, field_inc(field));
        } else if (field->len == 2) {
-               proto_hdr_field_set_be16(field->hdr, field->id, 
field_inc(field));
+               proto_field_set_be16(field, field_inc(field));
        } else if (field->len == 4) {
-               proto_hdr_field_set_be32(field->hdr, field->id, 
field_inc(field));
+               proto_field_set_be32(field, field_inc(field));
        } else if (field->len > 4) {
                uint8_t *bytes = __proto_field_get_bytes(field);
 
@@ -554,14 +554,11 @@ static inline uint32_t field_rand(struct proto_field 
*field)
 static void field_rnd_func(struct proto_field *field)
 {
        if (field->len == 1) {
-               proto_hdr_field_set_u8(field->hdr, field->id,
-                                   (uint8_t) field_rand(field));
+               proto_field_set_u8(field, (uint8_t) field_rand(field));
        } else if (field->len == 2) {
-               proto_hdr_field_set_be16(field->hdr, field->id,
-                                   (uint16_t) field_rand(field));
+               proto_field_set_be16(field, (uint16_t) field_rand(field));
        } else if (field->len == 4) {
-               proto_hdr_field_set_be32(field->hdr, field->id,
-                                   (uint32_t) field_rand(field));
+               proto_field_set_be32(field, (uint32_t) field_rand(field));
        } else if (field->len > 4) {
                uint8_t *bytes = __proto_field_get_bytes(field);
                uint32_t i;
@@ -571,11 +568,9 @@ static void field_rnd_func(struct proto_field *field)
        }
 }
 
-void proto_hdr_field_func_add(struct proto_hdr *hdr, uint32_t fid,
-                             struct proto_field_func *func)
+void proto_field_func_add(struct proto_field *field,
+                         struct proto_field_func *func)
 {
-       struct proto_field *field = proto_hdr_field_by_id(hdr, fid);
-
        bug_on(!func);
 
        field->func.update_field = func->update_field;
@@ -588,11 +583,11 @@ void proto_hdr_field_func_add(struct proto_hdr *hdr, 
uint32_t fid,
                if (func->type & PROTO_FIELD_FUNC_MIN)
                        field->func.val = func->min;
                else if (field->len == 1)
-                       field->func.val = proto_hdr_field_get_u8(hdr, fid);
+                       field->func.val = proto_field_get_u8(field);
                else if (field->len == 2)
-                       field->func.val = proto_hdr_field_get_u16(hdr, fid);
+                       field->func.val = proto_field_get_u16(field);
                else if (field->len == 4)
-                       field->func.val = proto_hdr_field_get_u32(hdr, fid);
+                       field->func.val = proto_field_get_u32(field);
                else if (field->len > 4) {
                        uint8_t *bytes = __proto_field_get_bytes(field);
 
diff --git a/trafgen_proto.h b/trafgen_proto.h
index d4427e6..29d68db 100644
--- a/trafgen_proto.h
+++ b/trafgen_proto.h
@@ -66,7 +66,9 @@ struct proto_field_func {
        uint32_t min;
        uint32_t max;
        int32_t inc;
+       uint16_t offset;
        uint32_t val;
+       size_t len;
 
        void (*update_field)(struct proto_field *field);
 };
@@ -142,9 +144,6 @@ extern void proto_hdr_field_set_default_dev_ipv6(struct 
proto_hdr *hdr, uint32_t
 
 extern void proto_field_dyn_apply(struct proto_field *field);
 
-extern void proto_hdr_field_func_add(struct proto_hdr *hdr, uint32_t fid,
-                                    struct proto_field_func *func);
-
 extern struct proto_field *proto_hdr_field_by_id(struct proto_hdr *hdr, 
uint32_t fid);
 
 
@@ -157,4 +156,7 @@ extern uint32_t proto_field_get_u32(struct proto_field 
*field);
 extern void proto_field_set_be16(struct proto_field *field, uint16_t val);
 extern void proto_field_set_be32(struct proto_field *field, uint32_t val);
 
+extern void proto_field_func_add(struct proto_field *field,
+                                struct proto_field_func *func);
+
 #endif /* TRAFGEN_PROTO_H */
-- 
2.10.2

-- 
You received this message because you are subscribed to the Google Groups 
"netsniff-ng" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to netsniff-ng+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to