wifimon example program

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index d42b495..99ba2af 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -36,6 +36,7 @@
 hostprogs-y += xdp_tx_iptunnel
 hostprogs-y += test_map_in_map
 hostprogs-y += per_socket_stats_example
+hostprogs-y += wifimon
 
 # Libbpf dependencies
 LIBBPF := ../../tools/lib/bpf/bpf.o
@@ -76,6 +77,7 @@
 xdp_tx_iptunnel-objs := bpf_load.o $(LIBBPF) xdp_tx_iptunnel_user.o
 test_map_in_map-objs := bpf_load.o $(LIBBPF) test_map_in_map_user.o
 per_socket_stats_example-objs := $(LIBBPF) cookie_uid_helper_example.o
+wifimon-objs := bpf_load.o $(LIBBPF) wifimon_user.o
 
 # Tell kbuild to always build the programs
 always := $(hostprogs-y)
@@ -111,7 +113,9 @@
 always += xdp_tx_iptunnel_kern.o
 always += test_map_in_map_kern.o
 always += cookie_uid_helper_example.o
+always += wifimon_kern.o
 
+HOSTCFLAGS += -I$(srctree)/include/uapi/ -D__EXPORTED_HEADERS__
 HOSTCFLAGS += -I$(objtree)/usr/include
 HOSTCFLAGS += -I$(srctree)/tools/lib/
 HOSTCFLAGS += -I$(srctree)/tools/testing/selftests/bpf/
@@ -146,6 +150,7 @@
 HOSTLOADLIBES_lwt_len_hist += -l elf
 HOSTLOADLIBES_xdp_tx_iptunnel += -lelf
 HOSTLOADLIBES_test_map_in_map += -lelf
+HOSTLOADLIBES_wifimon += -lelf
 
 # Allows pointing LLC/CLANG to a LLVM backend with bpf support, redefine on cmdline:
 #  make samples/bpf/ LLC=~/git/llvm/build/bin/llc CLANG=~/git/llvm/build/bin/clang
diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c
index dcdce12..d692044 100644
--- a/samples/bpf/bpf_load.c
+++ b/samples/bpf/bpf_load.c
@@ -68,6 +68,7 @@
 	bool is_perf_event = strncmp(event, "perf_event", 10) == 0;
 	bool is_cgroup_skb = strncmp(event, "cgroup/skb", 10) == 0;
 	bool is_cgroup_sk = strncmp(event, "cgroup/sock", 11) == 0;
+	bool is_wifimon_sk = strncmp(event, "wifimon", 7) == 0;
 	size_t insns_cnt = size / sizeof(struct bpf_insn);
 	enum bpf_prog_type prog_type;
 	char buf[256];
@@ -93,6 +94,8 @@
 		prog_type = BPF_PROG_TYPE_CGROUP_SKB;
 	} else if (is_cgroup_sk) {
 		prog_type = BPF_PROG_TYPE_CGROUP_SOCK;
+	} else if (is_wifimon_sk) {
+		prog_type = BPF_PROG_TYPE_WIFIMON;
 	} else {
 		printf("Unknown event '%s'\n", event);
 		return -1;
@@ -107,7 +110,7 @@
 
 	prog_fd[prog_cnt++] = fd;
 
-	if (is_xdp || is_perf_event || is_cgroup_skb || is_cgroup_sk)
+	if (is_xdp || is_perf_event || is_cgroup_skb || is_cgroup_sk || is_wifimon_sk)
 		return 0;
 
 	if (is_socket) {
@@ -310,7 +313,7 @@
 		return 1;
 
 	/* clear all kprobes */
-	i = system("echo \"\" > /sys/kernel/debug/tracing/kprobe_events");
+//	i = system("echo \"\" > /sys/kernel/debug/tracing/kprobe_events");
 
 	/* scan over all elf sections to get license and map info */
 	for (i = 1; i < ehdr.e_shnum; i++) {
@@ -375,14 +378,14 @@
 			    memcmp(shname_prog, "xdp", 3) == 0 ||
 			    memcmp(shname_prog, "perf_event", 10) == 0 ||
 			    memcmp(shname_prog, "socket", 6) == 0 ||
-			    memcmp(shname_prog, "cgroup/", 7) == 0)
+			    memcmp(shname_prog, "cgroup/", 7) == 0 ||
+			    memcmp(shname_prog, "wifimon", 7) == 0)
 				load_and_attach(shname_prog, insns, data_prog->d_size);
 		}
 	}
 
 	/* load programs that don't use maps */
 	for (i = 1; i < ehdr.e_shnum; i++) {
-
 		if (processed_sec[i])
 			continue;
 
@@ -395,7 +398,8 @@
 		    memcmp(shname, "xdp", 3) == 0 ||
 		    memcmp(shname, "perf_event", 10) == 0 ||
 		    memcmp(shname, "socket", 6) == 0 ||
-		    memcmp(shname, "cgroup/", 7) == 0)
+		    memcmp(shname, "cgroup/", 7) == 0 ||
+		    memcmp(shname, "wifimon", 7) == 0)
 			load_and_attach(shname, data->d_buf, data->d_size);
 	}
 
diff --git a/samples/bpf/wifimon_kern.c b/samples/bpf/wifimon_kern.c
new file mode 100644
index 0000000..9f16b83
--- /dev/null
+++ b/samples/bpf/wifimon_kern.c
@@ -0,0 +1,31 @@
+/* Copyright (c) 2017 Intel Deutschland GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ */
+#define KBUILD_MODNAME "wifimon_test"
+#include <uapi/linux/bpf.h>
+#include <linux/ieee80211.h>
+#include "bpf_helpers.h"
+
+SEC("wifimon_no_data")
+int wifimon_no_data(struct __sk_buff *skb)
+{
+	u8 fc1;
+	int ret = bpf_skb_load_bytes(skb, 0, &fc1, sizeof(fc1));
+
+	/* reject data frames */
+	if ((fc1 & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)
+		return 0;
+
+	/* reject beacon frames */
+	if ((fc1 & (IEEE80211_FCTL_FTYPE | IEEE80211_FCTL_STYPE)) ==
+			(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON))
+		return 0;
+
+	/* accept */
+	return 1;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/samples/bpf/wifimon_user.c b/samples/bpf/wifimon_user.c
new file mode 100644
index 0000000..557bc6b
--- /dev/null
+++ b/samples/bpf/wifimon_user.c
@@ -0,0 +1,55 @@
+/* Copyright (c) 2017 Intel Deutschland GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <linux/bpf.h>
+#include "bpf_load.h"
+
+int main(int argc, char **argv)
+{
+	char filename[256];
+	char fdstr[100];
+	char *args[] = {
+		"iw",
+		"dev",
+		argv[1],
+		"set",
+		"filter",
+		fdstr,
+		NULL,
+	};
+
+	snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
+
+	if (argc != 2) {
+		printf("usage: %s <ifname>\n", argv[0]);
+		return 1;
+	}
+
+	if (load_bpf_file(filename)) {
+		printf("%s", bpf_log_buf);
+		return 1;
+	}
+
+	if (!prog_cnt) {
+		printf("load_bpf_file: nothing loaded\n");
+		return 1;
+	}
+
+	snprintf(fdstr, sizeof(fdstr), "%d", prog_fd[0]);
+
+	if (fcntl(prog_fd[0], F_SETFD, 0) < 0) {
+		printf("fcntl error: %d: %s\n", errno, strerror(errno));
+		return 1;
+	}
+
+	return execve("/root/iw", args, NULL);
+}