On Mon, Jan 25, 2016 at 10:15:24AM +0100, Tobias Klauser wrote: > On 2016-01-21 at 00:19:52 +0100, Vadim Kochan <vadi...@gmail.com> wrote: > > Add new trafgen_proto.c module with basic proto > > header fields generation logic. > > > > Each proto must implement proto_gen struct and register it > > to the global proto list. > > > > Proto header consist from set of fields, and each field must be > > described via proto_field struct by specifying unique id, len, > > offset (relative to the header). Small fields ( < 8 bits) can be > > described via left shift & mask. > > > > On header_init required fields must be added to the packet and > > initialized with default values. > > > > header_finish callback is invoked from upper to lower proto > > and some final calculations might be performed (total len, checksum). > > > > Proto generation API provides easy proto field setters/getters to easy > > craft the packet via parser. > > > > Signed-off-by: Vadim Kochan <vadi...@gmail.com> > > --- > > trafgen.c | 3 + > > trafgen/Makefile | 1 + > > trafgen_proto.c | 288 > > +++++++++++++++++++++++++++++++++++++++++++++++++++++++ > > trafgen_proto.h | 82 ++++++++++++++++ > > 4 files changed, 374 insertions(+) > > create mode 100644 trafgen_proto.c > > create mode 100644 trafgen_proto.h > > > > diff --git a/trafgen.c b/trafgen.c > > index c74a973..949f909 100644 > > --- a/trafgen.c > > +++ b/trafgen.c > > @@ -54,6 +54,7 @@ > > #include "timer.h" > > #include "ring_tx.h" > > #include "csum.h" > > +#include "trafgen_proto.h" > > > > #ifndef timeval_to_timespec > > #define timeval_to_timespec(tv, ts) { \ > > @@ -1215,6 +1216,8 @@ int main(int argc, char **argv) > > register_signal(SIGTERM, signal_handler); > > register_signal(SIGHUP, signal_handler); > > > > + protos_init(ctx.device); > > + > > if (prio_high) { > > set_proc_prio(-20); > > set_sched_status(SCHED_FIFO, > > sched_get_priority_max(SCHED_FIFO)); > > diff --git a/trafgen/Makefile b/trafgen/Makefile > > index bc256b2..2ea684f 100644 > > --- a/trafgen/Makefile > > +++ b/trafgen/Makefile > > @@ -19,6 +19,7 @@ trafgen-objs = xmalloc.o \ > > timer.o \ > > sysctl.o \ > > cpp.o \ > > + trafgen_proto.o \ > > trafgen_lexer.yy.o \ > > trafgen_parser.tab.o \ > > trafgen.o > > diff --git a/trafgen_proto.c b/trafgen_proto.c > > new file mode 100644 > > index 0000000..caf2685 > > --- /dev/null > > +++ b/trafgen_proto.c > > @@ -0,0 +1,288 @@ > > +/* > > + * netsniff-ng - the packet sniffing beast > > + * Subject to the GPL, version 2. > > + */ > > + > > +#include <stddef.h> > > +#include <string.h> > > + > > +#include "xmalloc.h" > > +#include "trafgen_conf.h" > > +#include "trafgen_proto.h" > > + > > +#define field_shift_and_mask(f, v) (((v) << (f)->shift) & \ > > + ((f)->mask ? (f)->mask : (0xffffffff))) > > + > > +#define field_unmask_and_unshift(f, v) (((v) & \ > > + ((f)->mask ? (f)->mask : (0xffffffff))) >> (f)->shift) > > + > > +static struct proto_ctx ctx; > > + > > +#define PROTO_MAX_LAYERS 8 > > + > > +static struct proto_gen *headers[PROTO_MAX_LAYERS]; > > +static int headers_count; > > + > > +static struct proto_gen *protos; > > + > > +struct proto_gen *proto_get_by_id(enum proto_id id) > > +{ > > + struct proto_gen *p = protos; > > + > > + for (; p; p = p->next) > > + if (p->id == id) > > + return p; > > + > > + panic("Can't lookup proto by id %u\n", id); > > Why do panic here? Wouldn't it be better to return NULL and let the > callers handle it gracefully?
Well, just because it should not happen in normal case but only when adding new proto syntax (parser strictly specifies the proto id). > > > +} > > + > > +void proto_register(struct proto_gen *prot) > > +{ > > + prot->next = protos; > > + protos = prot; > > + > > + prot->fields = NULL; > > + prot->fields_count = 0; > > +} > > + > > +static void proto_fields_realloc(struct proto_gen *prot, int count) > > +{ > > + prot->fields = xrealloc(prot->fields, count * sizeof(*prot->fields)); > > + prot->fields_count = count; > > +} > > + > > +void proto_fields_add(enum proto_id pid, struct proto_field *fields, int > > count) > > +{ > > + struct proto_gen *prot = proto_get_by_id(pid); > > + struct packet *pkt = current_packet(); > > + struct proto_field *f; > > + int i; > > + > > + if (!prot->fields) > > + prot->pkt_offset = pkt->len; > > + > > + proto_fields_realloc(prot, prot->fields_count + count); > > + > > + for (i = 0; count >= 1; count--, i++) { > > + f = &prot->fields[prot->fields_count - count]; > > + > > + f->id = fields[i].id; > > + f->len = fields[i].len; > > + f->is_set = false; > > + f->shift = fields[i].shift; > > + f->mask = fields[i].mask; > > + f->pkt_offset = prot->pkt_offset + fields[i].offset; > > + > > + if (f->pkt_offset + f->len > pkt->len) > > + set_fill(0, (f->pkt_offset + f->len) - pkt->len); > > + } > > +} > > + > > +static struct proto_field *proto_field_by_id(struct proto_gen *prot, int > > fid) > > +{ > > + int i; > > + > > + for (i = 0; i < prot->fields_count; i++) > > + if (prot->fields[i].id == fid) > > + return &prot->fields[i]; > > + > > + panic("Failed lookup field id %u for proto id %u\n", fid, prot->id); > > +} > > + > > +bool proto_field_is_set(enum proto_id pid, int fid) > > +{ > > + struct proto_gen *prot = proto_get_by_id(pid); > > + struct proto_field *field = proto_field_by_id(prot, fid); > > + > > + if (!field) > > + return false; > > + > > + return field->is_set; > > +} > > + > > +void proto_header_init(enum proto_id pid) > > +{ > > + struct proto_gen *prot = proto_get_by_id(pid); > > + int i; > > + > > + for (i = 0; i < headers_count; i++) { > > + if (headers[i]->id == prot->id) > > + return; > > + } > > + > > + if (headers_count >= PROTO_MAX_LAYERS) > > + panic("Too much proto headers\n"); > > + > > + headers[headers_count++] = prot; > > + > > + if (prot->header_init) > > + prot->header_init(prot); > > +} > > + > > +static void __proto_field_set_bytes(enum proto_id pid, uint32_t fid, > > + uint8_t *bytes, bool is_default, bool is_be) > > +{ > > + struct proto_field *field; > > + struct proto_gen *prot; > > + uint8_t *payload; > > + uint32_t v32; > > + uint16_t v16; > > + uint8_t v8; > > + > > + prot = proto_get_by_id(pid); > > + > > + field = proto_field_by_id(prot, fid); > > + if (field->is_set) > > + return; > > + > > + payload = ¤t_packet()->payload[field->pkt_offset]; > > + > > + if (field->len == 1) { > > + v8 = field_shift_and_mask(field, *bytes); > > + v8 = field->mask ? (v8 | *payload) : v8; > > + bytes = &v8; > > + } else if (field->len == 2) { > > + v16 = field_shift_and_mask(field, *(uint16_t *)bytes); > > + v16 = is_be ? cpu_to_be16(v16) : v16; > > + v16 = field->mask ? (v16 | *(uint16_t *)payload) : v16; > > + bytes = (uint8_t *)&v16; > > + } else if (field->len == 4) { > > + v32 = field_shift_and_mask(field, *(uint32_t *)bytes); > > + v32 = is_be ? cpu_to_be32(v32) : v32; > > + v32 = field->mask ? (v32 | *(uint32_t *)payload) : v32; > > + bytes = (uint8_t *)&v32; > > + } > > + > > + memcpy(payload, bytes, field->len); > > + > > + if (!is_default) > > + field->is_set = true; > > +} > > + > > +void proto_field_set_bytes(enum proto_id pid, uint32_t fid, uint8_t *bytes) > > +{ > > + __proto_field_set_bytes(pid, fid, bytes, false, false); > > +} > > + > > +static uint8_t *__proto_field_get_bytes(struct proto_field *field) > > +{ > > + struct packet *pkt = current_packet(); > > + > > + return &pkt->payload[field->pkt_offset]; > > +} > > + > > +void proto_field_set_u8(enum proto_id pid, uint32_t fid, uint8_t val) > > +{ > > + proto_field_set_bytes(pid, fid, (uint8_t *)&val); > > +} > > + > > +uint8_t proto_field_get_u8(enum proto_id pid, uint32_t fid) > > +{ > > + struct proto_gen *prot = proto_get_by_id(pid); > > + struct proto_field *field = proto_field_by_id(prot, fid); > > + uint8_t val = *__proto_field_get_bytes(field); > > + > > + return field_unmask_and_unshift(field, val); > > +} > > + > > +void proto_field_set_u16(enum proto_id pid, uint32_t fid, uint16_t val) > > +{ > > + proto_field_set_bytes(pid, fid, (uint8_t *)&val); > > +} > > + > > +uint16_t proto_field_get_u16(enum proto_id pid, uint32_t fid) > > +{ > > + struct proto_field *field = proto_field_by_id(proto_get_by_id(pid), > > fid); > > + uint16_t val = *(uint16_t *)__proto_field_get_bytes(field); > > + > > + return field_unmask_and_unshift(field, be16_to_cpu(val)); > > +} > > + > > +void proto_field_set_u32(enum proto_id pid, uint32_t fid, uint32_t val) > > +{ > > + proto_field_set_bytes(pid, fid, (uint8_t *)&val); > > +} > > + > > +uint32_t proto_field_get_u32(enum proto_id pid, uint32_t fid) > > +{ > > + struct proto_field *field = proto_field_by_id(proto_get_by_id(pid), > > fid); > > + uint32_t val = *(uint32_t *)__proto_field_get_bytes(field); > > + > > + return field_unmask_and_unshift(field, be32_to_cpu(val)); > > +} > > + > > +void proto_field_set_default_bytes(enum proto_id pid, uint32_t fid, > > uint8_t *bytes) > > +{ > > + __proto_field_set_bytes(pid, fid, bytes, true, false); > > +} > > + > > +void proto_field_set_default_u8(enum proto_id pid, uint32_t fid, uint8_t > > val) > > +{ > > + __proto_field_set_bytes(pid, fid, (uint8_t *)&val, true, false); > > +} > > + > > +void proto_field_set_default_u16(enum proto_id pid, uint32_t fid, uint16_t > > val) > > +{ > > + __proto_field_set_bytes(pid, fid, (uint8_t *)&val, true, false); > > +} > > + > > +void proto_field_set_default_u32(enum proto_id pid, uint32_t fid, uint32_t > > val) > > +{ > > + __proto_field_set_bytes(pid, fid, (uint8_t *)&val, true, false); > > +} > > + > > +void proto_field_set_be16(enum proto_id pid, uint32_t fid, uint16_t val) > > +{ > > + __proto_field_set_bytes(pid, fid, (uint8_t *)&val, false, true); > > +} > > + > > +void proto_field_set_be32(enum proto_id pid, uint32_t fid, uint32_t val) > > +{ > > + __proto_field_set_bytes(pid, fid, (uint8_t *)&val, false, true); > > +} > > + > > +void proto_field_set_default_be16(enum proto_id pid, uint32_t fid, > > uint16_t val) > > +{ > > + __proto_field_set_bytes(pid, fid, (uint8_t *)&val, true, true); > > +} > > + > > +void proto_field_set_default_be32(enum proto_id pid, uint32_t fid, > > uint32_t val) > > +{ > > + __proto_field_set_bytes(pid, fid, (uint8_t *)&val, true, true); > > +} > > + > > +void protos_init(char *dev) > > +{ > > + struct proto_gen *p; > > + > > + ctx.dev = dev; > > + > > + for (p = protos; p; p = p->next) > > + p->ctx = &ctx; > > +} > > + > > +void proto_packet_finish(void) > > +{ > > + int i; > > + > > + /* Go down from upper layers to do last calculations (checksum) */ > > + for (i = headers_count - 1; i >= 0; i--) { > > + struct proto_gen *p = headers[i]; > > + > > + if (p->header_finish) > > + p->header_finish(p); > > + } > > + > > + for (i = 0; i < headers_count; i++) { > > + struct proto_gen *p = headers[i]; > > + > > + if (p->fields) { > > + xfree(p->fields); > > + p->fields_count = 0; > > + } > > + > > + headers[i] = NULL; > > + } > > + > > + headers_count = 0; > > +} > > diff --git a/trafgen_proto.h b/trafgen_proto.h > > new file mode 100644 > > index 0000000..76f3376 > > --- /dev/null > > +++ b/trafgen_proto.h > > @@ -0,0 +1,82 @@ > > +#ifndef TRAFGEN_PROTO_I_H > > +#define TRAFGEN_PROTO_I_H > > + > > +#include <stdint.h> > > +#include <stdbool.h> > > + > > +struct proto_ctx { > > + char *dev; > > +}; > > + > > +enum proto_id { > > + PROTO_NONE, > > + PROTO_ETH, > > + PROTO_ARP, > > + PROTO_IP4, > > + PROTO_IP6, > > + PROTO_UDP, > > + PROTO_TCP, > > +}; > > + > > +struct proto_field { > > + int id; > > Shouldn't this be uint32_t to be consistent with the "uint32_t fid" > parameter of the manipulating functions? Also some proto_field_* > functions take "fid" as int. These should probably be changed to > uint32_t as well to be consistent. > > > + int len; > > size_t? > > > + uint32_t shift; > > + uint32_t mask; > > + uint16_t offset; > > + > > + bool is_set; > > + uint16_t pkt_offset; > > +}; > > + > > +struct proto_gen { > > + struct proto_gen *next; > > + struct proto_ctx *ctx; > > + enum proto_id id; > > + uint16_t pkt_offset; > > + > > + /* array of fields ordered from the lower to higher offset */ > > + struct proto_field *fields; > > + int fields_count; > > size_t? > > > + > > + void (*header_init)(struct proto_gen *prot); > > + void (*header_finish)(struct proto_gen *prot); > > +}; > > + > > +extern void protos_init(char *dev); > > +extern void proto_register(struct proto_gen *prot); > > +extern struct proto_gen *proto_get_by_id(enum proto_id id); > > + > > +extern void proto_header_init(enum proto_id pid); > > +extern void proto_packet_finish(void); > > + > > +extern void proto_fields_add(enum proto_id pid, struct proto_field *fields, > > + int count); > > +extern bool proto_field_is_set(enum proto_id pid, int fid); > > +extern void proto_field_set_bytes(enum proto_id pid, uint32_t fid, > > + uint8_t *bytes); > > +extern void proto_field_set_u8(enum proto_id pid, uint32_t fid, uint8_t > > val); > > +extern uint8_t proto_field_get_u8(enum proto_id pid, uint32_t fid); > > +extern void proto_field_set_u16(enum proto_id pid, uint32_t fid, uint16_t > > val); > > +extern uint16_t proto_field_get_u16(enum proto_id pid, uint32_t fid); > > +extern void proto_field_set_u32(enum proto_id pid, uint32_t fid, uint32_t > > val); > > +extern uint32_t proto_field_get_u32(enum proto_id pid, uint32_t fid); > > + > > +extern void proto_field_set_default_bytes(enum proto_id pid, uint32_t fid, > > + uint8_t *bytes); > > +extern void proto_field_set_default_u8(enum proto_id pid, uint32_t fid, > > + uint8_t val); > > +extern void proto_field_set_default_u16(enum proto_id pid, uint32_t fid, > > + uint16_t val); > > +extern void proto_field_set_default_u32(enum proto_id pid, uint32_t fid, > > + uint32_t val); > > + > > +extern void proto_field_set_be16(enum proto_id pid, uint32_t fid, uint16_t > > val); > > +extern void proto_field_set_be32(enum proto_id pid, uint32_t fid, uint32_t > > val); > > + > > +extern void proto_field_set_default_be16(enum proto_id pid, uint32_t fid, > > + uint16_t val); > > +extern void proto_field_set_default_be32(enum proto_id pid, uint32_t fid, > > + uint32_t val); > > + > > +#endif /* TRAFGEN_PROTO_I_H */ > > -- > > 2.6.3 > > -- 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.