]> mj.ucw.cz Git - netgrind.git/commitdiff
Initial revision
authorMartin Mares <mj@ucw.cz>
Fri, 6 Jun 2003 15:57:32 +0000 (15:57 +0000)
committerMartin Mares <mj@ucw.cz>
Fri, 6 Jun 2003 15:57:32 +0000 (15:57 +0000)
13 files changed:
Makefile [new file with mode: 0644]
build/mergedeps [new file with mode: 0755]
lib/Makefile [new file with mode: 0644]
lib/alloc.c [new file with mode: 0644]
lib/assert.c [new file with mode: 0644]
lib/config.h [new file with mode: 0644]
lib/lib.h [new file with mode: 0644]
lib/lists.h [new file with mode: 0644]
netgrind/Makefile [new file with mode: 0644]
netgrind/netgrind.c [new file with mode: 0644]
netgrind/netgrind.h [new file with mode: 0644]
netgrind/pkt.c [new file with mode: 0644]
netgrind/pkt.h [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..c7bf0d0
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,80 @@
+CLANG=-std=gnu99
+COPT=-O2 -fstrict-aliasing -finline-limit=2000
+CWARNS=-Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes -Winline
+LOPT=
+LIBS=
+CDEBUG=-DDEBUG -ggdb
+
+CFLAGS=$(CLANG) $(COPT) $(CDEBUG) $(CWARNS) -I.
+LDFLAGS=$(LOPT)
+
+.PHONY: all dust clean distclean programs dirtree
+
+DIRS=
+PROGS=
+
+all: dirtree programs
+
+dust::
+       rm -f `find . -path "*~" -or -name "\#*\#" -or -name core`
+
+clean:: dust
+       rm -rf obj
+       rm -f depend depend.new TAGS
+
+distclean:: clean
+
+include lib/Makefile
+include netgrind/Makefile
+
+programs: $(PROGS)
+
+dirtree: $(addsuffix /.dir-stamp,$(addprefix obj/,$(DIRS)))
+
+tags:
+       etags `find . -name "*.[ch]"`
+
+# Black magic with dependencies. It would be more correct to make "depend.new"
+# a prerequisite for "depend", but "depend.new" often has the same timestamp
+# as "depend" which would confuse make a lot and either force remaking anyway
+# or (as in current versions of GNU make) erroneously skipping the remaking.
+
+-include depend
+
+depend: force
+       if [ -s depend.new ] ; then build/mergedeps depend depend.new ; >depend.new ; fi
+
+force:
+
+# Implicit rules
+
+%.dir-stamp:
+       mkdir -p $(@D) && touch $@
+
+%.a:
+       ar rcs $@ $?
+
+obj/%.o: %.c
+       DEPENDENCIES_OUTPUT="depend.new $@" $(CC) $(CFLAGS) -c -o $@ $<
+
+obj/%-tt.o: %.c
+       DEPENDENCIES_OUTPUT="depend.new $@" $(CC) $(CFLAGS) -DTEST -c -o $@ $<
+
+obj/%-t: obj/%-tt.o
+       $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+obj/%: obj/%.o
+       $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+obj/%: %.sh
+       cp $(TOPDIR)/$^ $@
+       chmod +x $@
+
+obj/%: %.pl
+       cp $(TOPDIR)/$^ $@
+       chmod +x $@
+
+# Don't delete intermediate targets. There shouldn't be any, but due to bugs
+# in GNU Make rules with targets in not-yet-existing directories are ignored
+# when searching for implicit rules and thence targets considered intermediate.
+.SECONDARY:
diff --git a/build/mergedeps b/build/mergedeps
new file mode 100755 (executable)
index 0000000..e1c467d
--- /dev/null
@@ -0,0 +1,21 @@
+#!/usr/bin/perl
+
+@ARGV == 2 or die "Usage: mergedeps <base> <update>";
+foreach $a (@ARGV) {
+       open F, "$a" or next;
+       $t = "";
+       while (<F>) {
+               $t .= $_;
+               if (! /\\$/) {
+                       ($t =~ /^(.*):/) || die "Parse error at $t";
+                       $rules{$1} = $t;
+                       $t = "";
+               }
+       }
+       close F;
+}
+open(F,">" . $ARGV[0]) || die "Unable to write output file";
+foreach $a (sort keys %rules) {
+       print F $rules{$a};
+}
+close F;
diff --git a/lib/Makefile b/lib/Makefile
new file mode 100644 (file)
index 0000000..c5190fd
--- /dev/null
@@ -0,0 +1,7 @@
+DIRS+=lib
+
+LIBSH=obj/lib/libsh.a
+LIBSH_MODS=alloc assert
+LIBSH_MOD_PATHS=$(addprefix obj/lib/,$(LIBSH_MODS))
+
+$(LIBSH): $(addsuffix .o,$(LIBSH_MOD_PATHS))
diff --git a/lib/alloc.c b/lib/alloc.c
new file mode 100644 (file)
index 0000000..40f3edf
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ *     Sherlock Library -- Memory Allocation
+ *
+ *     (c) 2000 Martin Mares <mj@ucw.cz>
+ *
+ *     This software may be freely distributed and used according to the terms
+ *     of the GNU Lesser General Public License.
+ */
+
+#include "lib/lib.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef DMALLOC
+
+void *
+xmalloc(uns size)
+{
+  void *x = malloc(size);
+  if (!x)
+    die("Cannot allocate %d bytes of memory", size);
+  return x;
+}
+
+#endif
+
+void *
+xmalloc_zero(uns size)
+{
+  void *x = xmalloc(size);
+  bzero(x, size);
+  return x;
+}
diff --git a/lib/assert.c b/lib/assert.c
new file mode 100644 (file)
index 0000000..61bd61b
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ *     Sherlock Library -- Assertions
+ *
+ *     (c) 2003 Martin Mares <mj@ucw.cz>
+ *
+ *     This software may be freely distributed and used according to the terms
+ *     of the GNU Lesser General Public License.
+ */
+
+#include "lib/lib.h"
+
+#include <stdlib.h>
+
+#ifdef DEBUG
+void
+assert_failed(char *assertion, char *file, int line)
+{
+  die("Assertion `%s' failed at %s:%d", assertion, file, line);
+  abort();
+}
+#else
+void
+assert_failed(void)
+{
+  die("Internal error: Assertion failed.");
+}
+#endif
diff --git a/lib/config.h b/lib/config.h
new file mode 100644 (file)
index 0000000..00e9f77
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ *     Sherlock Library -- Configuration-Dependent Definitions
+ *
+ *     (c) 1997--2003 Martin Mares <mj@ucw.cz>
+ *
+ *     This software may be freely distributed and used according to the terms
+ *     of the GNU Lesser General Public License.
+ */
+
+#ifndef _SHERLOCK_CONFIG_H
+#define _SHERLOCK_CONFIG_H
+
+#define CPU_I386 1
+#define CPU_LITTLE_ENDIAN 1
+#define CPU_ALLOW_UNALIGNED 1
+#define CPU_STRUCT_ALIGN 4
+#define CONFIG_LINUX 1
+
+/* Types */
+
+typedef unsigned char byte;            /* exactly 8 bits, unsigned */
+typedef signed char sbyte;             /* exactly 8 bits, signed */
+typedef unsigned short word;           /* exactly 16 bits, unsigned */
+typedef short sword;                   /* exactly 16 bits, signed */
+typedef unsigned short u16;            /* exactly 16 bits, unsigned */
+typedef short s16;                     /* exactly 16 bits, signed */
+typedef unsigned int u32;              /* exactly 32 bits, unsigned */
+typedef int s32;                       /* exactly 32 bits, signed */
+typedef unsigned int uns;              /* at least 32 bits */
+typedef unsigned long long int u64;    /* exactly 64 bits, unsigned */
+typedef long long int s64;             /* exactly 64 bits, signed */
+typedef unsigned long addr_int_t;      /* Both integer and address */
+typedef unsigned int sh_time_t;                /* Timestamp */
+
+#ifndef NULL
+#define NULL (void *)0
+#endif
+
+/* Misc */
+
+#ifdef __GNUC__
+
+#undef inline
+#define NONRET __attribute__((noreturn))
+#define UNUSED __attribute__((unused))
+#define CONSTRUCTOR __attribute__((constructor))
+#define PACKED __attribute__((packed))
+#define CONST __attribute__((const))
+#define PURE __attribute__((const))
+
+#else
+#error This program requires the GNU C compiler.
+#endif
+
+#endif
diff --git a/lib/lib.h b/lib/lib.h
new file mode 100644 (file)
index 0000000..13c07d6
--- /dev/null
+++ b/lib/lib.h
@@ -0,0 +1,86 @@
+/*
+ *     Sherlock Library -- Miscellaneous Functions
+ *
+ *     (c) 1997--2003 Martin Mares <mj@ucw.cz>
+ *
+ *     This software may be freely distributed and used according to the terms
+ *     of the GNU Lesser General Public License.
+ */
+
+/*
+ *  This file should be included as the very first include in all
+ *  source files, especially before all OS includes since it sets
+ *  up libc feature macros.
+ */
+
+#ifndef _SHERLOCK_LIB_H
+#define _SHERLOCK_LIB_H
+
+#include "lib/config.h"
+
+/* Tell libc we're going to use all extensions available */
+
+#define _GNU_SOURCE
+
+/* Ugly structure handling macros */
+
+#define OFFSETOF(s, i) ((unsigned int)&((s *)0)->i)
+#define SKIP_BACK(s, i, p) ((s *)((char *)p - OFFSETOF(s, i)))
+#define ALIGN(s, a) (((s)+a-1)&~(a-1))
+#define UNALIGNED_PART(ptr, type) (((long) (ptr)) % sizeof(type))
+
+/* Some other macros */
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#define CLAMP(x,min,max) ({ int _t=x; (_t < min) ? min : (_t > max) ? max : _t; })
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
+
+/* Logging */
+
+void die(byte *, ...) NONRET;
+
+#ifdef DEBUG
+void assert_failed(char *assertion, char *file, int line) NONRET;
+#define ASSERT(x) do { if (!(x)) assert_failed(#x, __FILE__, __LINE__); } while(0)
+#else
+void assert_failed(void) NONRET;
+#define ASSERT(x) do { if (__builtin_constant_p(x) && !(x)) assert_failed(); } while(0)
+#endif
+
+#ifdef LOCAL_DEBUG
+#define DBG(x,y...) log(L_DEBUG, x,##y)
+#else
+#define DBG(x,y...) do { } while(0)
+#endif
+
+/* Memory allocation */
+
+#ifdef DMALLOC
+/*
+ * The standard dmalloc macros tend to produce lots of namespace
+ * conflicts and we use only xmalloc and xfree, so we can define
+ * the stubs ourselves.
+ */
+#define DMALLOC_DISABLE
+#include <dmalloc.h>
+#define xmalloc(size) _xmalloc_leap(__FILE__, __LINE__, size)
+#define xrealloc(ptr,size) _xrealloc_leap(__FILE__, __LINE__, ptr, size)
+#define xfree(ptr) _xfree_leap(__FILE__, __LINE__, ptr)
+#else
+/*
+ * Unfortunately, several libraries we might want to link to define
+ * their own xmalloc and we don't want to interfere with them, hence
+ * the renaming.
+ */
+#define xmalloc sh_xmalloc
+void *xmalloc(unsigned);
+void *xrealloc(void *, unsigned);
+#define xfree(x) free(x)
+#endif
+
+void *xmalloc_zero(unsigned);
+byte *stralloc(byte *);
+
+#endif
diff --git a/lib/lists.h b/lib/lists.h
new file mode 100644 (file)
index 0000000..2f7cea1
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ *     Sherlock Library -- Linked Lists
+ *
+ *     (c) 2003 Martin Mares <mj@ucw.cz>
+ *
+ *     This software may be freely distributed and used according to the terms
+ *     of the GNU Lesser General Public License.
+ */
+
+#ifndef _SHERLOCK_LISTS_H
+#define _SHERLOCK_LISTS_H
+
+typedef struct node {
+  struct node *next, *prev;
+} node;
+
+typedef struct list {
+  struct node head;
+} list;
+
+static inline void *list_first(list *l)
+{
+  return (l->head.next != &l->head) ? l->head.next : NULL;
+}
+
+static inline void *list_last(list *l)
+{
+  return (l->head.prev != &l->head) ? l->head.prev : NULL;
+}
+
+#define WALK_LIST(n,list) for(n=(void*)(list).head; ((node*)(n))->next != &(list).head; n=(void*)((node*)(n))->next)
+
+static inline void list_insert(node *what, node *after)
+{
+  node *before = after->next;
+  what->next = before;
+  what->prev = before->prev;
+  before->prev = what;
+  after->next = what;
+}
+
+static inline void list_add_tail(list *l, node *n)
+{
+  list_insert(n, l->head.prev);
+}
+
+static inline void list_add_head(list *l, node *n)
+{
+  list_insert(n, &l->head);
+}
+
+static inline void list_remove(node *n)
+{
+  node *before = n->prev;
+  node *after = n->next;
+  before->next = after;
+  after->prev = before;
+}
+
+static inline void list_init(list *l)
+{
+  node *head = &l->head;
+  head->next = head->prev = head;
+}
+
+#endif
diff --git a/netgrind/Makefile b/netgrind/Makefile
new file mode 100644 (file)
index 0000000..60ce104
--- /dev/null
@@ -0,0 +1,6 @@
+DIRS+=netgrind
+PROGS+=obj/netgrind/netgrind
+NG_OBJS=netgrind.o pkt.o
+
+obj/netgrind/netgrind: $(addprefix obj/netgrind/,$(NG_OBJS)) $(LIBSH)
+obj/netgrind/netgrind: LIBS+=-lpcap
diff --git a/netgrind/netgrind.c b/netgrind/netgrind.c
new file mode 100644 (file)
index 0000000..a25f02a
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ *     Netgrind -- The Network Traffic Analyser
+ *
+ *     (c) 2003 Martin Mares <mj@ucw.cz>
+ *
+ *     This software may be freely distributed and used according to the terms
+ *     of the GNU General Public License.
+ */
+
+#include "lib/lib.h"
+#include "netgrind/netgrind.h"
+#include "netgrind/pkt.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <net/ethernet.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+
+#include <pcap.h>
+
+void die(byte *msg, ...)
+{
+  va_list args;
+
+  va_start(args, msg);
+  fputs("netgrind: ", stderr);
+  vfprintf(stderr, msg, args);
+  fputs("\n", stderr);
+  exit(1);
+}
+
+/*** CHECKSUMMING ***/
+
+static uns tcpip_calc_checksum(void *data, uns len, uns csum)
+{
+  byte *x = data;
+
+  while (len >= 2)
+    {
+      csum += (x[0] << 8) | x[1];
+      if (csum & 0xffff0000)
+       {
+         csum &= 0x0000ffff;
+         csum++;
+       }
+      x += 2;
+      len -= 2;
+    }
+  if (len)
+    {
+      csum += x[0];
+      if (csum & 0xffff0000)
+       {
+         csum &= 0x0000ffff;
+         csum++;
+       }
+    }
+  return csum;
+}
+
+static inline uns tcpip_verify_checksum(uns csum)
+{
+  return (csum == 0xffff);
+}
+
+/*** TCP LAYER ***/
+
+static struct pkt_stats stat_tcp_in, stat_tcp_invalid;
+
+static void tcp_got_packet(struct iphdr *iph, struct pkt *p)
+{
+  struct tcphdr *tcph;
+  struct {
+    u32 src;
+    u32 dst;
+    byte zero;
+    byte proto;
+    u16 len;
+  } fakehdr;
+
+  pkt_account(&stat_tcp_in, p);
+  if (!(tcph = pkt_peek(p, sizeof(*tcph))))
+    goto invalid;
+  uns hdrlen = 4*tcph->doff;
+  if (hdrlen < sizeof(*tcph) || hdrlen > pkt_len(p))
+    goto invalid;
+  fakehdr.src = iph->saddr;
+  fakehdr.dst = iph->daddr;
+  fakehdr.zero = 0;
+  fakehdr.proto = IPPROTO_TCP;
+  fakehdr.len = htons(pkt_len(p));
+  uns sum = tcpip_calc_checksum(&fakehdr, sizeof(fakehdr), 0);
+  sum = tcpip_calc_checksum(p->data, pkt_len(p), sum);
+  if (!tcpip_verify_checksum(sum))
+    goto invalid;
+
+  /* Here we should do something with the packet */
+  pkt_free(p);
+  return;
+
+ invalid:
+  pkt_account(&stat_tcp_invalid, p);
+  pkt_free(p);
+}
+
+/*** IP LAYER ***/
+
+static struct pkt_stats stat_ip_in, stat_ip_invalid, stat_ip_uninteresting, stat_ip_fragmented;
+
+static void ip_got_packet(struct pkt *p)
+{
+  struct iphdr *iph;
+
+  pkt_account(&stat_ip_in, p);
+  if (!(iph = pkt_peek(p, sizeof(*iph))))
+    goto invalid;
+  if (iph->ihl < 5)
+    goto invalid;
+  if (iph->version != 4)
+    goto invalid;
+  uns hdrlen = 4*iph->ihl;
+  if (pkt_len(p) < hdrlen)
+    goto invalid;
+  if (!tcpip_verify_checksum(tcpip_calc_checksum(p->data, hdrlen, 0)))
+    goto invalid;
+  uns len = ntohs(iph->tot_len);
+  if (len < hdrlen || len > pkt_len(p))
+    goto invalid;
+  pkt_unappend(p, pkt_len(p) - len);
+  pkt_pop(p, hdrlen);
+
+  if (iph->protocol != IPPROTO_TCP)
+    {
+      pkt_account(&stat_ip_uninteresting, p);
+      goto drop;
+    }
+  /* XXX: Fragmentation not supported yet, but well-behaved TCP stacks don't use it anyway */
+  if (ntohs(iph->frag_off) & 0x3fff)
+    {
+      pkt_account(&stat_ip_fragmented, p);
+      goto drop;
+    }
+  tcp_got_packet(iph, p);
+  return;
+
+ invalid:
+  pkt_account(&stat_ip_invalid, p);
+ drop:
+  pkt_free(p);
+}
+
+/*** LINK LAYER ***/
+
+static struct pkt_stats stat_link_dwarf, stat_link_in, stat_link_unknown, stat_link_arp;
+
+static void link_eth_got_packet(struct pkt *p)
+{
+  struct ether_header *eth;
+  uns etype;
+
+  pkt_account(&stat_link_in, p);
+  if (!(eth = pkt_pop(p, sizeof(*eth))))
+    {
+      pkt_account(&stat_link_dwarf, p);
+      return;
+    }
+  etype = ntohs(eth->ether_type);
+  switch (etype)
+    {
+    case ETHERTYPE_IP:
+      ip_got_packet(p);
+      break;
+    case ETHERTYPE_ARP:
+      pkt_account(&stat_link_arp, p);
+      pkt_free(p);
+      break;
+    default:
+      // printf("Unknown ethertype: %04x\n", etype);
+      pkt_account(&stat_link_unknown, p);
+      pkt_free(p);
+    }
+}
+
+/*** PCAP INTERFACE ***/
+
+static void (*link_handler)(struct pkt *);
+static struct pkt_stats stat_pcap_incomplete;
+
+static int link_setup_handler(int dlt)
+{
+  switch (dlt)
+    {
+    case DLT_EN10MB:   link_handler = link_eth_got_packet; return 1;
+    default:           return 0;
+    }
+}
+
+static void got_pcap_packet(u_char *userdata UNUSED, const struct pcap_pkthdr *hdr, const u_char *pkt)
+{
+  if (hdr->caplen != hdr->len)
+    {
+      stat_pcap_incomplete.packets++;
+      stat_pcap_incomplete.bytes += hdr->len - hdr->caplen;
+      return;
+    }
+  struct pkt *p = pkt_new(0, hdr->len);
+  memcpy(pkt_append(p, hdr->len), pkt, hdr->len);
+  link_handler(p);
+}
+
+int main(int argc, char **argv)
+{
+  char errbuf[PCAP_ERRBUF_SIZE];
+  pcap_t *pcap;
+  int dlt;
+
+  if (argc != 2)
+    die("Usage: netgrind <capture-file>");
+
+  if (!(pcap = pcap_open_offline(argv[1], errbuf)))
+    die("Unable to open %s: %s", argv[1], errbuf);
+  dlt = pcap_datalink(pcap);
+  if (!link_setup_handler(dlt))
+    die("Don't know how to handle data link type %d", dlt);
+  if (pcap_loop(pcap, -1, got_pcap_packet, NULL) < 0)
+    die("Capture failed: %s", pcap_geterr(pcap));
+#if 0
+  struct pcap_stat stats;
+  if (pcap_stats(pcap, &stats))
+    die("pcap_stats: %s", pcap_geterr(pcap));
+  printf("libpcap stats: %d packets received, %d dropped\n", stats.ps_recv, stats.ps_drop);
+#endif
+  printf("Pcap: %Ld(%Ld) incomplete\n",
+        stat_pcap_incomplete.packets, stat_pcap_incomplete.bytes);
+  printf("Link: %Ld(%Ld) in, %Ld(%Ld) dwarves, %Ld(%Ld) strangers, %Ld(%Ld) ARPs\n",
+        stat_link_in.packets, stat_link_in.bytes,
+        stat_link_dwarf.packets, stat_link_dwarf.bytes,
+        stat_link_unknown.packets, stat_link_unknown.bytes,
+        stat_link_arp.packets, stat_link_arp.bytes);
+  printf("IP: %Ld(%Ld) in, %Ld(%Ld) invalid, %Ld(%Ld) boring, %Ld(%Ld) fragmented\n",
+        stat_ip_in.packets, stat_ip_in.bytes,
+        stat_ip_invalid.packets, stat_ip_invalid.bytes,
+        stat_ip_uninteresting.packets, stat_ip_uninteresting.bytes,
+        stat_ip_fragmented.packets, stat_ip_fragmented.bytes);
+  printf("TCP: %Ld(%Ld) in, %Ld(%Ld) invalid\n",
+        stat_tcp_in.packets, stat_tcp_in.bytes,
+        stat_tcp_invalid.packets, stat_tcp_invalid.bytes);
+  pcap_close(pcap);
+  return 0;
+}
diff --git a/netgrind/netgrind.h b/netgrind/netgrind.h
new file mode 100644 (file)
index 0000000..60512ca
--- /dev/null
@@ -0,0 +1,8 @@
+/*
+ *     Netgrind -- The Network Traffic Analyser
+ *
+ *     (c) 2003 Martin Mares <mj@ucw.cz>
+ *
+ *     This software may be freely distributed and used according to the terms
+ *     of the GNU General Public License.
+ */
diff --git a/netgrind/pkt.c b/netgrind/pkt.c
new file mode 100644 (file)
index 0000000..ad0c21c
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ *     Netgrind -- Packet Buffers
+ *
+ *     (c) 2003 Martin Mares <mj@ucw.cz>
+ *
+ *     This software may be freely distributed and used according to the terms
+ *     of the GNU General Public License.
+ */
+
+#include "lib/lib.h"
+#include "netgrind/pkt.h"
+
+#include <stdlib.h>
+
+struct pkt *pkt_new(uns preroom, uns postroom)
+{
+  uns len = preroom + postroom;
+  struct pkt *p = xmalloc(sizeof(struct pkt) + len);
+  p->stop = p->data = p->buf + preroom;
+  p->ebuf = p->buf + len;
+  return p;
+}
+
+void pkt_free(struct pkt *p)
+{
+  xfree(p);
+}
diff --git a/netgrind/pkt.h b/netgrind/pkt.h
new file mode 100644 (file)
index 0000000..c1e4a99
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ *     Netgrind -- Packet Buffers
+ *
+ *     (c) 2003 Martin Mares <mj@ucw.cz>
+ *
+ *     This software may be freely distributed and used according to the terms
+ *     of the GNU General Public License.
+ */
+
+#include "lib/lists.h"
+
+struct pkt {
+  struct node n;
+  u64 timestamp;
+  byte *data, *stop, *ebuf;
+  byte buf[0];
+};
+
+static inline uns pkt_len(struct pkt *p)
+{
+  return p->stop - p->data;
+}
+
+static inline void pkt_push(struct pkt *p, uns len)
+{
+  p->data -= len;
+  ASSERT(p->data >= p->buf);
+}
+
+static inline void *pkt_pop(struct pkt *p, uns len)
+{
+  byte *d = p->data;
+  if (d + len > p->stop)
+    return NULL;
+  p->data += len;
+  return d;
+}
+
+static inline void *pkt_peek(struct pkt *p, uns len)
+{
+  byte *d = p->data;
+  if (d + len > p->stop)
+    return NULL;
+  return d;
+}
+
+static inline byte *pkt_append(struct pkt *p, uns len)
+{
+  byte *d = p->stop;
+  p->stop = d + len;
+  ASSERT(p->stop <= p->ebuf);
+  return d;
+}
+
+static inline void pkt_unappend(struct pkt *p, uns len)
+{
+  p->stop -= len;
+  ASSERT(p->stop >= p->data);
+}
+
+struct pkt *pkt_new(uns preroom, uns postroom);
+void pkt_free(struct pkt *pkt);
+
+struct pkt_stats {
+  u64 packets;
+  u64 bytes;
+};
+
+static inline void pkt_account(struct pkt_stats *stats, struct pkt *pkt)
+{
+  stats->packets++;
+  stats->bytes += pkt_len(pkt);
+}