From: Vadim Kochan <[email protected]>

Added high-level command line protocol packet building intreface,
which allows to specify specified protocol parameters to build
the protocol specific header.

Each protocol is represented by proto_gen struct which is responsible
only for providing field description (size, data) by name to trafgen's
low level packet generation layer.

All packet generation routine is performed by the generic code in
trafgen.c which parses the command line, obtains proto name, param=value
list and calls the specific protocol handler to get protocol field info
by name.

The command line syntax looks like:

    trafgen/trafgen --dev lo eth da = AA:BB:CC:DD:EE:FF sa=11:22:33:44:55:66, 
arp op=rep tip=192.168.1.1 -n 1

so the first is proto name and after there are param value pairs which
are separated by space, in case if there are multiple protocols
specified - their should be separated by "," after last param value of
the previous protocol.

Signed-off-by: Vadim Kochan <[email protected]>
---
 layer2_gen.c     | 248 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 net_utils.c      |  41 +++++++++
 net_utils.h      |   7 ++
 proto_gen.c      | 115 ++++++++++++++++++++++++++
 proto_gen.h      |  72 ++++++++++++++++
 trafgen.c        | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 trafgen/Makefile |   3 +
 7 files changed, 720 insertions(+), 5 deletions(-)
 create mode 100644 layer2_gen.c
 create mode 100644 net_utils.c
 create mode 100644 net_utils.h
 create mode 100644 proto_gen.c
 create mode 100644 proto_gen.h

diff --git a/layer2_gen.c b/layer2_gen.c
new file mode 100644
index 0000000..08d2bc1
--- /dev/null
+++ b/layer2_gen.c
@@ -0,0 +1,248 @@
+/*
+ * netsniff-ng - the packet sniffing beast
+ * Subject to the GPL, version 2.
+ */
+
+#include <net/if_arp.h>
+#include <linux/if_ether.h>
+
+#include "xmalloc.h"
+#include "net_utils.h"
+#include "proto_gen.h"
+
+enum eth_field {
+       ETH_DST_ADDR,
+       ETH_SRC_ADDR,
+       ETH_PROTO_ID,
+};
+
+static int eth_parse_param(struct proto_gen *prot, char *name, char *val)
+{
+       uint8_t addr[6] = {};
+
+       if (!strcasecmp("dst", name) || !strcasecmp("da", name)) {
+               int ret = str2mac(val, &addr[0]);
+               proto_field_set_bytes(prot, ETH_DST_ADDR, &addr[0]);
+
+               return ret == 0 ? ETH_DST_ADDR : -1;
+       }
+
+       if (!strcasecmp("src", name) || !strcasecmp("sa", name)) {
+               int ret = str2mac(val, &addr[0]);
+               proto_field_set_bytes(prot, ETH_SRC_ADDR, &addr[0]);
+
+               return ret == 0 ? ETH_SRC_ADDR : -1;
+       }
+
+       if (!strcasecmp("type", name) || !strcasecmp("proto", name)) {
+               if (val) {
+                       char *ptr = NULL;
+                       int proto_id = htons(strtol(val, &ptr, 0));
+
+                       if (errno == ERANGE || errno == EINVAL || ptr == val)
+                               return -1;
+
+                       proto_field_set_value(prot, ETH_PROTO_ID, proto_id);
+                       return ETH_PROTO_ID;
+               }
+       }
+
+       return -1;
+}
+
+static void eth_check_fields(struct proto_gen *prot)
+{
+}
+
+static void eth_set_next_proto(struct proto_gen *prot, struct proto_gen *next)
+{
+       int proto_id = 0;
+
+       switch (next->id) {
+       case NET_PROTO_ARP:
+               proto_id = ETH_P_ARP;
+               break;
+       case NET_PROTO_IPV4:
+               proto_id = ETH_P_IP;
+               break;
+       case NET_PROTO_IPV6:
+               proto_id = ETH_P_IPV6;
+               break;
+       case NET_PROTO_NONE:
+       case NET_PROTO_ETH:
+       case NET_PROTO_UDP:
+       case NET_PROTO_TCP:
+               break;
+       }
+
+       proto_field_set_value(prot, ETH_PROTO_ID, htons(proto_id));
+}
+
+static void eth_print_help(struct proto_gen *prot)
+{
+#define ETH_PROT_HELP \
+       "| eth proto: Sends Ethernet packets.\n" \
+       "| Parameters:\n" \
+       "|\n" \
+       "|    src,sa = XX:XX:XX:XX:XX:XX               ..... Source MAC 
address\n" \
+       "|    dst,da = XX:XX:XX:XX:XX:XX               ..... Destination MAC 
address\n" \
+       "|    proto,type = decimal | 0xXXX             ..... Sets 
proto/type/len value\n" \
+       "|    data,payload = hexadecimal               ..... Binary payload 
data\n" \
+       "|    text = ascii string                      ..... Textual payload 
data\n" \
+       "|\n" \
+       "| EXAMPLES:\n" \
+       "|      trafgen --dev eth0 eth sa=af:cd:4b:c3:56:6a, 
da=af:cd:4b:c3:56:6a, proto=0x0800\n" \
+       "|\n" \
+       "\n"
+
+       printf(ETH_PROT_HELP);
+}
+
+static void eth_proto_init(struct proto_gen *prot)
+{
+       proto_fields_alloc(prot, 3);
+
+       proto_field_add(prot, ETH_DST_ADDR, 6);
+       proto_field_add(prot, ETH_SRC_ADDR, 6);
+       proto_field_add(prot, ETH_PROTO_ID, 2);
+}
+
+static struct proto_gen eth_gen = {
+       .id             = NET_PROTO_ETH,
+       .name           = "eth",
+       .min_size       = 15,
+       .proto_init     = eth_proto_init,
+       .parse_param    = eth_parse_param,
+       .check_fields   = eth_check_fields,
+       .set_next_proto = eth_set_next_proto,
+       .print_help     = eth_print_help,
+};
+
+enum arp_field {
+       ARP_HW_TYPE,
+       ARP_PROT_TYPE,
+       ARP_HW_LEN,
+       ARP_PROT_LEN,
+       ARP_OP_TYPE,
+       ARP_SENDER_HW_ADDR,
+       ARP_SENDER_PROT_ADDR,
+       ARP_TARGET_HW_ADDR,
+       ARP_TARGET_PROT_ADDR,
+};
+
+static void arp_proto_init(struct proto_gen *prot)
+{
+       proto_fields_alloc(prot, 9);
+
+       proto_field_add(prot, ARP_HW_TYPE, 2);
+       proto_field_add(prot, ARP_PROT_TYPE, 2);
+       proto_field_add(prot, ARP_HW_LEN, 1);
+       proto_field_add(prot, ARP_PROT_LEN, 1);
+       proto_field_add(prot, ARP_OP_TYPE, 2);
+       proto_field_add(prot, ARP_SENDER_HW_ADDR, 6);
+       proto_field_add(prot, ARP_SENDER_PROT_ADDR, 4);
+       proto_field_add(prot, ARP_TARGET_HW_ADDR, 6);
+       proto_field_add(prot, ARP_TARGET_PROT_ADDR, 4);
+
+       /* set defaults */
+       proto_field_set_value(prot, ARP_HW_TYPE, htons(ARPHRD_ETHER));
+       proto_field_set_value(prot, ARP_PROT_TYPE, htons(ETH_P_IP));
+       proto_field_set_value(prot, ARP_HW_LEN, 6);
+       proto_field_set_value(prot, ARP_PROT_LEN, 4);
+       proto_field_set_value(prot, ARP_OP_TYPE, htons(ARPOP_REQUEST));
+}
+
+static int arp_parse_param(struct proto_gen *prot, char *name, char *val)
+{
+       if (!strcasecmp("tmac", name) || !strcasecmp("targetmac", name)) {
+               uint8_t mac[6];
+               int ret = str2mac(val, &mac[0]);
+
+               proto_field_set_bytes(prot, ARP_TARGET_HW_ADDR, &mac[0]);
+               return ret == 0 ? ARP_TARGET_HW_ADDR : -1;
+       }
+
+       if (!strcasecmp("smac", name) || !strcasecmp("sendermac", name)) {
+               uint8_t mac[6];
+               int ret = str2mac(val, &mac[0]);
+
+               proto_field_set_bytes(prot, ARP_SENDER_HW_ADDR, &mac[0]);
+               return ret == 0 ? ARP_SENDER_HW_ADDR : -1;
+       }
+
+       if (!strcasecmp("tip", name) || !strcasecmp("targetip", name)) {
+               uint8_t ip[4];
+               int ret = str2addr(AF_INET, val, &ip[0]);
+
+               proto_field_set_bytes(prot, ARP_TARGET_PROT_ADDR, &ip[0]);
+               return ret == 0 ? ARP_TARGET_PROT_ADDR : -1;
+       }
+
+       if (!strcasecmp("sip", name) || !strcasecmp("senderip", name)) {
+               uint8_t ip[4];
+               int ret = str2addr(AF_INET, val, &ip[0]);
+
+               proto_field_set_bytes(prot, ARP_SENDER_PROT_ADDR, &ip[0]);
+               return ret == 0 ? ARP_SENDER_PROT_ADDR : -1;
+       }
+
+       if (!strcasecmp("op", name) || !strcasecmp("oper", name)) {
+               int op = ARPOP_REQUEST;
+
+               if (!strncasecmp("rep", val, 3))
+                       op = ARPOP_REPLY;
+               else if (!strncasecmp("rreq", val, 4))
+                       op = ARPOP_RREQUEST;
+               else if (!strncasecmp("rrep", val, 4))
+                       op = ARPOP_RREPLY;
+               else if (!strncasecmp("in-req", val, 5))
+                       op = ARPOP_InREQUEST;
+               else if (!strncasecmp("in-rep", val, 5))
+                       op = ARPOP_InREPLY;
+               else if (!strcasecmp("nak", val))
+                       op = ARPOP_NAK;
+               else if (strncasecmp("req", val, 3))
+                       return -1;
+
+               proto_field_set_value(prot, ARP_OP_TYPE, htons(op));
+               return ARP_OP_TYPE;
+       }
+
+       return -1;
+}
+
+static void arp_print_help(struct proto_gen *prot)
+{
+#define ARP_PROT_HELP \
+       "| arp proto: Sends ARP packets.\n" \
+       "| Parameters:\n" \
+       "|\n" \
+       "|    sip,senderip = XXX.XXX.XXX.XXX           ..... Sender Proto 
address\n" \
+       "|    smac,sendermac = XX:XX:XX:XX:XX:XX       ..... Sender HW 
address\n" \
+       "|    tip,targetip = XXX.XXX.XXX.XXX           ..... Target Proto 
address\n" \
+       "|    tmac,targetmac = XX:XX:XX:XX:XX:XX       ..... Target HW 
address\n" \
+       "|    op,oper =  reply|req|rreq|in-req|nak     ..... Operation type\n" \
+       "|\n" \
+       "| EXAMPLES:\n" \
+       "|      trafgen/trafgen --dev lo eth da = AA:BB:CC:DD:EE:FF 
sa=11:22:33:44:55:66, arp op=rep tip=192.168.1.1 -n 1\n" \
+       "|      trafgen/trafgen --dev lo arp -n 1\n" \
+       "|\n" \
+       "\n"
+
+       printf(ARP_PROT_HELP);
+}
+
+static struct proto_gen arp_gen = {
+       .id             = NET_PROTO_ARP,
+       .layer_proto    = NET_PROTO_ETH,
+       .name           = "arp",
+       .proto_init     = arp_proto_init,
+       .parse_param    = arp_parse_param,
+       .print_help     = arp_print_help,
+};
+
+void layer2_gen_register(void)
+{
+       proto_gen_register(&eth_gen);
+       proto_gen_register(&arp_gen);
+}
diff --git a/net_utils.c b/net_utils.c
new file mode 100644
index 0000000..749199b
--- /dev/null
+++ b/net_utils.c
@@ -0,0 +1,41 @@
+/*
+ * netsniff-ng - the packet sniffing beast
+ * Subject to the GPL, version 2.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+int str2mac(char *str, uint8_t *mac)
+{
+       int i, count;
+       unsigned int tmp[6];
+
+       if (!str)
+              return -1;
+
+       count = sscanf(str, "%02X:%02X:%02X:%02X:%02X:%02X",
+                       &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]);
+
+       if (count != 6)
+               count = sscanf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
+                       &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]);
+
+       if (count != 6)
+               return -1;
+
+       for (i = 0; i < 6; i++)
+               mac[i] = (uint8_t)tmp[i];
+
+       return 0;
+}
+
+int str2addr(int af, const char *str, uint8_t *addr)
+{
+       if (inet_pton(af, str, addr))
+               return 0;
+
+       return -1;
+}
diff --git a/net_utils.h b/net_utils.h
new file mode 100644
index 0000000..5bd7b7e
--- /dev/null
+++ b/net_utils.h
@@ -0,0 +1,7 @@
+#ifndef NET_UTILS_I_H
+#define NET_UTILS_I_H
+
+int str2mac(char *str, uint8_t *mac);
+int str2addr(int af, const char *str, uint8_t *addr);
+
+#endif
diff --git a/proto_gen.c b/proto_gen.c
new file mode 100644
index 0000000..224db0f
--- /dev/null
+++ b/proto_gen.c
@@ -0,0 +1,115 @@
+/*
+ * netsniff-ng - the packet sniffing beast
+ * Subject to the GPL, version 2.
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+#include "proto_gen.h"
+#include "xmalloc.h"
+
+static struct proto_gen *protos;
+
+extern void layer2_gen_register(void);
+
+struct proto_gen *proto_gen_by_name(char *name)
+{
+       struct proto_gen *p = protos;
+
+       for (; p; p = p->next)
+               if (strcmp(p->name, name) == 0)
+                       return p;
+
+       return NULL;
+}
+
+struct proto_gen *proto_gen_by_id(enum net_proto id)
+{
+       struct proto_gen *p = protos;
+
+       for (; p; p = p->next)
+               if (p->id == id)
+                       return p;
+
+       return NULL;
+}
+
+void proto_gen_register(struct proto_gen *prot)
+{
+       prot->next = protos;
+       protos = prot;
+}
+
+void proto_gen_init(void)
+{
+       layer2_gen_register();
+}
+
+void proto_gen_uninit(void)
+{
+       struct proto_gen *p = protos;
+
+       for (; p; p = p->next) {
+               int f;
+
+               if (p->payload)
+                       xfree(p->payload);
+
+               if (!p->fields)
+                       continue;
+
+               for (f = 0; f < p->fields_count; f++)
+                       if (p->fields[f].is_allocated)
+                               xfree(p->fields[f].data);
+
+               xfree(p->fields);
+       }
+}
+
+void proto_gen_set_ctx(struct ctx *ctx)
+{
+       struct proto_gen *p = protos;
+
+       for (; p; p = p->next)
+               p->ctx = ctx;
+}
+
+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_alloc(struct proto_gen *prot, int count)
+{
+       proto_fields_realloc(prot, count);
+       memset(prot->fields, 0, count * sizeof(*prot->fields));
+}
+
+void proto_field_add(struct proto_gen *prot, int id, size_t len)
+{
+       struct proto_field *field = &prot->fields[id];
+
+       if (id >= prot->fields_count)
+               proto_fields_realloc(prot, id + 1);
+
+       if (len > sizeof(field->value)) {
+               field->data = xzmalloc(len);
+               field->is_allocated = true;
+       } else {
+               field->data = (uint8_t *)&field->value;
+       }
+
+       field->len = len;
+}
+
+void proto_field_set_bytes(struct proto_gen *prot, int id, uint8_t *bytes)
+{
+       memcpy(prot->fields[id].data, bytes, prot->fields[id].len);
+}
+
+void proto_field_set_value(struct proto_gen *prot, int id, int value)
+{
+       proto_field_set_bytes(prot, id, (uint8_t *)&value);
+}
diff --git a/proto_gen.h b/proto_gen.h
new file mode 100644
index 0000000..e51769c
--- /dev/null
+++ b/proto_gen.h
@@ -0,0 +1,72 @@
+#ifndef PROTO_GEN_I_H
+#define PROTO_GEN_I_H
+
+#include "trafgen.h"
+#include "trafgen_conf.h"
+
+enum net_proto {
+       NET_PROTO_NONE,
+       NET_PROTO_ETH,
+       NET_PROTO_ARP,
+       NET_PROTO_IPV4,
+       NET_PROTO_IPV6,
+       NET_PROTO_UDP,
+       NET_PROTO_TCP,
+};
+
+enum field_op {
+       OP_CSUM_IP,
+       OP_CSUM_UDP,
+       OP_CSUM_TCP,
+       OP_FILL_BYTES,
+       OP_COUNTER,
+       OP_RAND,
+};
+
+struct proto_field {
+       bool is_allocated;
+       uint8_t *data;
+       int value;
+       int len;
+};
+
+struct proto_gen {
+       struct proto_gen *next;
+       struct ctx *ctx;
+       uint8_t *payload;
+       /* payload len */
+       int len;
+
+       /* array of fields ordered from the lower to higher offset */
+       struct proto_field *fields;
+       int fields_count;
+
+       char *name;
+       size_t min_size;
+       enum net_proto id;
+       /* in case if no lower layer proto is specified */
+       enum net_proto layer_proto;
+
+       void (*proto_init)(struct proto_gen *prot);
+       void (*print_help)(struct proto_gen *prot);
+       int (*parse_param)(struct proto_gen *prot, char *arg, char *val);
+       void (*check_fields)(struct proto_gen *prot);
+       void (*set_next_proto)(struct proto_gen *prot, struct proto_gen *next);
+};
+
+void proto_gen_register(struct proto_gen *prot);
+struct proto_gen *proto_gen_by_name(char *name);
+struct proto_gen *proto_gen_by_id(enum net_proto id);
+
+void proto_gen_init(void);
+void proto_gen_uninit(void);
+void proto_gen_set_ctx(struct ctx *ctx);
+
+void proto_fields_alloc(struct proto_gen *prot, int count);
+void proto_fields_realloc(struct proto_gen *prot, int count);
+
+void proto_field_add(struct proto_gen *prot, int id, size_t len);
+void proto_field_set_value(struct proto_gen *prot, int id, int value);
+void proto_field_set_bytes(struct proto_gen *prot, int id, uint8_t *value);
+
+#endif
diff --git a/trafgen.c b/trafgen.c
index f7402d6..ca8842c 100644
--- a/trafgen.c
+++ b/trafgen.c
@@ -51,6 +51,7 @@
 #include "ring_tx.h"
 #include "csum.h"
 #include "trafgen.h"
+#include "proto_gen.h"
 
 struct cpu_stats {
        unsigned long tv_sec, tv_usec;
@@ -68,6 +69,11 @@ size_t plen = 0;
 struct packet_dyn *packet_dyn = NULL;
 size_t dlen = 0;
 
+static bool has_proto = false;
+#define PROTO_MAX_LAYERS       8
+static struct proto_gen *protos[PROTO_MAX_LAYERS];
+static int protos_count = 0;
+
 static const char *short_options = "d:c:n:t:vJhS:rk:i:o:VRs:P:eE:pu:g:CHQq";
 static const struct option long_options[] = {
        {"dev",                 required_argument,      NULL, 'd'},
@@ -786,10 +792,224 @@ static int xmit_packet_precheck(struct ctx *ctx, 
unsigned int cpu)
        return 0;
 }
 
+static void proto_layer_add(struct proto_gen *prot)
+{
+       struct proto_gen *prev;
+
+       /* find lower proto if it is needed & exist */
+       if (!protos_count && prot->layer_proto) {
+               struct proto_gen *lower = proto_gen_by_id(prot->layer_proto);
+
+               if (lower) {
+                       if (lower->proto_init)
+                               lower->proto_init(lower);
+
+                       if (lower->check_fields)
+                               lower->check_fields(lower);
+
+                       proto_layer_add(lower);
+               }
+       }
+
+       if (protos_count >= PROTO_MAX_LAYERS)
+               panic("Too much proto layers\n");
+
+       prev = protos_count > 0 ? protos[protos_count - 1] : NULL;
+       protos[protos_count++] = prot;
+
+       if (prev && prev->set_next_proto)
+               prev->set_next_proto(prev, prot);
+}
+
+static void proto_fill_fields(struct proto_gen *prot)
+{
+       int i;
+
+       for (i = 0; i < prot->fields_count; i++) {
+               struct proto_field *field = &prot->fields[i];
+
+               if (!field->data) {
+                       set_fill(0, field->len);
+                       continue;
+               }
+
+               set_multi_byte(field->data, field->len);
+       }
+}
+
+static void proto_check_padding(struct proto_gen *prot)
+{
+       int pkt_len;
+
+       if (!prot->min_size)
+               return;
+
+       pkt_len = current_packet()->len;
+       if (pkt_len < prot->min_size)
+               set_fill(0, prot->min_size - pkt_len);
+}
+
+static void proto_gen_packets(void)
+{
+       int i;
+
+       realloc_packet();
+
+       for (i = 0; i < protos_count; i++) {
+               proto_fill_fields(protos[i]);
+
+               if (protos[i]->payload)
+                       set_multi_byte(protos[i]->payload, protos[i]->len);
+       }
+
+       /* check for padding (i.e. Ethernet min frame size is 64 bytes) */
+       proto_check_padding(protos[0]);
+}
+
+static char *parse_name_value(char *str, char **name, char **value)
+{
+       char *eq_ptr = strchr(str, '=');
+       char *end;
+       bool has_quote = false;
+
+       if (!eq_ptr)
+               return NULL;
+
+       /* parse name */
+       while (*str && isspace(*str))
+               str++;
+
+       end = str;
+       while (*end && !isspace(*end) && *end != '=')
+               end++;
+
+       if (!end)
+               return NULL;
+
+       *end = '\0';
+       *name = str;
+
+       /* parse value */
+       str = eq_ptr + 1;
+       while (*str && (isspace(*str) || *str == '"')) {
+               if (*str == '"') {
+                       has_quote = true;
+                       str++;
+                       break;
+               }
+               str++;
+       }
+
+       end = str;
+       while (*end) {
+               if (!has_quote && isspace(*end)) {
+                       break;
+               } else if (has_quote && *end == '"') {
+                       break;
+               }
+               end++;
+       }
+
+       *value = str;
+
+       if (*end == '\0')
+               return end;
+
+       *end = '\0';
+       return ++end;
+}
+
+static int parse_common_param(struct proto_gen *prot, char *name, char *value)
+{
+       if (!strcasecmp("payload", name) || !strcasecmp("data", name)) {
+               if (prot->payload)
+                       xfree(prot->payload);
+
+               prot->len = str2bytes(value, &prot->payload);
+
+               if (!prot->len)
+                       panic("Invalid payload\n");
+
+               return 0;
+       }
+
+       if (!strcasecmp("text", name)) {
+               if (prot->payload)
+                       xfree(prot->payload);
+
+               prot->payload = (uint8_t *)strdup(value);
+               prot->len = strlen(value);
+
+               return 0;
+       }
+
+       return -1;
+}
+
+static void parse_proto_params(struct proto_gen *prot, char *params)
+{
+       char *name = NULL, *value = NULL;
+
+       while ((params = parse_name_value(params, &name, &value))) {
+               if (!name || !value || !strlen(name) || !strlen(value))
+                       panic("Can't parse param name=value\n");
+
+               if ((prot->parse_param(prot, name, value)) == -1) {
+                       if (!parse_common_param(prot, name, value))
+                               continue;
+
+                       if (prot->print_help)
+                               prot->print_help(prot);
+
+                       panic("proto %s: Invalid argument(%s=%s)\n", prot->name,
+                                       name, value);
+               }
+       }
+}
+
+static int parse_proto(int argc, char **argv)
+{
+       char *args = cmdline_args2str(optind, argc, argv);
+       char *args_ptr = args;
+       struct proto_gen *prot;
+       char *proto_args, *proto_args_ptr = NULL;
+
+       while ((proto_args = strtok_r(args_ptr, ",", &proto_args_ptr))) {
+               char *args_list = NULL;
+               char *prot_name = strtok_r(proto_args, " ", &args_list);
+
+               if (!prot_name || !strlen(prot_name))
+                       panic("proto is null\n");
+
+               prot = proto_gen_by_name(prot_name);
+               if (!prot)
+                       panic("proto %s: Is not supported\n", prot_name);
+
+               if (prot->proto_init)
+                       prot->proto_init(prot);
+
+               parse_proto_params(prot, args_list);
+
+               proto_layer_add(prot);
+
+               if (prot->check_fields)
+                       prot->check_fields(prot);
+
+               args_ptr = NULL;
+       }
+
+       proto_gen_packets();
+
+       xfree(args);
+       return 0;
+}
+
 static void main_loop(struct ctx *ctx, char *confname, bool slow,
                      unsigned int cpu, bool invoke_cpp, unsigned long orig_num)
 {
-       compile_packets(confname, ctx->verbose, cpu, invoke_cpp);
+       if (!has_proto)
+               compile_packets(confname, ctx->verbose, cpu, invoke_cpp);
+
        if (xmit_packet_precheck(ctx, cpu) < 0)
                return;
 
@@ -1030,15 +1250,22 @@ int main(int argc, char **argv)
                }
        }
 
-       if (argc < 5)
-               help();
        if (ctx.device == NULL)
                panic("No networking device given!\n");
-       if (confname == NULL)
-               panic("No configuration file given!\n");
        if (device_mtu(ctx.device) == 0)
                panic("This is no networking device!\n");
 
+       proto_gen_init();
+       proto_gen_set_ctx(&ctx);
+
+       if (optind != argc && !parse_proto(argc, argv))
+               has_proto = true;
+
+       if (argc < 5 && !has_proto)
+               help();
+       if (confname == NULL && !has_proto)
+               panic("No configuration file given!\n");
+
        register_signal(SIGINT, signal_handler);
        register_signal(SIGQUIT, signal_handler);
        register_signal(SIGTERM, signal_handler);
@@ -1137,5 +1364,7 @@ thread_out:
        free(ctx.rhost);
        free(confname);
 
+       proto_gen_uninit();
+
        return 0;
 }
diff --git a/trafgen/Makefile b/trafgen/Makefile
index 3cb8497..7b5b2ea 100644
--- a/trafgen/Makefile
+++ b/trafgen/Makefile
@@ -17,6 +17,9 @@ trafgen-objs =        xmalloc.o \
                ring_tx.o \
                ring.o \
                timer.o \
+               net_utils.o \
+               proto_gen.o \
+               layer2_gen.o \
                trafgen_lexer.yy.o \
                trafgen_parser.tab.o \
                trafgen.o
-- 
2.4.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 [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to