diff options
Diffstat (limited to 'tests/osmo-pcap-test/pcap.c')
-rw-r--r-- | tests/osmo-pcap-test/pcap.c | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/tests/osmo-pcap-test/pcap.c b/tests/osmo-pcap-test/pcap.c new file mode 100644 index 0000000..dbc0204 --- /dev/null +++ b/tests/osmo-pcap-test/pcap.c @@ -0,0 +1,176 @@ +/* + * (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 version. + */ + +#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 "osmo_pcap.h" + +#include <osmocom/core/msgb.h> +#include <osmocom/core/timer.h> +#include <osmocom/core/select.h> + +#include <osmocom/netif/osmux.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; +} + +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; +} + +void osmo_pcap_test_close(pcap_t *handle) +{ + pcap_close(handle); +} + +int +osmo_pcap_test_run(struct osmo_pcap *p, 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(p->h, &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(&p->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, &p->last, &res); + printf("next packet comes in %lu.%.6lu seconds\n", + res.tv_sec, res.tv_usec); + osmo_timer_schedule(&p->timer, res.tv_sec, res.tv_usec); + + memcpy(&p->last, &pcaph.ts, sizeof(struct timeval)); + + return 0; +} + +void osmo_pcap_stats_printf(void) +{ + 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); +} + +void osmo_pcap_init(void) +{ + /* Initialization of supported layer 3 and 4 protocols here. */ + l2l3_ipv4_init(); + l4_tcp_init(); + l4_udp_init(); +} |