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 = &current_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.

Reply via email to