summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorreyk <reyk@openbsd.org>2006-06-27 18:14:59 +0000
committerreyk <reyk@openbsd.org>2006-06-27 18:14:59 +0000
commit9a571ad92f0369e28994ebefe4761c6127d9efb3 (patch)
tree3aa0381dfeb3beb6965616b0066dfd3ed21714e0
parentdon't set BGE_DEBUG by default, reduces the bloat a bit. noticed by deraadt. (diff)
downloadwireguard-openbsd-9a571ad92f0369e28994ebefe4761c6127d9efb3.tar.xz
wireguard-openbsd-9a571ad92f0369e28994ebefe4761c6127d9efb3.zip
add new event rules to match optional elements of radiotap headers:
signal percentage, transmit rate and channel frequency. ok and hints by jsg@ jmc@
-rw-r--r--usr.sbin/hostapd/handle.c127
-rw-r--r--usr.sbin/hostapd/hostapd.conf.556
-rw-r--r--usr.sbin/hostapd/hostapd.h31
-rw-r--r--usr.sbin/hostapd/parse.y160
4 files changed, 364 insertions, 10 deletions
diff --git a/usr.sbin/hostapd/handle.c b/usr.sbin/hostapd/handle.c
index bbe169a0a1f..58c3477b58a 100644
--- a/usr.sbin/hostapd/handle.c
+++ b/usr.sbin/hostapd/handle.c
@@ -1,7 +1,7 @@
-/* $OpenBSD: handle.c,v 1.9 2006/06/01 22:09:09 reyk Exp $ */
+/* $OpenBSD: handle.c,v 1.10 2006/06/27 18:14:59 reyk Exp $ */
/*
- * Copyright (c) 2005 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2005, 2006 Reyk Floeter <reyk@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -33,6 +33,9 @@
#include <netinet/if_ether.h>
#include <arpa/inet.h>
+#include <net80211/ieee80211.h>
+#include <net80211/ieee80211_radiotap.h>
+
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
@@ -49,6 +52,9 @@ void hostapd_handle_addr(const u_int32_t, u_int32_t *, u_int8_t *,
u_int8_t *, struct hostapd_table *);
void hostapd_handle_ref(u_int, u_int, u_int8_t *, u_int8_t *, u_int8_t *,
u_int8_t *);
+int hostapd_handle_radiotap(struct hostapd_radiotap *, u_int8_t *,
+ const u_int);
+int hostapd_cmp(enum hostapd_op, int, int);
int
hostapd_handle_input(struct hostapd_apme *apme, u_int8_t *buf, u_int len)
@@ -103,12 +109,14 @@ int
hostapd_handle_frame(struct hostapd_apme *apme, struct hostapd_frame *frame,
u_int8_t *buf, const u_int len)
{
+ struct hostapd_config *cfg = (struct hostapd_config *)apme->a_cfg;
struct ieee80211_frame *wh;
struct hostapd_ieee80211_frame *mh;
+ struct hostapd_radiotap rtap;
u_int8_t *wfrom, *wto, *wbssid;
struct timeval t_now;
u_int32_t flags;
- int offset, min_rate = 0;
+ int offset, min_rate = 0, val;
if ((offset = hostapd_apme_offset(apme, buf, len)) < 0)
return (0);
@@ -203,6 +211,35 @@ hostapd_handle_frame(struct hostapd_apme *apme, struct hostapd_frame *frame,
hostapd_handle_addr(HOSTAPD_FRAME_F_BSSID_M, &flags, wbssid,
mh->i_bssid, frame->f_bssid);
+ /* parse the optional radiotap header if required */
+ if (frame->f_radiotap) {
+ if (hostapd_handle_radiotap(&rtap, buf, len) != 0)
+ return (0);
+ else if ((rtap.r_present & frame->f_radiotap) !=
+ frame->f_radiotap) {
+ cfg->c_stats.cn_rtap_miss++;
+ return (0);
+ }
+ if (flags & HOSTAPD_FRAME_F_RSSI && rtap.r_max_rssi) {
+ val = ((float)rtap.r_rssi / rtap.r_max_rssi) * 100;
+ if (hostapd_cmp(frame->f_rssi_op,
+ val, frame->f_rssi))
+ flags &= ~HOSTAPD_FRAME_F_RSSI;
+ }
+ if (flags & HOSTAPD_FRAME_F_RATE) {
+ val = rtap.r_txrate;
+ if (hostapd_cmp(frame->f_txrate_op,
+ val, frame->f_txrate))
+ flags &= ~HOSTAPD_FRAME_F_RATE;
+ }
+ if (flags & HOSTAPD_FRAME_F_CHANNEL) {
+ val = rtap.r_chan;
+ if (hostapd_cmp(frame->f_chan_op,
+ val, frame->f_chan))
+ flags &= ~HOSTAPD_FRAME_F_CHANNEL;
+ }
+ }
+
/* Handle if frame matches */
if ((flags & HOSTAPD_FRAME_F_M) != 0)
return (0);
@@ -347,3 +384,87 @@ hostapd_handle_action(struct hostapd_apme *apme, struct hostapd_frame *frame,
return (ret);
}
+
+int
+hostapd_handle_radiotap(struct hostapd_radiotap *rtap,
+ u_int8_t *buf, const u_int len)
+{
+ struct ieee80211_radiotap_header *rh =
+ (struct ieee80211_radiotap_header*)buf;
+ u_int8_t *t, *ptr = NULL;
+ u_int rh_len;
+ const u_int8_t *snapend = buf + len;
+
+ TCHECK(*rh);
+
+ rh_len = letoh16(rh->it_len);
+ if (rh->it_version != 0)
+ return (EINVAL);
+ if (len <= rh_len)
+ goto trunc;
+
+ bzero(rtap, sizeof(struct hostapd_radiotap));
+
+ t = (u_int8_t*)buf + sizeof(struct ieee80211_radiotap_header);
+ if ((rtap->r_present = letoh32(rh->it_present)) == 0)
+ return (0);
+
+#define RADIOTAP(_x, _len) \
+ if (rtap->r_present & HOSTAPD_RADIOTAP_F(_x)) { \
+ TCHECK2(*t, _len); \
+ ptr = t; \
+ t += _len; \
+ } else \
+ ptr = NULL;
+
+ /* radiotap doesn't use TLV header fields, ugh */
+ RADIOTAP(TSFT, 8);
+ RADIOTAP(FLAGS, 1);
+
+ RADIOTAP(RATE, 1);
+ if (ptr != NULL) {
+ rtap->r_txrate = *(u_int8_t *)ptr;
+ }
+
+ RADIOTAP(CHANNEL, 4);
+ if (ptr != NULL) {
+ rtap->r_chan = letoh16(*(u_int16_t*)ptr);
+ rtap->r_chan_flags = letoh16(*(u_int16_t*)ptr + 1);
+ }
+
+ RADIOTAP(FHSS, 2);
+ RADIOTAP(DBM_ANTSIGNAL, 1);
+ RADIOTAP(DBM_ANTNOISE, 1);
+ RADIOTAP(LOCK_QUALITY, 2);
+ RADIOTAP(TX_ATTENUATION, 2);
+ RADIOTAP(DB_TX_ATTENUATION, 2);
+ RADIOTAP(DBM_TX_POWER, 1);
+ RADIOTAP(ANTENNA, 1);
+ RADIOTAP(DB_ANTSIGNAL, 1);
+ RADIOTAP(DB_ANTNOISE, 1);
+ RADIOTAP(FCS, 4);
+
+ RADIOTAP(RSSI, 2);
+ if (ptr != NULL) {
+ rtap->r_rssi = *(u_int8_t *)ptr;
+ rtap->r_max_rssi = *(u_int8_t *)ptr + 1;
+ }
+
+ return (0);
+
+ trunc:
+ return (EINVAL);
+}
+
+int
+hostapd_cmp(enum hostapd_op op, int val1, int val2)
+{
+ if ((op == HOSTAPD_OP_EQ && val1 == val2) ||
+ (op == HOSTAPD_OP_NE && val1 != val2) ||
+ (op == HOSTAPD_OP_LE && val1 <= val2) ||
+ (op == HOSTAPD_OP_LT && val1 < val2) ||
+ (op == HOSTAPD_OP_GE && val1 >= val2) ||
+ (op == HOSTAPD_OP_GT && val1 > val2))
+ return (1);
+ return (0);
+}
diff --git a/usr.sbin/hostapd/hostapd.conf.5 b/usr.sbin/hostapd/hostapd.conf.5
index d012beddd84..9a46a936a4f 100644
--- a/usr.sbin/hostapd/hostapd.conf.5
+++ b/usr.sbin/hostapd/hostapd.conf.5
@@ -1,6 +1,6 @@
-.\" $OpenBSD: hostapd.conf.5,v 1.32 2006/05/15 21:09:49 reyk Exp $
+.\" $OpenBSD: hostapd.conf.5,v 1.33 2006/06/27 18:14:59 reyk Exp $
.\"
-.\" Copyright (c) 2004, 2005 Reyk Floeter <reyk@openbsd.org>
+.\" Copyright (c) 2004, 2005, 2006 Reyk Floeter <reyk@openbsd.org>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
@@ -304,6 +304,7 @@ Match all frames.
.Op Ar from
.Op Ar to
.Op Ar bssid
+.Op Ar radiotap
.Xc
Apply rules to frames matching the given parameters.
The parameters are explained below.
@@ -360,6 +361,51 @@ section below for available direction specifications.
.El
.Pp
The
+.Ar radiotap
+rules allow parsing and matching of the extra information reported by
+the radiotap header.
+Support for the specified radiotap headers is optional and the
+specific parameters depend on the radiotap elements reported
+by the wireless interface.
+Support for the radiotap data link type can be verified with the
+.Xr tcpdump 8
+command.
+These rules require
+.Ic hostap mode radiotap
+in the global configuration.
+.Bl -tag -width Ds
+.It Xo
+.Ic signal
+.Op Ic operator
+.Ar percentage Ic %
+.Xc
+Match the signal quality of the received frame.
+.It Xo
+.Ic freq
+.Op Ic operator
+.Ar value Ic ( GHz \*(Ba MHz )
+.Xc
+Match the transmit rate of the received frame.
+.It Xo
+.Ic txrate
+.Op Ic operator
+.Ar rate Ic Mb
+.Xc
+Match the frequency of the received frame.
+.El
+.Pp
+The radiotap rules support the following operators.
+If omitted, the specified value will be checked if it is equal or not.
+.Bd -literal -offset indent
+= (equal)
+!= (not equal)
+\*(Lt (less than)
+\*(Le (less than or equal)
+\*(Gt (greater than)
+\*(Ge (greater than or equal)
+.Ed
+.Pp
+The
.Ar from , to ,
and
.Ar bssid
@@ -667,6 +713,12 @@ hostap handle on ath0 type management subtype auth with resend
# Remove a blacklisted node from the kernel node tree
hostap handle type management subtype auth from <blacklist> \e
with node delete &from
+
+# Log rogue accesspoints with a strong signal quality on
+# channel 3 (2.422GHz) transmitting frames with 1Mb.
+hostap handle type management subtype beacon bssid !<myess> \e
+ signal >= 50% txrate 1Mb freq 2.422GHz \e
+ with log
.Ed
.Sh IP ROAMING
In a traditional wireless network, multiple access points are
diff --git a/usr.sbin/hostapd/hostapd.h b/usr.sbin/hostapd/hostapd.h
index 1d5c439c3e9..e29f460e631 100644
--- a/usr.sbin/hostapd/hostapd.h
+++ b/usr.sbin/hostapd/hostapd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: hostapd.h,v 1.17 2006/05/15 20:53:02 reyk Exp $ */
+/* $OpenBSD: hostapd.h,v 1.18 2006/06/27 18:14:59 reyk Exp $ */
/*
* Copyright (c) 2004, 2005 Reyk Floeter <reyk@openbsd.org>
@@ -73,6 +73,7 @@ struct hostapd_counter {
u_int64_t cn_tx_iapp; /* sent IAPP messages */
u_int64_t cn_rx_apme; /* received Host AP messages */
u_int64_t cn_tx_apme; /* sent Host AP messages */
+ u_int64_t cn_rtap_miss; /* missing radiotap field */
};
#define HOSTAPD_ENTRY_MASK_ADD(_a, _m) do { \
@@ -139,6 +140,16 @@ struct hostapd_table {
TAILQ_ENTRY(hostapd_table) t_entries;
};
+struct hostapd_radiotap {
+ u_int32_t r_present;
+ u_int8_t r_txrate;
+ u_int16_t r_chan;
+ u_int16_t r_chan_flags;
+ u_int8_t r_rssi;
+ u_int8_t r_max_rssi;
+};
+#define HOSTAPD_RADIOTAP_F(_x) (1 << IEEE80211_RADIOTAP_##_x)
+
struct hostapd_ieee80211_frame {
u_int8_t i_fc[2];
u_int8_t i_dur[2];
@@ -160,6 +171,15 @@ enum hostapd_action {
HOSTAPD_ACTION_RESEND = 6
};
+enum hostapd_op {
+ HOSTAPD_OP_EQ = 0,
+ HOSTAPD_OP_NE = 1,
+ HOSTAPD_OP_LE = 2,
+ HOSTAPD_OP_LT = 3,
+ HOSTAPD_OP_GE = 4,
+ HOSTAPD_OP_GT = 5
+};
+
struct hostapd_action_data {
union {
struct hostapd_ieee80211_frame u_frame;
@@ -188,6 +208,8 @@ struct hostapd_action_data {
struct hostapd_frame {
struct hostapd_ieee80211_frame f_frame;
+ u_int32_t f_radiotap;
+
u_int32_t f_flags;
#define HOSTAPD_FRAME_F_TYPE 0x00000001
@@ -211,6 +233,10 @@ struct hostapd_frame {
#define HOSTAPD_FRAME_F_APME 0x00008000
#define HOSTAPD_FRAME_F_APME_N 0x00010000
#define HOSTAPD_FRAME_F_APME_M 0x00018000
+#define HOSTAPD_FRAME_F_RSSI 0x00020000
+#define HOSTAPD_FRAME_F_RATE 0x00040000
+#define HOSTAPD_FRAME_F_CHANNEL 0x00080000
+#define HOSTAPD_FRAME_F_RADIOTAP_M 0x000e0000
#define HOSTAPD_FRAME_F_M 0x0fffffff
#define HOSTAPD_FRAME_F_RET_OK 0x00000000
#define HOSTAPD_FRAME_F_RET_QUICK 0x10000000
@@ -231,6 +257,9 @@ struct hostapd_frame {
long f_rate, f_rate_intval;
long f_rate_cnt, f_rate_delay;
+ enum hostapd_op f_rssi_op, f_txrate_op, f_chan_op;
+ short f_rssi, f_txrate, f_chan;
+
enum hostapd_action f_action;
u_int32_t f_action_flags;
diff --git a/usr.sbin/hostapd/parse.y b/usr.sbin/hostapd/parse.y
index 0ac01148b82..8ca6cd902c5 100644
--- a/usr.sbin/hostapd/parse.y
+++ b/usr.sbin/hostapd/parse.y
@@ -1,7 +1,7 @@
-/* $OpenBSD: parse.y,v 1.23 2006/06/01 22:09:09 reyk Exp $ */
+/* $OpenBSD: parse.y,v 1.24 2006/06/27 18:14:59 reyk Exp $ */
/*
- * Copyright (c) 2004, 2005 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2004, 2005, 2006 Reyk Floeter <reyk@openbsd.org>
* Copyright (c) 2002 - 2005 Henning Brauer <henning@openbsd.org>
* Copyright (c) 2001 Markus Friedl. All rights reserved.
* Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
@@ -40,6 +40,9 @@
#include <netinet/if_ether.h>
#include <arpa/inet.h>
+#include <net80211/ieee80211.h>
+#include <net80211/ieee80211_radiotap.h>
+
#include <ctype.h>
#include <errno.h>
#include <event.h>
@@ -101,6 +104,7 @@ typedef struct {
char *string;
long val;
u_int16_t reason;
+ enum hostapd_op op;
} v;
int lineno;
} YYSTYPE;
@@ -119,12 +123,23 @@ u_int negative;
frame.f_flags |= HOSTAPD_FRAME_F_##_m##_TABLE | (negative ? \
HOSTAPD_FRAME_F_##_m##_N : HOSTAPD_FRAME_F_##_m); \
}
+#define HOSTAPD_MATCH_RADIOTAP(_x) { \
+ if (hostapd_cfg.c_apme_dlt == DLT_IEEE802_11 || \
+ (hostapd_cfg.c_apme_dlt == 0 && \
+ HOSTAPD_DLT == DLT_IEEE802_11)) { \
+ yyerror("option %s requires radiotap headers", #_x); \
+ YYERROR; \
+ } \
+ frame.f_radiotap |= HOSTAPD_RADIOTAP_F(RSSI); \
+ frame.f_flags |= HOSTAPD_FRAME_F_##_x; \
+}
#define HOSTAPD_IAPP_FLAG(_f) { \
if (negative) \
hostapd_cfg.c_iapp.i_flags &= ~(HOSTAPD_IAPP_F_##_f); \
else \
hostapd_cfg.c_iapp.i_flags |= (HOSTAPD_IAPP_F_##_f); \
}
+
%}
%token MODE INTERFACE IAPP HOSTAP MULTICAST BROADCAST SET SEC USEC
@@ -134,7 +149,7 @@ u_int negative;
%token ERROR CONST TABLE NODE DELETE ADD LOG VERBOSE LIMIT QUICK SKIP
%token REASON UNSPECIFIED EXPIRE LEAVE ASSOC TOOMANY NOT AUTHED ASSOCED
%token RESERVED RSN REQUIRED INCONSISTENT IE INVALID MIC FAILURE OPEN
-%token ADDRESS PORT ON NOTIFY TTL INCLUDE ROUTE ROAMING
+%token ADDRESS PORT ON NOTIFY TTL INCLUDE ROUTE ROAMING RSSI TXRATE FREQ
%token <v.string> STRING
%token <v.val> VALUE
%type <v.val> number
@@ -144,6 +159,10 @@ u_int negative;
%type <v.string> table
%type <v.string> string
%type <v.authalg> authalg
+%type <v.op> unaryop
+%type <v.val> percent
+%type <v.val> txrate
+%type <v.val> freq
%%
@@ -410,7 +429,7 @@ nodeopt : DELETE
frmmatch : ANY
| frm frmmatchtype frmmatchdir frmmatchfrom frmmatchto
- frmmatchbssid
+ frmmatchbssid frmmatchrtap
;
frm : /* empty */
@@ -710,6 +729,42 @@ frmmatchbssid : /* any */
}
;
+frmmatchrtap : /* empty */
+ | frmmatchrtap_l
+ ;
+
+frmmatchrtap_l : frmmatchrtap_l frmmatchrtapopt
+ | frmmatchrtapopt
+ ;
+
+frmmatchrtapopt : RSSI unaryop percent
+ {
+ if (($2 == HOSTAPD_OP_GT && $3 == 100) ||
+ ($2 == HOSTAPD_OP_LE && $3 == 100) ||
+ ($2 == HOSTAPD_OP_LT && $3 == 0) ||
+ ($2 == HOSTAPD_OP_GE && $3 == 0)) {
+ yyerror("absurd unary comparison");
+ YYERROR;
+ }
+
+ frame.f_rssi_op = $2;
+ frame.f_rssi = $3;
+ HOSTAPD_MATCH_RADIOTAP(RSSI);
+ }
+ | TXRATE unaryop txrate
+ {
+ frame.f_txrate_op = $2;
+ frame.f_txrate = $3;
+ HOSTAPD_MATCH_RADIOTAP(RATE);
+ }
+ | FREQ unaryop freq
+ {
+ frame.f_chan_op = $2;
+ frame.f_chan = $3;
+ HOSTAPD_MATCH_RADIOTAP(CHANNEL);
+ }
+ ;
+
frmmatchaddr : ANY
{
$$.flags = 0;
@@ -997,6 +1052,100 @@ not : /* empty */
}
;
+unaryop : /* any */
+ {
+ $$ = HOSTAPD_OP_EQ;
+ }
+ | '='
+ {
+ $$ = HOSTAPD_OP_EQ;
+ }
+ | '=='
+ {
+ $$ = HOSTAPD_OP_EQ;
+ }
+ | '!'
+ {
+ $$ = HOSTAPD_OP_NE;
+ }
+ | '!' '='
+ {
+ $$ = HOSTAPD_OP_NE;
+ }
+ | '<' '='
+ {
+ $$ = HOSTAPD_OP_LE;
+ }
+ | '<'
+ {
+ $$ = HOSTAPD_OP_LT;
+ }
+ | '>' '='
+ {
+ $$ = HOSTAPD_OP_GE;
+ }
+ | '>'
+ {
+ $$ = HOSTAPD_OP_GT;
+ }
+ ;
+
+percent : STRING
+ {
+ double val;
+ char *cp;
+
+ val = strtod($1, &cp);
+ if (cp == NULL || strcmp(cp, "%") != 0 ||
+ val < 0 || val > 100) {
+ yyerror("invalid percentage: %s", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ $$ = val;
+ }
+ ;
+
+txrate : STRING
+ {
+ double val;
+ char *cp;
+
+ val = strtod($1, &cp) * 2;
+ if (cp == NULL || strcasecmp(cp, "mb") != 0 ||
+ val != (int)val) {
+ yyerror("invalid rate: %s", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ $$ = val;
+ }
+ ;
+
+freq : STRING
+ {
+ double val;
+ char *cp;
+
+ val = strtod($1, &cp);
+ if (cp != NULL) {
+ if (strcasecmp(cp, "ghz") == 0) {
+ $$ = val * 1000;
+ } else if (strcasecmp(cp, "mhz") == 0) {
+ $$ = val;
+ } else
+ cp = NULL;
+ }
+ if (cp == NULL) {
+ yyerror("invalid frequency: %s", $1);
+ free($1);
+ YYERROR;
+ }
+ free($1);
+ }
+ ;
%%
/*
@@ -1040,6 +1189,7 @@ lookup(char *token)
{ "expire", EXPIRE },
{ "failure", FAILURE },
{ "frame", FRAME },
+ { "freq", FREQ },
{ "from", FROM },
{ "handle", HANDLE },
{ "hostap", HOSTAP },
@@ -1083,12 +1233,14 @@ lookup(char *token)
{ "rsn", RSN },
{ "sec", SEC },
{ "set", SET },
+ { "signal", RSSI },
{ "skip", SKIP },
{ "subtype", SUBTYPE },
{ "table", TABLE },
{ "to", TO },
{ "toomany", TOOMANY },
{ "ttl", TTL },
+ { "txrate", TXRATE },
{ "type", TYPE },
{ "unspecified", UNSPECIFIED },
{ "usec", USEC },