aboutsummaryrefslogtreecommitdiffstats
path: root/tests/osmo-pcap-test
diff options
context:
space:
mode:
Diffstat (limited to 'tests/osmo-pcap-test')
-rw-r--r--tests/osmo-pcap-test/.gitignore24
-rw-r--r--tests/osmo-pcap-test/Make_global.am6
-rw-r--r--tests/osmo-pcap-test/Makefile.am12
-rw-r--r--tests/osmo-pcap-test/configure.ac28
-rw-r--r--tests/osmo-pcap-test/l3_ipv4.c44
-rw-r--r--tests/osmo-pcap-test/l4_tcp.c38
-rw-r--r--tests/osmo-pcap-test/l4_udp.c38
-rw-r--r--tests/osmo-pcap-test/main.c215
-rw-r--r--tests/osmo-pcap-test/pcaps/rtp-nanobts-2-phones-amr-dtx.pcapbin0 -> 149092 bytes
-rw-r--r--tests/osmo-pcap-test/pcaps/rtp-nanobts-2-phones-amr.pcapbin0 -> 239416 bytes
-rw-r--r--tests/osmo-pcap-test/proto.c53
-rw-r--r--tests/osmo-pcap-test/proto.h40
12 files changed, 498 insertions, 0 deletions
diff --git a/tests/osmo-pcap-test/.gitignore b/tests/osmo-pcap-test/.gitignore
new file mode 100644
index 0000000..68f19b2
--- /dev/null
+++ b/tests/osmo-pcap-test/.gitignore
@@ -0,0 +1,24 @@
+Makefile
+Makefile.in
+.deps
+.libs
+*.o
+*.lo
+*.la
+aclocal.m4
+acinclude.m4
+aminclude.am
+m4/*.m4
+autom4te.cache
+config.h*
+config.sub
+config.log
+config.status
+config.guess
+configure
+depcomp
+missing
+ltmain.sh
+install-sh
+stamp-h1
+libtool
diff --git a/tests/osmo-pcap-test/Make_global.am b/tests/osmo-pcap-test/Make_global.am
new file mode 100644
index 0000000..b44fdfe
--- /dev/null
+++ b/tests/osmo-pcap-test/Make_global.am
@@ -0,0 +1,6 @@
+AM_CPPFLAGS = -I$(top_srcdir)/include -I../../../include
+
+AM_CFLAGS = -std=gnu99 -W -Wall \
+ -Wmissing-prototypes -Wwrite-strings -Wcast-qual -Wfloat-equal -Wshadow -Wpointer-arith -Wbad-function-cast -Wsign-compare -Waggregate-return -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wstrict-prototypes -Wundef \
+ -Wno-unused-parameter \
+ ${LIBOSMOCORE_CFLAGS}
diff --git a/tests/osmo-pcap-test/Makefile.am b/tests/osmo-pcap-test/Makefile.am
new file mode 100644
index 0000000..6420faf
--- /dev/null
+++ b/tests/osmo-pcap-test/Makefile.am
@@ -0,0 +1,12 @@
+include $(top_srcdir)/Make_global.am
+
+check_PROGRAMS = osmo-pcap-test
+
+osmo_pcap_test_SOURCES = proto.c \
+ l3_ipv4.c \
+ l4_tcp.c \
+ l4_udp.c \
+ main.c
+
+osmo_pcap_test_LDFLAGS = -lpcap \
+ -losmocore
diff --git a/tests/osmo-pcap-test/configure.ac b/tests/osmo-pcap-test/configure.ac
new file mode 100644
index 0000000..0d496db
--- /dev/null
+++ b/tests/osmo-pcap-test/configure.ac
@@ -0,0 +1,28 @@
+AC_INIT(osmo-pcap-test, 0.0.1, pablo@gnumonks.org)
+AC_CONFIG_AUX_DIR([build-aux])
+
+AC_CANONICAL_HOST
+AC_CONFIG_MACRO_DIR([m4])
+AM_INIT_AUTOMAKE([-Wall foreign subdir-objects
+ tar-pax no-dist-gzip dist-bzip2 1.6])
+
+dnl kernel style compile messages
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.3.0)
+
+AC_PROG_CC
+AC_DISABLE_STATIC
+AM_PROG_LIBTOOL
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AM_PROG_LEX
+AC_PROG_YACC
+
+case "$host" in
+*-*-linux*) ;;
+*) AC_MSG_ERROR([Linux only, dude!]);;
+esac
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
diff --git a/tests/osmo-pcap-test/l3_ipv4.c b/tests/osmo-pcap-test/l3_ipv4.c
new file mode 100644
index 0000000..83e3479
--- /dev/null
+++ b/tests/osmo-pcap-test/l3_ipv4.c
@@ -0,0 +1,44 @@
+/*
+ * (C) 2012 by Pablo Neira Ayuso <pablo@gnumonks.org>
+ * (C) 2012 by On Waves ehf <http://www.on-waves.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later vers
+ */
+
+#include <stdlib.h>
+#include <netinet/ip.h>
+#include <linux/if_ether.h>
+
+#include "proto.h"
+
+#define PRINT_CMP(...)
+
+static int l3_ipv4_pkt_l4proto_num(const uint8_t *pkt)
+{
+ const struct iphdr *iph = (const struct iphdr *)pkt;
+
+ return iph->protocol;
+}
+
+static int l3_ipv4_pkt_l3hdr_len(const uint8_t *pkt)
+{
+ const struct iphdr *iph = (const struct iphdr *)pkt;
+
+ return iph->ihl << 2;
+}
+
+static struct osmo_pcap_proto_l2l3 ipv4 = {
+ .l2protonum = ETH_P_IP,
+ .l3protonum = AF_INET,
+ .l2hdr_len = ETH_HLEN,
+ .l3pkt_hdr_len = l3_ipv4_pkt_l3hdr_len,
+ .l4pkt_proto = l3_ipv4_pkt_l4proto_num,
+};
+
+void l2l3_ipv4_init(void)
+{
+ osmo_pcap_proto_l2l3_register(&ipv4);
+}
diff --git a/tests/osmo-pcap-test/l4_tcp.c b/tests/osmo-pcap-test/l4_tcp.c
new file mode 100644
index 0000000..1e024b5
--- /dev/null
+++ b/tests/osmo-pcap-test/l4_tcp.c
@@ -0,0 +1,38 @@
+/*
+ * (C) 2012 by Pablo Neira Ayuso <pablo@gnumonks.org>
+ * (C) 2012 by On Waves ehf <http://www.on-waves.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later vers
+ */
+
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+
+#include "proto.h"
+
+static int l4_tcp_pkt_hdr_len(const uint8_t *pkt)
+{
+ const struct tcphdr *tcph = (const struct tcphdr *)pkt;
+
+ return tcph->doff << 2;
+}
+
+static int l4_tcp_pkt_no_data(const uint8_t *pkt)
+{
+ const struct tcphdr *tcph = (const struct tcphdr *)pkt;
+ return tcph->syn || tcph->fin || tcph->rst || !tcph->psh;
+}
+
+static struct osmo_pcap_proto_l4 tcp = {
+ .l4protonum = IPPROTO_TCP,
+ .l4pkt_hdr_len = l4_tcp_pkt_hdr_len,
+ .l4pkt_no_data = l4_tcp_pkt_no_data,
+};
+
+void l4_tcp_init(void)
+{
+ osmo_pcap_proto_l4_register(&tcp);
+}
diff --git a/tests/osmo-pcap-test/l4_udp.c b/tests/osmo-pcap-test/l4_udp.c
new file mode 100644
index 0000000..0a4266e
--- /dev/null
+++ b/tests/osmo-pcap-test/l4_udp.c
@@ -0,0 +1,38 @@
+/*
+ * (C) 2012 by Pablo Neira Ayuso <pablo@gnumonks.org>
+ * (C) 2012 by On Waves ehf <http://www.on-waves.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later vers
+ */
+
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+
+#include "proto.h"
+
+static int l4_udp_pkt_hdr_len(const uint8_t *pkt)
+{
+ const struct udphdr *udph = (const struct udphdr *)pkt;
+
+ return ntohs(udph->len);
+}
+
+static int l4_udp_pkt_no_data(const uint8_t *pkt)
+{
+ /* UDP has no control packets. */
+ return 0;
+}
+
+static struct osmo_pcap_proto_l4 udp = {
+ .l4protonum = IPPROTO_UDP,
+ .l4pkt_hdr_len = l4_udp_pkt_hdr_len,
+ .l4pkt_no_data = l4_udp_pkt_no_data,
+};
+
+void l4_udp_init(void)
+{
+ osmo_pcap_proto_l4_register(&udp);
+}
diff --git a/tests/osmo-pcap-test/main.c b/tests/osmo-pcap-test/main.c
new file mode 100644
index 0000000..3a62d95
--- /dev/null
+++ b/tests/osmo-pcap-test/main.c
@@ -0,0 +1,215 @@
+/*
+ * (C) 2012 by Pablo Neira Ayuso <pablo@gnumonks.org>
+ * (C) 2012 by On Waves ehf <http://www.on-waves.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later vers
+ */
+
+#include <stdio.h>
+#include <pcap.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <unistd.h>
+
+#include <linux/if_ether.h>
+
+#include "proto.h"
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/core/select.h>
+
+struct osmo_pcap_test_stats {
+ uint32_t pkts;
+ uint32_t skip;
+ uint32_t processed;
+ uint32_t unsupported_l3;
+ uint32_t unsupported_l4;
+} osmo_pcap_test_stats;
+
+static int
+osmo_pcap_process_packet(const uint8_t *pkt, uint32_t pktlen,
+ struct osmo_pcap_proto_l2l3 *l3h,
+ struct osmo_pcap_proto_l4 *l4h,
+ int (*cb)(struct msgb *msgb))
+{
+ unsigned int l3hdr_len, skip_hdr_len;
+ struct msgb *msgb;
+ int ret;
+
+ /* skip layer 2, 3 and 4 headers */
+ l3hdr_len = l3h->l3pkt_hdr_len(pkt + ETH_HLEN);
+ skip_hdr_len = l3h->l2hdr_len + l3hdr_len +
+ l4h->l4pkt_hdr_len(pkt + ETH_HLEN + l3hdr_len);
+
+ /* This packet contains no data, skip it. */
+ if (l4h->l4pkt_no_data(pkt + l3hdr_len + ETH_HLEN)) {
+ osmo_pcap_test_stats.skip++;
+ return 0;
+ }
+
+ /* get application layer data. */
+ pkt += skip_hdr_len;
+ pktlen -= skip_hdr_len;
+
+ /* Create the fake network buffer. */
+ msgb = msgb_alloc(pktlen, "OSMO/PCAP test");
+ if (msgb == NULL) {
+ fprintf(stderr, "Not enough memory\n");
+ return -1;
+ }
+ memcpy(msgb->data, pkt, pktlen);
+ msgb_put(msgb, pktlen);
+
+ ret = cb(msgb);
+
+ msgb_free(msgb);
+
+ osmo_pcap_test_stats.processed++;
+
+ return ret;
+}
+
+static pcap_t *osmo_pcap_test_open(const char *pcapfile)
+{
+ pcap_t *handle;
+ char errbuf[PCAP_ERRBUF_SIZE];
+
+ handle = pcap_open_offline(pcapfile, errbuf);
+ if (handle == NULL) {
+ fprintf(stderr, "couldn't open pcap file %s: %s\n",
+ pcapfile, errbuf);
+ return NULL;
+ }
+
+ return handle;
+}
+
+static void osmo_pcap_test_close(pcap_t *handle)
+{
+ pcap_close(handle);
+}
+
+static struct osmo_pcap {
+ pcap_t *h;
+ struct osmo_timer_list timer;
+ struct timeval last;
+} osmo_pcap;
+
+static int
+osmo_pcap_test_run(pcap_t *handle, uint8_t pnum, int (*cb)(struct msgb *msgb))
+{
+ struct osmo_pcap_proto_l2l3 *l3h;
+ struct osmo_pcap_proto_l4 *l4h;
+ struct pcap_pkthdr pcaph;
+ const u_char *pkt;
+ struct timeval res;
+ uint8_t l4protonum;
+
+retry:
+ pkt = pcap_next(handle, &pcaph);
+ if (pkt == NULL)
+ return -1;
+
+ osmo_pcap_test_stats.pkts++;
+
+ l3h = osmo_pcap_proto_l2l3_find(pkt);
+ if (l3h == NULL) {
+ osmo_pcap_test_stats.unsupported_l3++;
+ goto retry;
+ }
+ l4protonum = l3h->l4pkt_proto(pkt + ETH_HLEN);
+
+ /* filter l4 protocols we are not interested in */
+ if (l4protonum != pnum) {
+ osmo_pcap_test_stats.skip++;
+ goto retry;
+ }
+
+ l4h = osmo_pcap_proto_l4_find(pkt, l4protonum);
+ if (l4h == NULL) {
+ osmo_pcap_test_stats.unsupported_l4++;
+ goto retry;
+ }
+
+ /* first packet that is going to be processed */
+ if (osmo_pcap_test_stats.processed == 0)
+ memcpy(&osmo_pcap.last, &pcaph.ts, sizeof(struct timeval));
+
+ /* retry with next packet if this has been skipped. */
+ if (osmo_pcap_process_packet(pkt, pcaph.caplen, l3h, l4h, cb) < 0)
+ goto retry;
+
+ /* calculate waiting time */
+ timersub(&pcaph.ts, &osmo_pcap.last, &res);
+ printf("waiting %lu.%.6lu seconds\n", res.tv_sec, res.tv_usec);
+ osmo_timer_schedule(&osmo_pcap.timer, res.tv_sec, res.tv_usec);
+
+ memcpy(&osmo_pcap.last, &pcaph.ts, sizeof(struct timeval));
+
+ return 0;
+}
+
+static int osmo_osmux_xfrm_encode(struct msgb *msgb)
+{
+ return 0;
+}
+
+static void osmo_pcap_pkt_timer_cb(void *data)
+{
+ if (osmo_pcap_test_run(osmo_pcap.h, IPPROTO_UDP,
+ osmo_osmux_xfrm_encode) < 0) {
+ printf("pkts=%d processed=%d skip=%d "
+ "unsupported_l3=%d unsupported_l4=%d\n",
+ osmo_pcap_test_stats.pkts,
+ osmo_pcap_test_stats.processed,
+ osmo_pcap_test_stats.skip,
+ osmo_pcap_test_stats.unsupported_l3,
+ osmo_pcap_test_stats.unsupported_l4);
+ printf("\e[1;34mDone.\e[0m\n");
+ osmo_pcap_test_close(osmo_pcap.h);
+ exit(EXIT_SUCCESS);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int ret;
+
+ if (argc != 2) {
+ fprintf(stderr, "Wrong usage:\n");
+ fprintf(stderr, "%s <pcap_file>\n", argv[0]);
+ fprintf(stderr, "example: %s file.pcap\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Initialization of supported layer 3 and 4 protocols here. */
+ l2l3_ipv4_init();
+ l4_tcp_init();
+ l4_udp_init();
+
+ printf("\e[1;34mStarting test...\e[0m\n");
+
+ osmo_pcap.h = osmo_pcap_test_open(argv[1]);
+ if (osmo_pcap.h == NULL)
+ exit(EXIT_FAILURE);
+
+ osmo_pcap.timer.cb = osmo_pcap_pkt_timer_cb;
+
+ /* first run */
+ osmo_pcap_pkt_timer_cb(NULL);
+
+ while(1) {
+ osmo_select_main(0);
+ }
+
+ return ret;
+}
diff --git a/tests/osmo-pcap-test/pcaps/rtp-nanobts-2-phones-amr-dtx.pcap b/tests/osmo-pcap-test/pcaps/rtp-nanobts-2-phones-amr-dtx.pcap
new file mode 100644
index 0000000..1b8a3e5
--- /dev/null
+++ b/tests/osmo-pcap-test/pcaps/rtp-nanobts-2-phones-amr-dtx.pcap
Binary files differ
diff --git a/tests/osmo-pcap-test/pcaps/rtp-nanobts-2-phones-amr.pcap b/tests/osmo-pcap-test/pcaps/rtp-nanobts-2-phones-amr.pcap
new file mode 100644
index 0000000..d2a9e45
--- /dev/null
+++ b/tests/osmo-pcap-test/pcaps/rtp-nanobts-2-phones-amr.pcap
Binary files differ
diff --git a/tests/osmo-pcap-test/proto.c b/tests/osmo-pcap-test/proto.c
new file mode 100644
index 0000000..f90f07c
--- /dev/null
+++ b/tests/osmo-pcap-test/proto.c
@@ -0,0 +1,53 @@
+/*
+ * (C) 2012 by Pablo Neira Ayuso <pablo@gnumonks.org>
+ * (C) 2012 by On Waves ehf <http://www.on-waves.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later vers
+ */
+
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <linux/if_ether.h>
+
+#include <osmocom/core/linuxlist.h>
+#include "proto.h"
+
+static LLIST_HEAD(l2l3_proto_list);
+static LLIST_HEAD(l4_proto_list);
+
+struct osmo_pcap_proto_l2l3 *osmo_pcap_proto_l2l3_find(const uint8_t *pkt)
+{
+ const struct ethhdr *eh = (const struct ethhdr *)pkt;
+ struct osmo_pcap_proto_l2l3 *cur;
+
+ llist_for_each_entry(cur, &l2l3_proto_list, head) {
+ if (ntohs(cur->l2protonum) == eh->h_proto)
+ return cur;
+ }
+ return NULL;
+}
+
+void osmo_pcap_proto_l2l3_register(struct osmo_pcap_proto_l2l3 *h)
+{
+ llist_add(&h->head, &l2l3_proto_list);
+}
+
+struct osmo_pcap_proto_l4 *
+osmo_pcap_proto_l4_find(const uint8_t *pkt, unsigned int l4protocol)
+{
+ struct osmo_pcap_proto_l4 *cur;
+
+ llist_for_each_entry(cur, &l4_proto_list, head) {
+ if (cur->l4protonum == l4protocol)
+ return cur;
+ }
+ return NULL;
+}
+
+void osmo_pcap_proto_l4_register(struct osmo_pcap_proto_l4 *h)
+{
+ llist_add(&h->head, &l4_proto_list);
+}
diff --git a/tests/osmo-pcap-test/proto.h b/tests/osmo-pcap-test/proto.h
new file mode 100644
index 0000000..8cb41ed
--- /dev/null
+++ b/tests/osmo-pcap-test/proto.h
@@ -0,0 +1,40 @@
+#ifndef _OSMO_PCAP_PROTO_H_
+#define _OSMO_PCAP_PROTO_H_
+
+#include <stdint.h>
+
+#include <osmocom/core/linuxlist.h>
+
+struct osmo_pcap_proto_l4 {
+ struct llist_head head;
+
+ unsigned int l4protonum;
+
+ int (*l4pkt_hdr_len)(const uint8_t *pkt);
+ int (*l4pkt_no_data)(const uint8_t *pkt);
+};
+
+struct osmo_pcap_proto_l2l3 {
+ struct llist_head head;
+
+ unsigned int l2protonum;
+ unsigned int l2hdr_len;
+
+ unsigned int l3protonum;
+
+ int (*l3pkt_hdr_len)(const uint8_t *pkt);
+ int (*l4pkt_proto)(const uint8_t *pkt);
+};
+
+struct osmo_pcap_proto_l2l3 *osmo_pcap_proto_l2l3_find(const uint8_t *pkt);
+void osmo_pcap_proto_l2l3_register(struct osmo_pcap_proto_l2l3 *h);
+
+struct osmo_pcap_proto_l4 *osmo_pcap_proto_l4_find(const uint8_t *pkt, unsigned int l4protonum);
+void osmo_pcap_proto_l4_register(struct osmo_pcap_proto_l4 *h);
+
+/* Initialization of supported protocols here. */
+void l2l3_ipv4_init(void);
+void l4_tcp_init(void);
+void l4_udp_init(void);
+
+#endif