summaryrefslogtreecommitdiff
path: root/package/wprobe/src/filter
diff options
context:
space:
mode:
Diffstat (limited to 'package/wprobe/src/filter')
-rw-r--r--package/wprobe/src/filter/README.txt1
-rwxr-xr-xpackage/wprobe/src/filter/gen_filter.pl63
-rw-r--r--package/wprobe/src/filter/pfc.c58
3 files changed, 122 insertions, 0 deletions
diff --git a/package/wprobe/src/filter/README.txt b/package/wprobe/src/filter/README.txt
new file mode 100644
index 0000000000..6fa265e4f8
--- /dev/null
+++ b/package/wprobe/src/filter/README.txt
@@ -0,0 +1 @@
+To compile pfc you need at least libpcap version 1.0, as it requires proper radiotap header support
diff --git a/package/wprobe/src/filter/gen_filter.pl b/package/wprobe/src/filter/gen_filter.pl
new file mode 100755
index 0000000000..f03f477a49
--- /dev/null
+++ b/package/wprobe/src/filter/gen_filter.pl
@@ -0,0 +1,63 @@
+#!/usr/bin/perl
+use strict;
+
+# helpers for custom packet format
+# bytes 0-7 are used by a dummy radiotap header
+my $WLAN_LEN = "radio[8:2]";
+my $SNR = "radio[10:1]";
+my $DEFAULT = undef;
+
+my $MAGIC = "WPFF";
+my $VERSION = 1; # filter binary format version
+my $HDRLEN = 3; # assumed storage space for custom fields
+
+my $output = "filter.bin";
+my $config = {
+ "packetsize" => [
+ [ "small", "$WLAN_LEN < 250" ],
+ [ "medium", "$WLAN_LEN < 800" ],
+ [ "big", $DEFAULT ],
+ ],
+ "snr" => [
+ [ "low", "$SNR < 10" ],
+ [ "medium", "$SNR < 20" ],
+ [ "high", $DEFAULT ],
+ ],
+ "type" => [
+ [ "beacon", "type mgt subtype beacon" ],
+ [ "data", "type data subtype data" ],
+ [ "qosdata", "type data subtype qos-data" ],
+ [ "other", "$DEFAULT" ]
+ ]
+};
+
+sub escape_q($) {
+ my $str = shift;
+ $str =~ s/'/'\\''/g;
+ return $str;
+}
+
+my $GROUPS = scalar(keys %$config);
+open OUTPUT, ">$output" or die "Cannot open output file: $!\n";
+print OUTPUT pack("a4CCn", $MAGIC, $VERSION, $HDRLEN, $GROUPS);
+
+foreach my $groupname (keys %$config) {
+ my $default = 0;
+ my $group = $config->{$groupname};
+ print OUTPUT pack("a32N", $groupname, scalar(@$group));
+ foreach my $filter (@$group) {
+ if (!$filter->[1]) {
+ $default > 0 and print "Cannot add more than one default filter per group: $groupname -> ".$filter->[0]."\n";
+ print OUTPUT pack("a32N", $filter->[0], 0);
+ $default++;
+ } else {
+ open FILTER, "./pfc '".escape_q($filter->[0])."' '".escape_q($filter->[1])."' |"
+ or die "Failed to run filter command for '".$filter->[0]."': $!\n";
+ while (<FILTER>) {
+ print OUTPUT $_;
+ }
+ close FILTER;
+ $? and die "Filter '".$filter->[0]."' did not compile.\n";
+ }
+ }
+}
diff --git a/package/wprobe/src/filter/pfc.c b/package/wprobe/src/filter/pfc.c
new file mode 100644
index 0000000000..76fb1412aa
--- /dev/null
+++ b/package/wprobe/src/filter/pfc.c
@@ -0,0 +1,58 @@
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <pcap.h>
+#include <pcap-bpf.h>
+
+struct wprobe_filter_hdr {
+ char name[32];
+ uint32_t len;
+} hdr;
+
+int main (int argc, char ** argv)
+{
+ struct bpf_program filter;
+ pcap_t *pc;
+ int i;
+
+ if (argc != 3)
+ {
+ fprintf(stderr, "Usage: %s <name> <expression>\n", argv[0]);
+ return 1;
+ }
+
+ pc = pcap_open_dead(DLT_IEEE802_11_RADIO, 256);
+ if (pcap_compile(pc, &filter, argv[2], 1, 0) != 0)
+ {
+ pcap_perror(pc, argv[0]);
+ exit(1);
+ }
+
+ /* fix up for linux */
+ for (i = 0; i < filter.bf_len; i++) {
+ struct bpf_insn *bi = &filter.bf_insns[i];
+ switch(BPF_CLASS(bi->code)) {
+ case BPF_RET:
+ if (BPF_MODE(bi->code) == BPF_K) {
+ if (bi->k != 0)
+ bi->k = 65535;
+ }
+ break;
+ }
+ bi->code = ntohs(bi->code);
+ bi->k = ntohl(bi->k);
+ }
+
+ memset(&hdr, 0, sizeof(hdr));
+ strncpy(hdr.name, argv[1], sizeof(hdr.name));
+ hdr.len = htonl(filter.bf_len);
+ fwrite(&hdr, sizeof(hdr), 1, stdout);
+ fwrite(filter.bf_insns, 8, filter.bf_len, stdout);
+ fflush(stdout);
+
+ return 0;
+}