diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2005-06-17 19:13:36 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2005-06-17 19:13:36 +0000 |
commit | bc120873efdde9755b7d563db5d0d17931f0ac03 (patch) | |
tree | fd4fe11866372687815f6c2f37d4153c85578386 | |
parent | e7c14c335fd49a0b07cca65d0a6d86e07e3c0e4f (diff) |
first step to implement a proactive wireless monitoring system using
hostapd(8). it's a very simple but powerful approach using highly
flexible and stateless event and action rules for IEEE 802.11 traffic.
you can monitor a wireless network by watching frames with types and
addresses (with support for tables and masks) and you can trigger
actions like writing log messages, sending pcap/radiotap dumps to the
IAPP network, removing nodes from the hostap, resending received
frames and sending contructed 802.11 frames in reply to traffic
received from any rogue nodes.
it's based on some initial work from the c2k5 which has been tested
and improved during the last weeks. some missing documentation for
hostapd.conf(5) will be written as soon as possible.
ok deraadt@
-rw-r--r-- | usr.sbin/hostapd/Makefile | 6 | ||||
-rw-r--r-- | usr.sbin/hostapd/apme.c | 120 | ||||
-rw-r--r-- | usr.sbin/hostapd/handle.c | 299 | ||||
-rw-r--r-- | usr.sbin/hostapd/hostapd.c | 150 | ||||
-rw-r--r-- | usr.sbin/hostapd/hostapd.conf.5 | 233 | ||||
-rw-r--r-- | usr.sbin/hostapd/hostapd.h | 275 | ||||
-rw-r--r-- | usr.sbin/hostapd/iapp.c | 131 | ||||
-rw-r--r-- | usr.sbin/hostapd/parse.y | 732 | ||||
-rw-r--r-- | usr.sbin/hostapd/print-802_11.c | 647 | ||||
-rw-r--r-- | usr.sbin/hostapd/privsep.c | 28 |
10 files changed, 2502 insertions, 119 deletions
diff --git a/usr.sbin/hostapd/Makefile b/usr.sbin/hostapd/Makefile index e79e24b76f1..fabb4bce5cd 100644 --- a/usr.sbin/hostapd/Makefile +++ b/usr.sbin/hostapd/Makefile @@ -1,10 +1,10 @@ -# $OpenBSD: Makefile,v 1.2 2005/04/13 20:30:17 deraadt Exp $ +# $OpenBSD: Makefile,v 1.3 2005/06/17 19:13:35 reyk Exp $ PROG= hostapd -SRCS= privsep.c apme.c iapp.c llc.c hostapd.c parse.y +SRCS= privsep.c apme.c handle.c iapp.c llc.c hostapd.c print-802_11.c parse.y MAN= hostapd.8 hostapd.conf.5 LDADD= ${LIBEVENT} -CFLAGS+= -Wall -pedantic -I${.CURDIR} +CFLAGS+= -Wall -I${.CURDIR} CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes CFLAGS+= -Wmissing-declarations CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual diff --git a/usr.sbin/hostapd/apme.c b/usr.sbin/hostapd/apme.c index a2287d0cb53..77ff8d33eae 100644 --- a/usr.sbin/hostapd/apme.c +++ b/usr.sbin/hostapd/apme.c @@ -1,4 +1,4 @@ -/* $OpenBSD: apme.c,v 1.3 2005/04/13 19:06:11 deraadt Exp $ */ +/* $OpenBSD: apme.c,v 1.4 2005/06/17 19:13:35 reyk Exp $ */ /* * Copyright (c) 2004, 2005 Reyk Floeter <reyk@vantronix.net> @@ -21,6 +21,7 @@ #include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> +#include <sys/uio.h> #include <net/if.h> #include <net/if_dl.h> @@ -33,6 +34,8 @@ #include <netinet/if_ether.h> #include <arpa/inet.h> +#include <net80211/ieee80211_radiotap.h> + #include <fcntl.h> #include <stdlib.h> #include <stdio.h> @@ -81,16 +84,105 @@ hostapd_apme_input(int fd, short sig, void *arg) } } +int +hostapd_apme_output(struct hostapd_config *cfg, + struct hostapd_ieee80211_frame *frame) +{ + struct iovec iov[2]; + int iovcnt; + struct ieee80211_frame wh; + + bzero(&wh, sizeof(wh)); + + switch (frame->i_fc[1] & IEEE80211_FC1_DIR_MASK) { + case IEEE80211_FC1_DIR_NODS: + bcopy(frame->i_from, wh.i_addr2, IEEE80211_ADDR_LEN); + bcopy(frame->i_to, wh.i_addr1, IEEE80211_ADDR_LEN); + bcopy(frame->i_bssid, wh.i_addr3, IEEE80211_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_TODS: + bcopy(frame->i_from, wh.i_addr2, IEEE80211_ADDR_LEN); + bcopy(frame->i_to, wh.i_addr3, IEEE80211_ADDR_LEN); + bcopy(frame->i_bssid, wh.i_addr1, IEEE80211_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_FROMDS: + bcopy(frame->i_from, wh.i_addr3, IEEE80211_ADDR_LEN); + bcopy(frame->i_to, wh.i_addr1, IEEE80211_ADDR_LEN); + bcopy(frame->i_bssid, wh.i_addr2, IEEE80211_ADDR_LEN); + break; + default: + case IEEE80211_FC1_DIR_DSTODS: + return (EINVAL); + } + + wh.i_fc[0] = IEEE80211_FC0_VERSION_0 | frame->i_fc[0]; + wh.i_fc[1] = frame->i_fc[1]; + bcopy(frame->i_dur, wh.i_dur, sizeof(wh.i_dur)); + bcopy(frame->i_seq, wh.i_seq, sizeof(wh.i_seq)); + + iovcnt = 1; + iov[0].iov_base = &wh; + iov[0].iov_len = sizeof(struct ieee80211_frame); + + if (frame->i_data != NULL && frame->i_data_len > 0) { + iovcnt = 2; + iov[1].iov_base = frame->i_data; + iov[1].iov_len = frame->i_data_len; + } + + if (writev(cfg->c_apme_raw, iov, iovcnt) == -1) + return (errno); + + return (0); +} + +int +hostapd_apme_offset(struct hostapd_config *cfg, + u_int8_t *buf, const u_int len) +{ + struct ieee80211_radiotap_header *rh; + u_int rh_len; + + if (cfg->c_apme_dlt == DLT_IEEE802_11) + return (0); + else if (cfg->c_apme_dlt != DLT_IEEE802_11_RADIO) + return (-1); + + if (len < sizeof(struct ieee80211_radiotap_header)) + return (-1); + + rh = (struct ieee80211_radiotap_header*)buf; + rh_len = letoh16(rh->it_len); + + if (rh->it_version != 0) + return (-1); + if (len <= rh_len) + return (-1); + + return ((int)rh_len); +} + void hostapd_apme_frame(struct hostapd_config *cfg, u_int8_t *buf, u_int len) { struct hostapd_node node; - struct ieee80211_frame *wh = (struct ieee80211_frame *)buf; + struct ieee80211_frame *wh; + int offset; + + if ((offset = hostapd_apme_offset(cfg, buf, len)) < 0) + return; + wh = (struct ieee80211_frame *)(buf + offset); /* Ignore short frames or fragments */ if (len < sizeof(struct ieee80211_frame)) return; + /* Handle received frames */ + if ((hostapd_handle_input(cfg, buf, len) == + (HOSTAPD_FRAME_F_RET_SKIP >> HOSTAPD_FRAME_F_RET_S)) || + cfg->c_flags & HOSTAPD_CFG_F_IAPP_PASSIVE) + return; + /* * Only accept local association response frames, ... */ @@ -117,14 +209,14 @@ hostapd_apme_frame(struct hostapd_config *cfg, u_int8_t *buf, u_int len) bcopy(wh->i_addr1, node.ni_macaddr, IEEE80211_ADDR_LEN); if (hostapd_priv_apme_getnode(cfg, &node) != 0) { hostapd_log(HOSTAPD_LOG_DEBUG, - "%s/%s: invalid association from %s on the Host AP\n", - cfg->c_apme_iface, cfg->c_iapp_iface, - ether_ntoa((struct ether_addr*)wh->i_addr1)); + "%s: invalid association from %s on the Host AP\n", + cfg->c_apme_iface, etheraddr_string(wh->i_addr1)); return; } + cfg->c_stats.cn_tx_apme++; - /* Call ADD.notify handler */ hostapd_iapp_add_notify(cfg, &node); + } void @@ -133,7 +225,7 @@ hostapd_apme_init(struct hostapd_config *cfg) u_int i, dlt; struct ifreq ifr; - cfg->c_apme_raw = hostapd_bpf_open(O_RDONLY); + cfg->c_apme_raw = hostapd_bpf_open(O_RDWR); cfg->c_apme_rawlen = IAPP_MAXSIZE; if (ioctl(cfg->c_apme_raw, BIOCSBLEN, &cfg->c_apme_rawlen) == -1) @@ -156,7 +248,7 @@ hostapd_apme_init(struct hostapd_config *cfg) hostapd_fatal("failed to set BPF interface \"%s\": %s\n", cfg->c_apme_iface, strerror(errno)); - dlt = IAPP_DLT; + dlt = cfg->c_apme_dlt; if (ioctl(cfg->c_apme_raw, BIOCSDLT, &dlt) == -1) hostapd_fatal("failed to set BPF link type on \"%s\": %s\n", cfg->c_apme_iface, strerror(errno)); @@ -166,3 +258,15 @@ hostapd_apme_init(struct hostapd_config *cfg) hostapd_fatal("failed to lock BPF interface on \"%s\": %s\n", cfg->c_apme_iface, strerror(errno)); } + +int +hostapd_apme_addnode(struct hostapd_config *cfg, struct hostapd_node *node) +{ + return (hostapd_priv_apme_setnode(cfg, node, 1)); +} + +int +hostapd_apme_delnode(struct hostapd_config *cfg, struct hostapd_node *node) +{ + return (hostapd_priv_apme_setnode(cfg, node, 0)); +} diff --git a/usr.sbin/hostapd/handle.c b/usr.sbin/hostapd/handle.c new file mode 100644 index 00000000000..a82f37a4eb8 --- /dev/null +++ b/usr.sbin/hostapd/handle.c @@ -0,0 +1,299 @@ +/* $OpenBSD: handle.c,v 1.1 2005/06/17 19:13:35 reyk Exp $ */ + +/* + * Copyright (c) 2005 Reyk Floeter <reyk@vantronix.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> + +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_arp.h> +#include <net/if_llc.h> +#include <net/bpf.h> + +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <arpa/inet.h> + +#include <fcntl.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include "hostapd.h" + +int hostapd_handle_frame(struct hostapd_config *, struct hostapd_frame *, + u_int8_t *, const u_int); +int hostapd_handle_action(struct hostapd_config *, struct hostapd_frame *, + u_int8_t *, u_int8_t *, u_int8_t *, u_int8_t *, const u_int); +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_input(struct hostapd_config *cfg, u_int8_t *buf, u_int len) +{ + int ret; + struct hostapd_frame *frame; + + TAILQ_FOREACH(frame, &cfg->c_frames, f_entries) { + if ((ret = hostapd_handle_frame(cfg, frame, buf, len)) != 0) + return (ret); + } + + return (0); +} + +void +hostapd_handle_addr(const u_int32_t mask, u_int32_t *flags, u_int8_t *addr, + u_int8_t *maddr, struct hostapd_table *table) +{ + int ret = 0; + + if ((*flags & mask) & HOSTAPD_FRAME_TABLE) { + if (hostapd_entry_lookup(table, addr) == NULL) + ret = 1; + } else if (bcmp(addr, maddr, IEEE80211_ADDR_LEN) != 0) + ret = 1; + + if ((ret == 1 && (*flags & mask) & HOSTAPD_FRAME_N) || + (ret == 0 && ((*flags & mask) & HOSTAPD_FRAME_N) == 0)) + *flags &= ~mask; +} + +void +hostapd_handle_ref(u_int flags, u_int shift, u_int8_t *wfrom, u_int8_t *wto, + u_int8_t *wbssid, u_int8_t *addr) +{ + if (flags & (HOSTAPD_ACTION_F_REF_FROM << shift)) + bcopy(wfrom, addr, IEEE80211_ADDR_LEN); + else if (flags & (HOSTAPD_ACTION_F_REF_TO << shift)) + bcopy(wto, addr, IEEE80211_ADDR_LEN); + else if (flags & (HOSTAPD_ACTION_F_REF_BSSID << shift)) + bcopy(wbssid, addr, IEEE80211_ADDR_LEN); +} + +int +hostapd_handle_frame(struct hostapd_config *cfg, struct hostapd_frame *frame, + u_int8_t *buf, const u_int len) +{ + struct ieee80211_frame *wh; + struct hostapd_ieee80211_frame *mh; + u_int8_t *wfrom, *wto, *wbssid; + struct timeval t_now; + u_int32_t flags; + int offset; + + if ((offset = hostapd_apme_offset(cfg, buf, len)) < 0) + return (0); + wh = (struct ieee80211_frame *)(buf + offset); + + mh = &frame->f_frame; + flags = frame->f_flags; + + /* Handle optional limit */ + if (frame->f_limit.tv_sec || frame->f_limit.tv_usec) { + gettimeofday(&t_now, NULL); + if (timercmp(&t_now, &frame->f_then, <)) + return (0); + timeradd(&t_now, &frame->f_limit, &frame->f_then); + } + + switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { + case IEEE80211_FC1_DIR_NODS: + wfrom = wh->i_addr2; + wto = wh->i_addr1; + wbssid = wh->i_addr3; + break; + case IEEE80211_FC1_DIR_TODS: + wfrom = wh->i_addr2; + wto = wh->i_addr3; + wbssid = wh->i_addr1; + break; + case IEEE80211_FC1_DIR_FROMDS: + wfrom = wh->i_addr3; + wto = wh->i_addr1; + wbssid = wh->i_addr2; + break; + default: + case IEEE80211_FC1_DIR_DSTODS: + return (0); + } + + if (flags & HOSTAPD_FRAME_F_TYPE) { + /* type $type */ + if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == + (mh->i_fc[0] & IEEE80211_FC0_TYPE_MASK)) + flags &= ~HOSTAPD_FRAME_F_TYPE; + } else if (flags & HOSTAPD_FRAME_F_TYPE_N) { + /* type !$type */ + if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != + (mh->i_fc[0] & IEEE80211_FC0_TYPE_MASK)) + flags &= ~HOSTAPD_FRAME_F_TYPE_N; + } + + if (flags & HOSTAPD_FRAME_F_SUBTYPE) { + /* subtype $subtype */ + if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == + (mh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK)) + flags &= ~HOSTAPD_FRAME_F_SUBTYPE; + } else if (flags & HOSTAPD_FRAME_F_SUBTYPE_N) { + /* subtype !$subtype */ + if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) != + (mh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK)) + flags &= ~HOSTAPD_FRAME_F_SUBTYPE_N; + } + + if (flags & HOSTAPD_FRAME_F_DIR) { + /* dir $dir */ + if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == + (mh->i_fc[1] & IEEE80211_FC1_DIR_MASK)) + flags &= ~HOSTAPD_FRAME_F_DIR; + } else if (flags & HOSTAPD_FRAME_F_DIR_N) { + /* dir !$dir */ + if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) != + (mh->i_fc[1] & IEEE80211_FC1_DIR_MASK)) + flags &= ~HOSTAPD_FRAME_F_DIR_N; + } + + /* from/to/bssid [!]$addr/<table> */ + hostapd_handle_addr(HOSTAPD_FRAME_F_FROM_M, &flags, wfrom, + mh->i_from, frame->f_from); + hostapd_handle_addr(HOSTAPD_FRAME_F_TO_M, &flags, wto, + mh->i_to, frame->f_to); + hostapd_handle_addr(HOSTAPD_FRAME_F_BSSID_M, &flags, wbssid, + mh->i_bssid, frame->f_bssid); + + /* Handle if frame matches */ + if ((flags & HOSTAPD_FRAME_F_M) != 0) + return (0); + + if (hostapd_handle_action(cfg, frame, wfrom, wto, wbssid, buf, + len) != 0) + return (0); + + return ((frame->f_flags & HOSTAPD_FRAME_F_RET_M) >> + HOSTAPD_FRAME_F_RET_S); +} + +int +hostapd_handle_action(struct hostapd_config *cfg, struct hostapd_frame *frame, + u_int8_t *wfrom, u_int8_t *wto, u_int8_t *wbssid, u_int8_t *buf, + const u_int len) +{ + struct hostapd_action_data *action = &frame->f_action_data; + struct hostapd_node node; + u_int8_t *lladdr = NULL; + int ret = 0, offset; + + switch (frame->f_action) { + case HOSTAPD_ACTION_RADIOTAP: + /* Send IAPP frame with radiotap/pcap payload */ + if ((ret = hostapd_iapp_radiotap(cfg, buf, len)) != 0) + return (ret); + + if ((frame->f_action_flags & HOSTAPD_ACTION_VERBOSE) == 0) + return (0); + + hostapd_log(HOSTAPD_LOG, + "%s: sent IAPP frame HOSTAPD_%s (%u bytes)\n", + cfg->c_iapp_iface, cfg->c_apme_dlt == + DLT_IEEE802_11_RADIO ? "RADIOTAP" : "PCAP", len); + break; + + case HOSTAPD_ACTION_LOG: + /* Log frame to syslog/stderr */ + hostapd_printf("%s: ", cfg->c_apme_iface); + + hostapd_print_ieee80211(cfg->c_apme_dlt, frame->f_action_flags & + HOSTAPD_ACTION_VERBOSE, buf, len); + + /* Flush output buffer */ + hostapd_printf(NULL); + break; + + case HOSTAPD_ACTION_DELNODE: + case HOSTAPD_ACTION_ADDNODE: + bzero(&node, sizeof(node)); + + if (action->a_flags & HOSTAPD_ACTION_F_REF_FROM) + lladdr = wfrom; + else if (action->a_flags & HOSTAPD_ACTION_F_REF_TO) + lladdr = wto; + else if (action->a_flags & HOSTAPD_ACTION_F_REF_BSSID) + lladdr = wbssid; + else + lladdr = action->a_lladdr; + + bcopy(lladdr, &node.ni_macaddr, IEEE80211_ADDR_LEN); + + if (HOSTAPD_ACTION_DELNODE) + ret = hostapd_apme_delnode(cfg, &node); + else + ret = hostapd_apme_addnode(cfg, &node); + + if (ret != 0) { + hostapd_log(HOSTAPD_LOG_DEBUG, + "%s: node add/delete %s failed: %s\n", + cfg->c_apme_iface, etheraddr_string(lladdr), + strerror(ret)); + } + break; + + case HOSTAPD_ACTION_NONE: + /* Nothing */ + break; + + case HOSTAPD_ACTION_RESEND: + /* Resend received raw IEEE 802.11 frame */ + if ((offset = hostapd_apme_offset(cfg, buf, len)) < 0) + return (EINVAL); + if (write(cfg->c_apme_raw, buf + offset, len - offset) == -1) + ret = errno; + break; + + case HOSTAPD_ACTION_FRAME: + if (action->a_flags & HOSTAPD_ACTION_F_REF_M) { + hostapd_handle_ref(action->a_flags & + HOSTAPD_ACTION_F_REF_FROM_M, + HOSTAPD_ACTION_F_REF_FROM_S, wfrom, wto, wbssid, + action->a_frame.i_from); + hostapd_handle_ref(action->a_flags & + HOSTAPD_ACTION_F_REF_TO_M, + HOSTAPD_ACTION_F_REF_TO_S, wfrom, wto, wbssid, + action->a_frame.i_to); + hostapd_handle_ref(action->a_flags & + HOSTAPD_ACTION_F_REF_BSSID_M, + HOSTAPD_ACTION_F_REF_BSSID_S, wfrom, wto, wbssid, + action->a_frame.i_bssid); + } + + /* Send a raw IEEE 802.11 frame */ + return (hostapd_apme_output(cfg, &action->a_frame)); + + default: + return (0); + } + + return (ret); +} diff --git a/usr.sbin/hostapd/hostapd.c b/usr.sbin/hostapd/hostapd.c index ca4f4661b37..e7dabf43f51 100644 --- a/usr.sbin/hostapd/hostapd.c +++ b/usr.sbin/hostapd/hostapd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hostapd.c,v 1.10 2005/05/21 19:18:51 msf Exp $ */ +/* $OpenBSD: hostapd.c,v 1.11 2005/06/17 19:13:35 reyk Exp $ */ /* * Copyright (c) 2004, 2005 Reyk Floeter <reyk@vantronix.net> @@ -54,6 +54,7 @@ void hostapd_sig_handler(int); struct hostapd_config hostapd_cfg; extern char *__progname; +char printbuf[BUFSIZ]; void hostapd_usage(void) @@ -81,6 +82,31 @@ hostapd_log(u_int level, const char *fmt, ...) } void +hostapd_printf(const char *fmt, ...) +{ + char newfmt[BUFSIZ]; + va_list ap; + size_t n; + + if (fmt == NULL) { + flush: + hostapd_log(HOSTAPD_LOG, "%s", printbuf); + bzero(printbuf, sizeof(printbuf)); + return; + } + + va_start(ap, fmt); + bzero(newfmt, sizeof(newfmt)); + if ((n = strlcpy(newfmt, printbuf, sizeof(newfmt))) >= sizeof(newfmt)) + goto flush; + if (strlcpy(newfmt + n, fmt, sizeof(newfmt) - n) >= sizeof(newfmt) - n) + goto flush; + if (vsnprintf(printbuf, sizeof(printbuf), newfmt, ap) == -1) + goto flush; + va_end(ap); +} + +void hostapd_fatal(const char *fmt, ...) { va_list ap; @@ -258,7 +284,7 @@ void hostapd_sig_handler(int sig) { struct timeval tv; - + tv.tv_sec = 0; tv.tv_usec = 0; @@ -274,7 +300,10 @@ hostapd_sig_handler(int sig) void hostapd_cleanup(struct hostapd_config *cfg) { + int i; struct ip_mreq mreq; + struct hostapd_table *table; + struct hostapd_entry *entry; if (cfg->c_flags & HOSTAPD_CFG_F_PRIV && (cfg->c_flags & HOSTAPD_CFG_F_BRDCAST) == 0 && @@ -304,6 +333,24 @@ hostapd_cleanup(struct hostapd_config *cfg) hostapd_iapp_term(&hostapd_cfg); } + /* Cleanup tables */ + while ((table = TAILQ_FIRST(&cfg->c_tables)) != NULL) { + for (i = 0; i < HOSTAPD_TABLE_HASHSIZE; i++) { + while ((entry = + TAILQ_FIRST(&table->t_head[i])) != NULL) { + TAILQ_REMOVE(&table->t_head[i], entry, + e_entries); + free(entry); + } + } + while ((entry = TAILQ_FIRST(&table->t_mask_head)) != NULL) { + TAILQ_REMOVE(&table->t_mask_head, entry, e_entries); + free(entry); + } + TAILQ_REMOVE(&cfg->c_tables, table, t_entries); + free(table); + } + hostapd_log(HOSTAPD_LOG_VERBOSE, "bye!\n"); } @@ -371,7 +418,8 @@ main(int argc, char *argv[]) hostapd_fatal("need root privileges\n"); /* Parse the configuration file */ - hostapd_parse_file(cfg); + if (hostapd_parse_file(cfg) != 0) + hostapd_fatal("invalid configuration\n"); if ((cfg->c_flags & HOSTAPD_CFG_F_IAPP) == 0) hostapd_usage(); @@ -379,6 +427,9 @@ main(int argc, char *argv[]) if ((cfg->c_flags & HOSTAPD_CFG_F_APME) == 0) strlcpy(cfg->c_apme_iface, "<none>", sizeof(cfg->c_apme_iface)); + if (cfg->c_apme_dlt == 0) + cfg->c_apme_dlt = HOSTAPD_DLT; + /* * Setup the hostapd handlers */ @@ -442,3 +493,96 @@ main(int argc, char *argv[]) hostapd_cleanup(cfg); return (EXIT_SUCCESS); } + +struct hostapd_table * +hostapd_table_add(struct hostapd_config *cfg, const char *name) +{ + int i; + struct hostapd_table *table; + + if (hostapd_table_lookup(cfg, name) != NULL) + return (NULL); + if ((table = (struct hostapd_table *) + calloc(1, sizeof(struct hostapd_table))) == NULL) + return (NULL); + + strlcpy(table->t_name, name, sizeof(table->t_name)); + for (i = 0; i < HOSTAPD_TABLE_HASHSIZE; i++) + TAILQ_INIT(&table->t_head[i]); + TAILQ_INIT(&table->t_mask_head); + TAILQ_INSERT_TAIL(&cfg->c_tables, table, t_entries); + + return (table); +} + +struct hostapd_table * +hostapd_table_lookup(struct hostapd_config *cfg, const char *name) +{ + struct hostapd_table *table; + + TAILQ_FOREACH(table, &cfg->c_tables, t_entries) { + if (strcmp(name, table->t_name) == 0) + return (table); + } + + return (NULL); +} + +struct hostapd_entry * +hostapd_entry_add(struct hostapd_table *table, u_int8_t *lladdr) +{ + u_int hash; + struct hostapd_entry *entry; + + if (hostapd_entry_lookup(table, lladdr) != NULL) + return (NULL); + + if ((entry = (struct hostapd_entry *) + calloc(1, sizeof(struct hostapd_entry))) == NULL) + return (NULL); + + bcopy(lladdr, entry->e_lladdr, IEEE80211_ADDR_LEN); + hash = HOSTAPD_TABLE_HASH(lladdr); + TAILQ_INSERT_TAIL(&table->t_head[hash], entry, e_entries); + + return (entry); +} + +struct hostapd_entry * +hostapd_entry_lookup(struct hostapd_table *table, u_int8_t *lladdr) +{ + u_int hash; + struct hostapd_entry *entry; + + hash = HOSTAPD_TABLE_HASH(lladdr); + TAILQ_FOREACH(entry, &table->t_head[hash], e_entries) { + if (bcmp(lladdr, entry->e_lladdr, IEEE80211_ADDR_LEN) == 0) + return (entry); + } + + /* Masked entries can't be handled by the hash table */ + TAILQ_FOREACH(entry, &table->t_mask_head, e_entries) { + if (HOSTAPD_ENTRY_MASK_MATCH(entry, lladdr)) + return (entry); + } + + return (NULL); +} + +void +hostapd_entry_update(struct hostapd_table *table, struct hostapd_entry *entry) +{ + u_int hash; + + hash = HOSTAPD_TABLE_HASH(entry->e_lladdr); + TAILQ_REMOVE(&table->t_head[hash], entry, e_entries); + + /* Apply mask to entry */ + if (entry->e_flags & HOSTAPD_ENTRY_F_MASK) { + HOSTAPD_ENTRY_MASK_ADD(entry->e_lladdr, entry->e_mask); + TAILQ_INSERT_TAIL(&table->t_mask_head, entry, e_entries); + } else { + hash = HOSTAPD_TABLE_HASH(entry->e_lladdr); + TAILQ_INSERT_TAIL(&table->t_head[hash], entry, e_entries); + } +} diff --git a/usr.sbin/hostapd/hostapd.conf.5 b/usr.sbin/hostapd/hostapd.conf.5 index 45923f27478..e8d388f17d6 100644 --- a/usr.sbin/hostapd/hostapd.conf.5 +++ b/usr.sbin/hostapd/hostapd.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: hostapd.conf.5,v 1.3 2005/04/13 20:03:06 jmc Exp $ +.\" $OpenBSD: hostapd.conf.5,v 1.4 2005/06/17 19:13:35 reyk Exp $ .\" .\" Copyright (c) 2004, 2005 Reyk Floeter <reyk@vantronix.net> .\" @@ -33,9 +33,15 @@ file is divided into two main sections. .It Sy Macros User-defined variables may be defined and used later, simplifying the configuration file. +.It Sy Tables +Tables provide a mechanism to handle large number of linker layer +addresses easily with increased performance and flexibility. .It Sy Global Configuration -Global settings for +Global runtime settings for .Xr hostapd 8 . +.It Sy Event rules +Event rules provide a powerful mechanism to trigger certain actions +when receiving specified IEEE 802.11 frames. .El .Pp Comments can be put anywhere in the file using a hash mark @@ -61,9 +67,36 @@ For example: wlan="ath0" set iapp interface $wlan .Ed +.Sh TABLES +Tables are named structures which can hold a collection of link layer +addresses, masked address ranges and link layer to IP address +assignments. Lookups against tables in +.Xr hostapd 8 +are relatively fast, making a single rule with tables much more +efficient, in terms of processor usage and memory consumption, than a +large number of rules which differ only in link layer addresses. +.Pp +Tables are used for +.Xr hostapd 8 +.Ic event rules +to match specified IEEE 802.11 link layer addresses and address ranges +and the capability to assign link layer to IP addresses is a +requirement for advanced IAPP functionality. +.Pp +For example: +.Bd -literal -offset indent +cisco="00:40:06:ff:ff:ff / ff:ff:ff:00:00:00" + +table <black> { $cisco, 00:0d:60:ff:f1:2a } +table <myess> const { + 00:00:24:c3:40:18 -> 10.195.64.24, + 00:00:24:c3:40:19 -> 10.195.64.25, + 00:00:24:c3:40:1a -> 10.195.64.26 +} +.Ed .Sh GLOBAL CONFIGURATION The following configuration settings are understood: -.Bl -tag -width Ds +.Bl -tag -width xxxx .It Ic set hostap interface Ar interface Specify the wireless interface running in Host AP mode. This option could be omitted to use @@ -78,9 +111,199 @@ The used multicast group is 224.0.1.178. .Pp Possible options: .Bd -literal -offset indent -set iapp mode multicast -set iapp mode broadcast +.Ar set iapp mode multicast +.Ar set iapp mode broadcast +.Ed +.El +.Sh EVENT RULES +Event rules provide a powerful way to trigger a certain action when +receiving specified IEEE 802.11 frames on the +.Ic hostap interface . +The rules are handled in sequential order, from first to last. +.Pp +In difference to packet filter rules like in +.Xr pf.conf 5 , +the +.Xr hostapd 8 +event rules are handled without a state, +each rule is processed indepedently from the others and from +any previous actions. +.Pp +All hostapd event rules are single line statements beginning with +the mandatory +.Ic hostap handle +keywords and optional rule options, frame matching, +a specified action and a limit. +.Bd -literal -offset indent +.Ar hostap handle [<option>] [<frame>] [<action>] [<limit>] +.Ed +.Pp +The optional parts are defined below: +.Bl -tag -width xxxx +.It Ar <option> +The rule +.Ic option +will modify the behaviour of handling the statement. +There are two possible options, +.Ar quick +and +.Ar skip . +If either the keyword +.Ar quick +or the keyword +.Ar skip +is specified, no further event rules will be handled for this frame +after processing this rule successfully. +The keyword +.Ar skip +additionally skips any further IAPP processing of the frame, +which is normally done after handling the event rules. +.It Ar [<type>] [<subtype>] [<dir>] [<from>] [<to>] [<bssid>] +The +.Ic frame +description specifies a mechanism to match IEEE 802.11 frames. +.It Ar with <action> +An optional +.Ic action +is triggered if a received IEEE 802.11 frame matches the frame +description. The following choice are available as an +.Ic action : +.Bd -literal +.Ar frame <type> <subtype> [<dir>] <from> <to> <bssid> +.Ed +.Pp +.Bd -literal -offset indent +.Ic type : +.Ar type data +.Ar type management +.Ed +.Pp +.Bd -literal -offset indent +.Ic subtype : +.Ar subtype beacon +.Ar subtype deauth [<reason>] +.Ar subtype assoc request +.Ar subtype assoc resp +.Ar subtype atim +.Ar subtype auth +.Ar subtype probe request +.Ar subtype probe resp +.Ar subtype reassoc request +.Ar subtype reassoc response +.Ed +.Pp +.Bd -literal -offset indent +.Ic reason : +.Ar reason assoc leave +.Ar reason assoc not authed +.Ar reason assoc toomany +.Ar reason auth expire +.Ar reason auth leave +.Ar reason ie invalid +.Ar reason mic failure +.Ar reason not authed +.Ar reason not assoced +.Ar reason rsn required +.Ar reason rsn inconsistent +.Ar reason unspecified +.Ed +.Pp +.Bd -literal -offset indent +.Ic dir : +.Ar dir no ds +.Ar dir to ds +.Ar dir from ds +.Ar dir ds to ds +.Ed +.Pp +.Bd -literal -offset indent +.Ic from/to/bssid : +.Ar ( from | to | bssid ) lladdr +.Ar ( from | to | bssid ) &refaddr +.Ed +.Pp +.Bd -literal +.Ar iapp radiotap +.Ar log [verbose] +.Ar node ( add | delete ) <lladdr> +.Ar resend +.Ed +.It Ar limit <number> ( sec | usec ) +It is possible to +.Ic limit +handling of specific rules. +In some cases it is absolutely necessary to use limited matching +to protect +.Xr hostapd 8 +against excessive flooding with IEEE 802.11 frames. +In example, beacon frames will be normally received every 100 ms. +.Pp +.El +.Sh GRAMMAR +Syntax for +.Nm +in BNF: +.Bd -literal +grammar = [ varset ] | [ tabledef ] | option | [ event ] + +varset = varname "=" varvalue + +tabledef = "table" table tableopts + +table = "<" tablename ">" + +tableopts = "const" | "{" [ "\n" ] "}" | + "{" [ "\\n" ] tableaddrlist [ "\\n" ] "}" + +tableaddrlist = lladdr [ "->" ipv4-dotted-quad | "&" lladdr-mask | + "/" number ] [ "," ] [ tableaddrlist ] + +option = "set" ( "hostap" "interface" name | + "iapp" "interface" name [ "passive" ] | + [ "iapp" "mode" ( "multicast" | "broadcast" ] ) + +event = "hostap" "handle" [ eventopt ] [ frmmatch ] [ action ] + [ limit ] + +eventopt = "skip" | "quick" + +action = "with" ( "log" [ "verbose" ] | "frame" frmaction | + "iapp" "type" "radiotap" | + "node" ( "add" | "delete" ) frmactionaddr ) + +frmmatch = [ frmmatchtype ] [ "dir" ( "any" | [ "!" ] frmdir ) ] + [ ( "from" | "to" | "bssid" ) frmmatchaddr ] + +frmmatchtype = "type" ( "any" | [ "!" ] ( "data" | "management" + [ frmmatchmgmt ] ) ) + +frmmatchmgmt = "subtype" ( "any" | [ "!" ] frmsubtype ) + +frmmatchaddr = "any" | [ "!" ] table | [ "!" ] lladdr + +frmaction = frmactiontype [ "dir" frmdir ] + ( "from" , "to" , "bssid" ) frmactionaddr + +frmactiontype = "type" ( "data" | "management" "subtype" frmsubtype ) + +frmactionaddr = lladdr | refaddr + +limit = "limit" number ( "sec" | "usec" ) + +frmsubtype = ( "probe-request" | "probe-resp" | "beacon" ) [ frmelems ] | + "atim" | "auth" | "deauth" | "assoc-request" | "assoc-resp" | + "reassoc-request" | "reassoc-response" + +frmelems = "nwid" [ "!" ] name [ frmelems ] + +frmdir = ( "no" | "to" | "from" | "ds" "to" ) "ds" + +refaddr = "&" ( "from" | "to" | "bssid" ) .Ed +.Sh FILES +.Bl -tag -width "/etc/hostapd.conf" -compact +.It Pa /etc/hostapd.conf +Default location of the configuration file. .El .Sh SEE ALSO .Xr hostapd 8 diff --git a/usr.sbin/hostapd/hostapd.h b/usr.sbin/hostapd/hostapd.h index 9c95bcfc7b6..226d6bc710d 100644 --- a/usr.sbin/hostapd/hostapd.h +++ b/usr.sbin/hostapd/hostapd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: hostapd.h,v 1.2 2005/04/13 18:31:38 henning Exp $ */ +/* $OpenBSD: hostapd.h,v 1.3 2005/06/17 19:13:35 reyk Exp $ */ /* * Copyright (c) 2004, 2005 Reyk Floeter <reyk@vantronix.net> @@ -40,9 +40,6 @@ * hostapd (IAPP) <-> Host AP (APME) */ -#define SIOCS80211IAPP 0 -#define SIOCG80211IAPP 1 - struct hostapd_node { u_int8_t ni_macaddr[IEEE80211_ADDR_LEN]; u_int8_t ni_bssid[IEEE80211_ADDR_LEN]; @@ -71,7 +68,9 @@ enum ieee80211_iapp_frame_type { IEEE80211_IAPP_FRAME_SEND_SECURITY_BLOCK = 3, IEEE80211_IAPP_FRAME_ACK_SECURITY_BLOCK = 4, IEEE80211_IAPP_FRAME_CACHE_NOTIFY = 5, - IEEE80211_IAPP_FRAME_CACHE_RESPONSE = 6 + IEEE80211_IAPP_FRAME_CACHE_RESPONSE = 6, + IEEE80211_IAPP_FRAME_HOSTAPD_RADIOTAP = 12, + IEEE80211_IAPP_FRAME_HOSTAPD_PCAP = 13 }; struct ieee80211_iapp_add_notify { @@ -107,65 +106,239 @@ struct hostapd_counter { u_int64_t cn_tx_apme; /* sent Host AP messages */ }; +#define HOSTAPD_ENTRY_MASK_ADD(_a, _m) do { \ + (_a)[0] &= (_m)[0]; \ + (_a)[1] &= (_m)[1]; \ + (_a)[2] &= (_m)[2]; \ + (_a)[3] &= (_m)[3]; \ + (_a)[4] &= (_m)[4]; \ + (_a)[5] &= (_m)[5]; \ +} while (0); +#define HOSTAPD_ENTRY_MASK_MATCH(_e, _b) ( \ + ((_e)->e_lladdr[0] == ((_b)[0] & (_e)->e_addr.a_mask[0])) && \ + ((_e)->e_lladdr[1] == ((_b)[1] & (_e)->e_addr.a_mask[1])) && \ + ((_e)->e_lladdr[2] == ((_b)[2] & (_e)->e_addr.a_mask[2])) && \ + ((_e)->e_lladdr[3] == ((_b)[3] & (_e)->e_addr.a_mask[3])) && \ + ((_e)->e_lladdr[4] == ((_b)[4] & (_e)->e_addr.a_mask[4])) && \ + ((_e)->e_lladdr[5] == ((_b)[5] & (_e)->e_addr.a_mask[5])) \ +) + +struct hostapd_entry { + u_int8_t e_lladdr[IEEE80211_ADDR_LEN]; + u_int8_t e_flags; + +#define HOSTAPD_ENTRY_F_LLADDR 0x00 +#define HOSTAPD_ENTRY_F_MASK 0x01 +#define HOSTAPD_ENTRY_F_IPV4 0x02 + + union { + u_int8_t a_mask[IEEE80211_ADDR_LEN]; + struct in_addr a_ipv4; + } e_addr; + + TAILQ_ENTRY(hostapd_entry) e_entries; +}; + +#define e_mask e_addr.a_mask +#define e_ipv4 e_addr.a_ipv4 + +#define HOSTAPD_TABLE_NAMELEN 32 +#define HOSTAPD_TABLE_HASHSIZE 256 +#define HOSTAPD_TABLE_HASH(_a) ((((( \ + (0 ^ (_a)[0]) ^ (_a)[1]) ^ (_a)[2]) ^ (_a)[3]) ^ (_a)[4]) ^ (_a)[5] \ +) + +struct hostapd_table { + char t_name[HOSTAPD_TABLE_NAMELEN]; + u_int8_t t_flags; + +#define HOSTAPD_TABLE_F_CONST 0x01 + + TAILQ_HEAD(, hostapd_entry) t_head[HOSTAPD_TABLE_HASHSIZE]; + TAILQ_HEAD(, hostapd_entry) t_mask_head; + TAILQ_ENTRY(hostapd_table) t_entries; +}; + +struct hostapd_ieee80211_frame { + u_int8_t i_fc[2]; + u_int8_t i_dur[2]; + u_int8_t i_from[IEEE80211_ADDR_LEN]; + u_int8_t i_to[IEEE80211_ADDR_LEN]; + u_int8_t i_bssid[IEEE80211_ADDR_LEN]; + u_int8_t i_seq[2]; + void *i_data; + u_int i_data_len; +}; + +enum hostapd_action { + HOSTAPD_ACTION_NONE = 0, + HOSTAPD_ACTION_LOG = 1, + HOSTAPD_ACTION_RADIOTAP = 2, + HOSTAPD_ACTION_FRAME = 3, + HOSTAPD_ACTION_ADDNODE = 4, + HOSTAPD_ACTION_DELNODE = 5, + HOSTAPD_ACTION_RESEND = 6 +}; + +struct hostapd_action_data { + union { + struct hostapd_ieee80211_frame u_frame; + u_int8_t u_lladdr[IEEE80211_ADDR_LEN]; + } a_data; + u_int16_t a_flags; + +#define HOSTAPD_ACTION_F_REF_FROM 0x0001 +#define HOSTAPD_ACTION_F_REF_FROM_M 0x000f +#define HOSTAPD_ACTION_F_REF_FROM_S 0 +#define HOSTAPD_ACTION_F_REF_TO 0x0002 +#define HOSTAPD_ACTION_F_REF_TO_M 0x00f0 +#define HOSTAPD_ACTION_F_REF_TO_S 4 +#define HOSTAPD_ACTION_F_REF_BSSID 0x0004 +#define HOSTAPD_ACTION_F_REF_BSSID_M 0x0f00 +#define HOSTAPD_ACTION_F_REF_BSSID_S 8 +#define HOSTAPD_ACTION_F_REF_M 0x0fff +#define HOSTAPD_ACTION_F_OPT_DIR_AUTO 0x1000 +#define HOSTAPD_ACTION_F_OPT_LLADDR 0x2000 +#define HOSTAPD_ACTION_F_OPT_TABLE 0x4000 +}; + +#define a_frame a_data.u_frame +#define a_lladdr a_data.u_lladdr + +struct hostapd_frame { + struct hostapd_ieee80211_frame f_frame; + u_int32_t f_flags; + +#define HOSTAPD_FRAME_F_TYPE 0x00000001 +#define HOSTAPD_FRAME_F_TYPE_N 0x00000002 +#define HOSTAPD_FRAME_F_SUBTYPE 0x00000004 +#define HOSTAPD_FRAME_F_SUBTYPE_N 0x00000008 +#define HOSTAPD_FRAME_F_DIR 0x00000010 +#define HOSTAPD_FRAME_F_DIR_N 0x00000020 +#define HOSTAPD_FRAME_F_FROM 0x00000040 +#define HOSTAPD_FRAME_F_FROM_N 0x00000080 +#define HOSTAPD_FRAME_F_FROM_TABLE 0x00000100 +#define HOSTAPD_FRAME_F_FROM_M 0x000001c0 +#define HOSTAPD_FRAME_F_TO 0x00000200 +#define HOSTAPD_FRAME_F_TO_N 0x00000400 +#define HOSTAPD_FRAME_F_TO_TABLE 0x00000800 +#define HOSTAPD_FRAME_F_TO_M 0x00000e00 +#define HOSTAPD_FRAME_F_BSSID 0x00001000 +#define HOSTAPD_FRAME_F_BSSID_N 0x00002000 +#define HOSTAPD_FRAME_F_BSSID_TABLE 0x00004000 +#define HOSTAPD_FRAME_F_BSSID_M 0x00007000 +#define HOSTAPD_FRAME_F_M 0x0fffffff +#define HOSTAPD_FRAME_F_RET_OK 0x00000000 +#define HOSTAPD_FRAME_F_RET_QUICK 0x10000000 +#define HOSTAPD_FRAME_F_RET_SKIP 0x20000000 +#define HOSTAPD_FRAME_F_RET_M 0xf0000000 +#define HOSTAPD_FRAME_F_RET_S 28 + +#define HOSTAPD_FRAME_TABLE \ + (HOSTAPD_FRAME_F_FROM_TABLE | HOSTAPD_FRAME_F_TO_TABLE | \ + HOSTAPD_FRAME_F_BSSID_TABLE) +#define HOSTAPD_FRAME_N \ + (HOSTAPD_FRAME_F_FROM_N | HOSTAPD_FRAME_F_TO_N | \ + HOSTAPD_FRAME_F_BSSID_N) + + struct hostapd_table *f_from, *f_to, *f_bssid; + struct timeval f_limit, f_then; + + enum hostapd_action f_action; + u_int32_t f_action_flags; + +#define HOSTAPD_ACTION_VERBOSE 0x00000001 + + struct hostapd_action_data f_action_data; + + TAILQ_ENTRY(hostapd_frame) f_entries; +}; + struct hostapd_config { - int c_apme; - int c_apme_raw; - u_int c_apme_rawlen; - struct event c_apme_ev; - char c_apme_iface[IFNAMSIZ]; - int c_apme_n; - u_int8_t c_apme_bssid[IEEE80211_ADDR_LEN]; - - u_int16_t c_iapp; - int c_iapp_raw; - char c_iapp_iface[IFNAMSIZ]; - int c_iapp_udp; - struct event c_iapp_udp_ev; - u_int16_t c_iapp_udp_port; - struct sockaddr_in c_iapp_addr; - struct sockaddr_in c_iapp_broadcast; - struct sockaddr_in c_iapp_multicast; - - u_int8_t c_flags; - -#define HOSTAPD_CFG_F_APME 0x01 -#define HOSTAPD_CFG_F_IAPP 0x02 -#define HOSTAPD_CFG_F_RAW 0x04 -#define HOSTAPD_CFG_F_UDP 0x08 -#define HOSTAPD_CFG_F_BRDCAST 0x10 -#define HOSTAPD_CFG_F_PRIV 0x20 - - struct event c_priv_ev; - - char c_config[MAXPATHLEN]; - - u_int c_verbose; - u_int c_debug; - - struct hostapd_counter c_stats; + int c_apme; + int c_apme_raw; + u_int c_apme_rawlen; + struct event c_apme_ev; + char c_apme_iface[IFNAMSIZ]; + int c_apme_n; + u_int8_t c_apme_bssid[IEEE80211_ADDR_LEN]; + u_int c_apme_dlt; + + u_int16_t c_iapp; + int c_iapp_raw; + char c_iapp_iface[IFNAMSIZ]; + int c_iapp_udp; + struct event c_iapp_udp_ev; + u_int16_t c_iapp_udp_port; + struct sockaddr_in c_iapp_addr; + struct sockaddr_in c_iapp_broadcast; + struct sockaddr_in c_iapp_multicast; + + u_int8_t c_flags; + +#define HOSTAPD_CFG_F_APME 0x01 +#define HOSTAPD_CFG_F_IAPP 0x02 +#define HOSTAPD_CFG_F_IAPP_PASSIVE 0x04 +#define HOSTAPD_CFG_F_RAW 0x08 +#define HOSTAPD_CFG_F_UDP 0x10 +#define HOSTAPD_CFG_F_BRDCAST 0x20 +#define HOSTAPD_CFG_F_PRIV 0x40 + + struct event c_priv_ev; + + char c_config[MAXPATHLEN]; + + u_int c_verbose; + u_int c_debug; + u_int c_id; + + struct hostapd_counter c_stats; + + TAILQ_HEAD(, hostapd_table) c_tables; + TAILQ_HEAD(, hostapd_frame) c_frames; }; #define IAPP_PORT 3517 /* XXX this should be added to /etc/services */ #define IAPP_MCASTADDR "224.0.1.178" -#define IAPP_DLT DLT_IEEE802_11 #define IAPP_MAXSIZE 512 #define HOSTAPD_USER "_hostapd" - #define HOSTAPD_CONFIG "/etc/hostapd.conf" +#define HOSTAPD_DLT DLT_IEEE802_11 #define HOSTAPD_LOG 0 #define HOSTAPD_LOG_VERBOSE 1 #define HOSTAPD_LOG_DEBUG 2 +#define PRINTF hostapd_printf +#define etheraddr_string(_s) ether_ntoa((struct ether_addr*)_s) +#define TTEST2(var, l) ( \ + snapend - (l) <= snapend && (const u_char *)&(var) <= snapend - (l) \ +) +#define TTEST(var) TTEST2(var, sizeof(var)) +#define TCHECK2(var, l) if (!TTEST2(var, l)) goto trunc +#define TCHECK(var) TCHECK2(var, sizeof(var)) + __BEGIN_DECLS void hostapd_log(u_int, const char *, ...); +void hostapd_printf(const char *, ...); void hostapd_fatal(const char *, ...); int hostapd_bpf_open(u_int); void hostapd_cleanup(struct hostapd_config *); int hostapd_check_file_secrecy(int, const char *); +struct hostapd_table *hostapd_table_add(struct hostapd_config *, + const char *); +struct hostapd_table *hostapd_table_lookup(struct hostapd_config *, + const char *); +struct hostapd_entry *hostapd_entry_add(struct hostapd_table *, + u_int8_t *); +struct hostapd_entry *hostapd_entry_lookup(struct hostapd_table *, + u_int8_t *); +void hostapd_entry_update(struct hostapd_table *, + struct hostapd_entry *); + int hostapd_parse_file(struct hostapd_config *); int hostapd_parse_symset(char *); @@ -174,21 +347,35 @@ int hostapd_priv_llc_xid(struct hostapd_config *, struct hostapd_node *); void hostapd_priv_apme_bssid(struct hostapd_config *); int hostapd_priv_apme_getnode(struct hostapd_config *, struct hostapd_node *); -int hostapd_priv_apme_delnode(struct hostapd_config *, - struct hostapd_node *); +int hostapd_priv_apme_setnode(struct hostapd_config *, + struct hostapd_node *node, int); void hostapd_apme_init(struct hostapd_config *); void hostapd_apme_input(int, short, void *); +int hostapd_apme_output(struct hostapd_config *, + struct hostapd_ieee80211_frame *); +int hostapd_apme_addnode(struct hostapd_config *, + struct hostapd_node *node); +int hostapd_apme_delnode(struct hostapd_config *, + struct hostapd_node *node); +int hostapd_apme_offset(struct hostapd_config *, u_int8_t *, + const u_int); void hostapd_iapp_init(struct hostapd_config *); void hostapd_iapp_term(struct hostapd_config *); int hostapd_iapp_add_notify(struct hostapd_config *, struct hostapd_node *); +int hostapd_iapp_radiotap(struct hostapd_config *, + u_int8_t *, const u_int); void hostapd_iapp_input(int, short, void *); void hostapd_llc_init(struct hostapd_config *); int hostapd_llc_send_xid(struct hostapd_config *, struct hostapd_node *); +int hostapd_handle_input(struct hostapd_config *, u_int8_t *, u_int); + +void hostapd_print_ieee80211(u_int, u_int, u_int8_t *, u_int); + __END_DECLS #endif /* _HOSTAPD_H */ diff --git a/usr.sbin/hostapd/iapp.c b/usr.sbin/hostapd/iapp.c index 5605b29a0b3..ef3ad3bf46a 100644 --- a/usr.sbin/hostapd/iapp.c +++ b/usr.sbin/hostapd/iapp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: iapp.c,v 1.4 2005/04/13 21:02:44 moritz Exp $ */ +/* $OpenBSD: iapp.c,v 1.5 2005/06/17 19:13:35 reyk Exp $ */ /* * Copyright (c) 2004, 2005 Reyk Floeter <reyk@vantronix.net> @@ -21,6 +21,7 @@ #include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> +#include <sys/uio.h> #include <net/if.h> #include <net/if_dl.h> @@ -50,9 +51,9 @@ hostapd_iapp_init(struct hostapd_config *cfg) hostapd_priv_apme_bssid(cfg); hostapd_log(HOSTAPD_LOG_VERBOSE, - "%s/%s: attaching to Host AP with BSSID \"%s\"\n", - cfg->c_apme_iface, cfg->c_iapp_iface, - ether_ntoa((struct ether_addr *)cfg->c_apme_bssid)); + "%s: attaching to Host AP %s with BSSID \"%s\"\n", + cfg->c_iapp_iface, cfg->c_apme_iface, + etheraddr_string(cfg->c_apme_bssid)); } void @@ -62,8 +63,8 @@ hostapd_iapp_term(struct hostapd_config *cfg) return; /* XXX not yet used but inspired by the APME TERMINATE action */ - hostapd_log(HOSTAPD_LOG_VERBOSE, "%s/%s: detaching from Host AP\n", - cfg->c_apme_iface, cfg->c_iapp_iface); + hostapd_log(HOSTAPD_LOG_VERBOSE, "%s: detaching from Host AP %s\n", + cfg->c_iapp_iface, cfg->c_apme_iface); } int @@ -84,6 +85,7 @@ hostapd_iapp_add_notify(struct hostapd_config *cfg, struct hostapd_node *node) frame.hdr.i_version = IEEE80211_IAPP_VERSION; frame.hdr.i_command = IEEE80211_IAPP_FRAME_ADD_NOTIFY; frame.hdr.i_identifier = htons(cfg->c_iapp++); + frame.hdr.i_length = sizeof(struct ieee80211_iapp_add_notify); frame.add.a_length = IEEE80211_ADDR_LEN; frame.add.a_seqnum = htons(node->ni_rxseq); @@ -97,34 +99,90 @@ hostapd_iapp_add_notify(struct hostapd_config *cfg, struct hostapd_node *node) if (sendto(cfg->c_iapp_udp, &frame, sizeof(frame), 0, (struct sockaddr *)addr, sizeof(struct sockaddr_in)) == -1) { hostapd_log(HOSTAPD_LOG, - "%s/%s: failed to send ADD notification: %s\n", - cfg->c_apme_iface, cfg->c_iapp_iface, - strerror(errno)); + "%s: failed to send ADD notification: %s\n", + cfg->c_iapp_iface, strerror(errno)); return (errno); } - hostapd_log(HOSTAPD_LOG, "%s/%s: sent ADD notification for %s\n", - cfg->c_apme_iface, cfg->c_iapp_iface, - ether_ntoa((struct ether_addr*)frame.add.a_macaddr)); + hostapd_log(HOSTAPD_LOG, "%s: sent ADD notification for %s\n", + cfg->c_iapp_iface, etheraddr_string(frame.add.a_macaddr)); /* Send a LLC XID frame, see llc.c for details */ return (hostapd_priv_llc_xid(cfg, node)); } +int +hostapd_iapp_radiotap(struct hostapd_config *cfg, u_int8_t *buf, + const u_int len) +{ + struct sockaddr_in *addr; + struct ieee80211_iapp_frame hdr; + struct msghdr msg; + struct iovec iov[2]; + + /* + * Send an HOSTAPD.pcap/radiotap message to other accesspoints with + * with an appaneded network dump. This is an hostapd extension to + * IAPP. + */ + bzero(&hdr, sizeof(hdr)); + + hdr.i_version = IEEE80211_IAPP_VERSION; + if (cfg->c_apme_dlt == DLT_IEEE802_11_RADIO) + hdr.i_command = IEEE80211_IAPP_FRAME_HOSTAPD_RADIOTAP; + else if (cfg->c_apme_dlt == DLT_IEEE802_11) + hdr.i_command = IEEE80211_IAPP_FRAME_HOSTAPD_PCAP; + else + return (EINVAL); + hdr.i_identifier = htons(cfg->c_iapp++); + hdr.i_length = len; + + if (cfg->c_flags & HOSTAPD_CFG_F_BRDCAST) + addr = &cfg->c_iapp_broadcast; + else + addr = &cfg->c_iapp_multicast; + + iov[0].iov_base = &hdr; + iov[0].iov_len = sizeof(hdr); + iov[1].iov_base = buf; + iov[1].iov_len = len; + msg.msg_name = (caddr_t)addr; + msg.msg_namelen = sizeof(struct sockaddr_in); + msg.msg_iov = iov; + msg.msg_iovlen = 2; + msg.msg_control = 0; + msg.msg_controllen = 0; + msg.msg_flags = 0; + + if (sendmsg(cfg->c_iapp_udp, &msg, 0) == -1) { + hostapd_log(HOSTAPD_LOG, + "%s: failed to send HOSTAPD %s: %s\n", + cfg->c_iapp_iface, cfg->c_apme_dlt == + DLT_IEEE802_11_RADIO ? "radiotap" : "pcap", + strerror(errno)); + return (errno); + } + + return (0); +} + void hostapd_iapp_input(int fd, short sig, void *arg) { struct hostapd_config *cfg = (struct hostapd_config *)arg; struct sockaddr_in addr; socklen_t addr_len; + ssize_t len; u_int8_t buf[IAPP_MAXSIZE]; struct hostapd_node node; struct ieee80211_iapp_recv { struct ieee80211_iapp_frame hdr; union { struct ieee80211_iapp_add_notify add; + u_int8_t buf[1]; } u; } __packed *frame; + u_int dlt; int ret = 0; /* Ignore invalid signals */ @@ -136,18 +194,19 @@ hostapd_iapp_input(int fd, short sig, void *arg) */ bzero(buf, sizeof(buf)); - if (recvfrom(fd, buf, sizeof(buf), 0, - (struct sockaddr*)&addr, &addr_len) < 1) + if ((len = recvfrom(fd, buf, sizeof(buf), 0, + (struct sockaddr*)&addr, &addr_len)) < 1) return; - if (memcmp(&cfg->c_iapp_addr.sin_addr, &addr.sin_addr, + if (bcmp(&cfg->c_iapp_addr.sin_addr, &addr.sin_addr, sizeof(addr.sin_addr)) == 0) return; frame = (struct ieee80211_iapp_recv*)buf; /* Validate the IAPP version */ - if (frame->hdr.i_version != IEEE80211_IAPP_VERSION || + if (len < (ssize_t)sizeof(struct ieee80211_iapp_frame) || + frame->hdr.i_version != IEEE80211_IAPP_VERSION || addr_len < sizeof(struct sockaddr_in)) return; @@ -158,6 +217,11 @@ hostapd_iapp_input(int fd, short sig, void *arg) */ switch (frame->hdr.i_command) { case IEEE80211_IAPP_FRAME_ADD_NOTIFY: + /* Short frame */ + if (len < (ssize_t)(sizeof(struct ieee80211_iapp_frame) + + sizeof(struct ieee80211_iapp_add_notify))) + return; + /* Don't support non-48bit MAC addresses, yet */ if (frame->u.add.a_length != IEEE80211_ADDR_LEN) return; @@ -171,19 +235,35 @@ hostapd_iapp_input(int fd, short sig, void *arg) * any allocated resources. Otherwise the received * ADD.notify message will be ignored. */ - if (cfg->c_flags & HOSTAPD_CFG_F_APME) - ret = hostapd_priv_apme_delnode(cfg, &node); - else + if (cfg->c_flags & HOSTAPD_CFG_F_APME) { + if ((ret = hostapd_apme_delnode(cfg, &node)) == 0) + cfg->c_stats.cn_tx_apme++; + } else ret = 0; - hostapd_log(HOSTAPD_LOG, "%s/%s: %s ADD notification " + hostapd_log(HOSTAPD_LOG, "%s: %s ADD notification " "for %s at %s\n", - cfg->c_apme_iface, cfg->c_iapp_iface, - ret == 0 ? "received" : "ignored", - ether_ntoa((struct ether_addr*)node.ni_macaddr), + cfg->c_apme_iface, ret == 0 ? + "received" : "ignored", + etheraddr_string(node.ni_macaddr), inet_ntoa(addr.sin_addr)); break; + case IEEE80211_IAPP_FRAME_HOSTAPD_PCAP: + case IEEE80211_IAPP_FRAME_HOSTAPD_RADIOTAP: + /* Short frame */ + if (len <= (ssize_t)sizeof(struct ieee80211_iapp_frame) || + frame->hdr.i_length < sizeof(struct ieee80211_frame)) + return; + + dlt = frame->hdr.i_command == + IEEE80211_IAPP_FRAME_HOSTAPD_PCAP ? + DLT_IEEE802_11 : DLT_IEEE802_11_RADIO; + + hostapd_print_ieee80211(dlt, 1, (u_int8_t *)frame->u.buf, + len - sizeof(struct ieee80211_iapp_frame)); + return; + case IEEE80211_IAPP_FRAME_MOVE_NOTIFY: case IEEE80211_IAPP_FRAME_MOVE_RESPONSE: case IEEE80211_IAPP_FRAME_SEND_SECURITY_BLOCK: @@ -196,9 +276,8 @@ hostapd_iapp_input(int fd, short sig, void *arg) */ hostapd_log(HOSTAPD_LOG_VERBOSE, - "%s/%s: received unsupported IAPP message %d\n", - cfg->c_apme_iface, cfg->c_iapp_iface, - frame->hdr.i_command); + "%s: received unsupported IAPP message %d\n", + cfg->c_iapp_iface, frame->hdr.i_command); return; default: diff --git a/usr.sbin/hostapd/parse.y b/usr.sbin/hostapd/parse.y index 6736661c0c9..90ec3b41536 100644 --- a/usr.sbin/hostapd/parse.y +++ b/usr.sbin/hostapd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.4 2005/04/13 19:06:08 henning Exp $ */ +/* $OpenBSD: parse.y,v 1.5 2005/06/17 19:13:35 reyk Exp $ */ /* * Copyright (c) 2004, 2005 Reyk Floeter <reyk@vantronix.net> @@ -81,18 +81,51 @@ char *symget(const char *); typedef struct { union { - char *string; - int val; + struct { + u_int8_t lladdr[IEEE80211_ADDR_LEN]; + struct hostapd_table *table; + u_int32_t flags; + } reflladdr __packed; + struct in_addr in; + char *string; + long val; + u_int16_t reason; } v; int lineno; } YYSTYPE; +struct hostapd_table *table; +struct hostapd_entry *entry; +struct hostapd_frame frame, *frame_ptr; +struct hostapd_ieee80211_frame *frame_ieee80211; +u_int negative; + +#define HOSTAPD_MATCH(_m) { \ + frame.f_flags |= negative ? \ + HOSTAPD_FRAME_F_##_m##_N : HOSTAPD_FRAME_F_##_m; \ + negative = 0; \ +} +#define HOSTAPD_MATCH_TABLE(_m) { \ + frame.f_flags |= HOSTAPD_FRAME_F_##_m##_TABLE | (negative ? \ + HOSTAPD_FRAME_F_##_m##_N : HOSTAPD_FRAME_F_##_m); \ + negative = 0; \ +} %} -%token MODE INTERFACE IAPP HOSTAP MULTICAST BROADCAST SET -%token ERROR +%token MODE INTERFACE IAPP HOSTAP MULTICAST BROADCAST SET SEC USEC +%token HANDLE TYPE SUBTYPE FROM TO BSSID WITH FRAME RADIOTAP NWID PASSIVE +%token MANAGEMENT DATA PROBE BEACON ATIM ANY DS NO DIR RESEND +%token AUTH DEAUTH ASSOC DISASSOC REASSOC REQUEST RESPONSE PCAP +%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 %token <v.string> STRING %token <v.val> VALUE +%type <v.val> number +%type <v.in> ipv4addr +%type <v.reflladdr> refaddr, lladdr, frmactionaddr, frmmatchaddr +%type <v.reason> frmreason +%type <v.string> table %type <v.string> string %% @@ -103,7 +136,9 @@ typedef struct { grammar : /* empty */ | grammar '\n' + | grammar tabledef '\n' | grammar option '\n' + | grammar event '\n' | grammar varset '\n' | grammar error '\n' { errors++; } ; @@ -121,7 +156,8 @@ option : SET HOSTAP INTERFACE STRING free($4); } - | SET IAPP INTERFACE STRING + | SET HOSTAP MODE hostapmode + | SET IAPP INTERFACE STRING passive { strlcpy(hostapd_cfg.c_iapp_iface, $4, sizeof(hostapd_cfg.c_iapp_iface)); @@ -133,17 +169,502 @@ option : SET HOSTAP INTERFACE STRING free($4); } - | SET IAPP MODE MULTICAST + | SET IAPP MODE iappmode + ; + +iappmode : MULTICAST { hostapd_cfg.c_flags &= ~HOSTAPD_CFG_F_BRDCAST; } - | SET IAPP MODE BROADCAST + | BROADCAST { hostapd_cfg.c_flags |= HOSTAPD_CFG_F_BRDCAST; } ; -string : string STRING { +hostapmode : RADIOTAP + { + hostapd_cfg.c_apme_dlt = DLT_IEEE802_11_RADIO; + } + | PCAP + { + hostapd_cfg.c_apme_dlt = DLT_IEEE802_11; + } + ; + +event : HOSTAP HANDLE + { + bzero(&frame, sizeof(struct hostapd_frame)); + /* IEEE 802.11 frame to match */ + frame_ieee80211 = &frame.f_frame; + } eventopt frmmatch { + /* IEEE 802.11 raw frame to send as an action */ + frame_ieee80211 = &frame.f_action_data.a_frame; + } action limit { + struct timeval t_now; + + if ((frame_ptr = (struct hostapd_frame *)calloc(1, + sizeof(struct hostapd_frame))) == NULL) { + yyerror("calloc"); + YYERROR; + } + + gettimeofday(&t_now, NULL); + timeradd(&t_now, &frame.f_limit, &frame.f_then); + + bcopy(&frame, frame_ptr, sizeof(struct hostapd_frame)); + TAILQ_INSERT_TAIL(&hostapd_cfg.c_frames, + frame_ptr, f_entries); + } + ; + +eventopt : /* empty */ + { + frame.f_flags |= HOSTAPD_FRAME_F_RET_OK; + } + | QUICK + { + frame.f_flags |= HOSTAPD_FRAME_F_RET_QUICK; + } + | SKIP + { + frame.f_flags |= HOSTAPD_FRAME_F_RET_SKIP; + } + ; + +action : /* empty */ + { + frame.f_action = HOSTAPD_ACTION_NONE; + } + | WITH LOG verbose + { + frame.f_action = HOSTAPD_ACTION_LOG; + } + | WITH FRAME frmaction + { + frame.f_action = HOSTAPD_ACTION_FRAME; + } + | WITH IAPP iapp + | WITH NODE nodeopt frmactionaddr + { + if (($4.flags & HOSTAPD_ACTION_F_REF_M) == 0) { + bcopy($4.lladdr, frame.f_action_data.a_lladdr, + IEEE80211_ADDR_LEN); + } else + frame.f_action_data.a_flags |= $4.flags; + } + | WITH RESEND + { + frame.f_action = HOSTAPD_ACTION_RESEND; + } + ; + +verbose : /* empty */ + | VERBOSE + { + frame.f_action_flags |= HOSTAPD_ACTION_VERBOSE; + } + ; + +iapp : TYPE RADIOTAP verbose + { + frame.f_action = HOSTAPD_ACTION_RADIOTAP; + } + ; + +nodeopt : DELETE + { + frame.f_action = HOSTAPD_ACTION_DELNODE; + } + | ADD + { + frame.f_action = HOSTAPD_ACTION_ADDNODE; + } + ; + +frmmatch : frmmatchtype frmmatchdir frmmatchfrom frmmatchto frmmatchbssid + ; + +frmaction : frmactiontype frmactiondir frmactionfrom frmactionto frmactionbssid + ; + +limit : /* empty */ + | LIMIT number SEC + { + frame.f_limit.tv_sec = $2; + } + | LIMIT number USEC + { + frame.f_limit.tv_usec = $2; + } + ; + +frmmatchtype : /* any */ + | TYPE ANY + | TYPE not DATA + { + frame_ieee80211->i_fc[0] |= + IEEE80211_FC0_TYPE_DATA; + HOSTAPD_MATCH(TYPE); + } + | TYPE not MANAGEMENT frmmatchmgmt + { + frame_ieee80211->i_fc[0] |= + IEEE80211_FC0_TYPE_MGT; + HOSTAPD_MATCH(TYPE); + } + ; + +frmmatchmgmt : /* any */ + | SUBTYPE ANY + | SUBTYPE not frmsubtype + { + HOSTAPD_MATCH(SUBTYPE); + } + ; + +frmsubtype : PROBE REQUEST frmelems + { + frame_ieee80211->i_fc[0] |= + IEEE80211_FC0_SUBTYPE_PROBE_REQ; + } + | PROBE RESPONSE frmelems + { + frame_ieee80211->i_fc[0] |= + IEEE80211_FC0_SUBTYPE_PROBE_RESP; + } + | BEACON frmelems + { + frame_ieee80211->i_fc[0] |= + IEEE80211_FC0_SUBTYPE_BEACON; + } + | ATIM + { + frame_ieee80211->i_fc[0] |= + IEEE80211_FC0_SUBTYPE_ATIM; + } + | AUTH + { + frame_ieee80211->i_fc[0] |= + IEEE80211_FC0_SUBTYPE_AUTH; + } + | DEAUTH frmreason + { + frame_ieee80211->i_fc[0] |= + IEEE80211_FC0_SUBTYPE_DEAUTH; + + if ($2 != 0) { + if ((frame_ieee80211->i_data = (u_int16_t *) + malloc(sizeof(u_int16_t))) == NULL) { + yyerror("failed to allocate deauth" + " reason code %u", $2); + YYERROR; + } + *(u_int16_t *)frame_ieee80211->i_data = + htole16($2); + frame_ieee80211->i_data_len = sizeof(u_int16_t); + } + } + | ASSOC REQUEST + { + frame_ieee80211->i_fc[0] |= + IEEE80211_FC0_SUBTYPE_ASSOC_REQ; + } + | DISASSOC + { + frame_ieee80211->i_fc[0] |= + IEEE80211_FC0_SUBTYPE_DISASSOC; + } + | ASSOC RESPONSE + { + frame_ieee80211->i_fc[0] |= + IEEE80211_FC0_SUBTYPE_ASSOC_RESP; + } + | REASSOC REQUEST + { + frame_ieee80211->i_fc[0] |= + IEEE80211_FC0_SUBTYPE_REASSOC_REQ; + } + | REASSOC RESPONSE + { + frame_ieee80211->i_fc[0] |= + IEEE80211_FC0_SUBTYPE_REASSOC_RESP; + } + ; + +frmelems : /* empty */ + | frmelems_l + ; + +frmelems_l : frmelems_l frmelem + | frmelem + ; + +frmelem : NWID not STRING + ; + +frmreason : /* empty */ + { + $$ = 0; + } + | REASON UNSPECIFIED + { + $$ = IEEE80211_REASON_UNSPECIFIED; + } + | REASON AUTH EXPIRE + { + $$ = IEEE80211_REASON_AUTH_EXPIRE; + } + | REASON AUTH LEAVE + { + $$ = IEEE80211_REASON_AUTH_LEAVE; + } + | REASON ASSOC EXPIRE + { + $$ = IEEE80211_REASON_ASSOC_EXPIRE; + } + | REASON ASSOC TOOMANY + { + $$ = IEEE80211_REASON_ASSOC_TOOMANY; + } + | REASON NOT AUTHED + { + $$ = IEEE80211_REASON_NOT_AUTHED; + } + | REASON NOT ASSOCED + { + $$ = IEEE80211_REASON_NOT_ASSOCED; + } + | REASON ASSOC LEAVE + { + $$ = IEEE80211_REASON_ASSOC_LEAVE; + } + | REASON ASSOC NOT AUTHED + { + $$ = IEEE80211_REASON_NOT_AUTHED; + } + | REASON RESERVED + { + $$ = 10; /* XXX unknown */ + } + | REASON RSN REQUIRED + { + $$ = IEEE80211_REASON_RSN_REQUIRED; + } + | REASON RSN INCONSISTENT + { + $$ = IEEE80211_REASON_RSN_INCONSISTENT; + } + | REASON IE INVALID + { + $$ = IEEE80211_REASON_IE_INVALID; + } + | REASON MIC FAILURE + { + $$ = IEEE80211_REASON_MIC_FAILURE; + } + ; + +frmmatchdir : /* any */ + | DIR ANY + | DIR frmdir + { + HOSTAPD_MATCH(DIR); + } + ; + +frmdir : NO DS + { + frame_ieee80211->i_fc[1] |= IEEE80211_FC1_DIR_NODS; + } + | TO DS + { + frame_ieee80211->i_fc[1] |= IEEE80211_FC1_DIR_TODS; + } + | FROM DS + { + frame_ieee80211->i_fc[1] |= IEEE80211_FC1_DIR_FROMDS; + } + | DS TO DS + { + frame_ieee80211->i_fc[1] |= IEEE80211_FC1_DIR_DSTODS; + } + ; + +frmmatchfrom : /* any */ + | FROM frmmatchaddr + { + if (($2.flags & HOSTAPD_ACTION_F_OPT_TABLE) == 0) { + bcopy($2.lladdr, &frame_ieee80211->i_from, + IEEE80211_ADDR_LEN); + HOSTAPD_MATCH(FROM); + } else { + frame.f_from = $2.table; + HOSTAPD_MATCH_TABLE(FROM); + } + } + ; + +frmmatchto : /* any */ + | TO frmmatchaddr + { + if (($2.flags & HOSTAPD_ACTION_F_OPT_TABLE) == 0) { + bcopy($2.lladdr, &frame_ieee80211->i_to, + IEEE80211_ADDR_LEN); + HOSTAPD_MATCH(TO); + } else { + frame.f_to = $2.table; + HOSTAPD_MATCH_TABLE(TO); + } + } + ; + +frmmatchbssid : /* any */ + | BSSID frmmatchaddr + { + if (($2.flags & HOSTAPD_ACTION_F_OPT_TABLE) == 0) { + bcopy($2.lladdr, &frame_ieee80211->i_bssid, + IEEE80211_ADDR_LEN); + HOSTAPD_MATCH(BSSID); + } else { + frame.f_bssid = $2.table; + HOSTAPD_MATCH_TABLE(BSSID); + } + } + ; + +frmmatchaddr : ANY + { + $$.flags = 0; + } + | not table + { + if (($$.table = + hostapd_table_lookup(&hostapd_cfg, $2)) == NULL) { + yyerror("undefined table <%s>", $2); + free($2); + YYERROR; + } + $$.flags = HOSTAPD_ACTION_F_OPT_TABLE; + free($2); + } + | not lladdr + { + bcopy($2.lladdr, $$.lladdr, IEEE80211_ADDR_LEN); + $$.flags = HOSTAPD_ACTION_F_OPT_TABLE; + } + ; + +frmactiontype : TYPE DATA + { + frame_ieee80211->i_fc[0] |= IEEE80211_FC0_TYPE_DATA; + } + | TYPE MANAGEMENT frmactionmgmt + { + frame_ieee80211->i_fc[0] |= IEEE80211_FC0_TYPE_MGT; + } + ; + +frmactionmgmt : SUBTYPE frmsubtype + ; + +frmactiondir : /* empty */ + { + frame.f_action_data.a_flags |= + HOSTAPD_ACTION_F_OPT_DIR_AUTO; + } + | DIR frmdir + ; + +frmactionfrom : FROM frmactionaddr + { + if (($2.flags & HOSTAPD_ACTION_F_REF_M) == 0) { + bcopy($2.lladdr, frame_ieee80211->i_from, + IEEE80211_ADDR_LEN); + } else + frame.f_action_data.a_flags |= + ($2.flags << HOSTAPD_ACTION_F_REF_FROM_S); + } + ; + +frmactionto : TO frmactionaddr + { + if (($2.flags & HOSTAPD_ACTION_F_REF_M) == 0) { + bcopy($2.lladdr, frame_ieee80211->i_to, + IEEE80211_ADDR_LEN); + } else + frame.f_action_data.a_flags |= + ($2.flags << HOSTAPD_ACTION_F_REF_TO_S); + } + ; + +frmactionbssid : BSSID frmactionaddr + { + if (($2.flags & HOSTAPD_ACTION_F_REF_M) == 0) { + bcopy($2.lladdr, frame_ieee80211->i_bssid, + IEEE80211_ADDR_LEN); + } else + frame.f_action_data.a_flags |= + ($2.flags << HOSTAPD_ACTION_F_REF_BSSID_S); + } + ; + +frmactionaddr : lladdr + { + bcopy($1.lladdr, $$.lladdr, IEEE80211_ADDR_LEN); + $$.flags = 0; + } + | refaddr + { + $$.flags = $1.flags; + } + ; + +table : '<' STRING '>' { + if (strlen($2) >= HOSTAPD_TABLE_NAMELEN) { + yyerror("table name %s too long, max %u", + $2, HOSTAPD_TABLE_NAMELEN - 1); + free($2); + YYERROR; + } + $$ = $2; + } + ; + +tabledef : TABLE table { + if ((table = + hostapd_table_add(&hostapd_cfg, $2)) == NULL) { + yyerror("failed to add table: %s", $2); + free($2); + YYERROR; + } + free($2); + } tableopts { + table = NULL; + } + ; + +tableopts : /* empty */ + | tableopts_l + ; + +tableopts_l : tableopts_l tableopt + | tableopt + ; + +tableopt : CONST { + if (table->t_flags & HOSTAPD_TABLE_F_CONST) { + yyerror("option already specified"); + YYERROR; + } + table->t_flags |= HOSTAPD_TABLE_F_CONST; + } + | '{' optnl '}' + | '{' optnl tableaddrlist optnl '}' + ; + +string : string STRING + { if (asprintf(&$$, "%s %s", $1, $2) == -1) hostapd_fatal("string: asprintf"); free($1); @@ -161,6 +682,115 @@ varset : STRING '=' string } ; +refaddr : '&' FROM + { + $$.flags |= HOSTAPD_ACTION_F_REF_FROM; + } + | '&' TO + { + $$.flags |= HOSTAPD_ACTION_F_REF_TO; + } + | '&' BSSID + { + $$.flags |= HOSTAPD_ACTION_F_REF_BSSID; + } + ; + +tableaddrlist : tableaddrentry + | tableaddrlist comma tableaddrentry + ; + +tableaddrentry : lladdr + { + if ((entry = hostapd_entry_add(table, + $1.lladdr)) == NULL) { + yyerror("failed to add entry: %s", + etheraddr_string($1.lladdr)); + YYERROR; + } + } tableaddropt { + entry = NULL; + } + ; + +tableaddropt : /* empty */ + | assign ipv4addr + { + entry->e_flags |= HOSTAPD_ENTRY_F_IPV4; + bcopy(&$2, &entry->e_ipv4, sizeof(struct in_addr)); + } + | mask lladdr + { + entry->e_flags |= HOSTAPD_ENTRY_F_MASK; + bcopy($2.lladdr, entry->e_mask, IEEE80211_ADDR_LEN); + + /* Update entry position in the table */ + hostapd_entry_update(table, entry); + } + ; + +ipv4addr : STRING + { + if (inet_net_pton(AF_INET, $1, &$$, sizeof($$)) == -1) { + yyerror("invalid address: %s\n", $1); + free($1); + YYERROR; + } + free($1); + } + ; + +lladdr : STRING + { + struct ether_addr *ea; + + if ((ea = ether_aton($1)) == NULL) { + yyerror("invalid address: %s\n", $1); + free($1); + YYERROR; + } + free($1); + + bcopy(ea, $$.lladdr, IEEE80211_ADDR_LEN); + $$.flags = 0; + } + ; + +number : STRING + { + $$ = strtonum($1, 0, 1 << sizeof(long), NULL); + free($1); + } + ; + +passive : /* empty */ + | PASSIVE + { + hostapd_cfg.c_flags |= HOSTAPD_CFG_F_IAPP_PASSIVE; + } + ; + +assign : '-' '>' + ; + +mask : '&' + ; + +comma : /* emtpy */ + | ',' optnl + ; + +optnl : /* empty */ + | '\n' + ; + +not : /* empty */ + | '!' + { + negative = 1; + } + ; + %% /* @@ -183,13 +813,70 @@ lookup(char *token) { /* Keep this list sorted */ static const struct keywords keywords[] = { - { "broadcast", BROADCAST }, - { "hostap", HOSTAP }, - { "iapp", IAPP }, - { "interface", INTERFACE }, - { "mode", MODE }, - { "multicast", MULTICAST }, - { "set", SET }, + { "add", ADD }, + { "any", ANY }, + { "assoc", ASSOC }, + { "assoced", ASSOCED }, + { "atim", ATIM }, + { "auth", AUTH }, + { "authed", AUTHED }, + { "beacon", BEACON }, + { "broadcast", BROADCAST }, + { "bssid", BSSID }, + { "const", CONST }, + { "data", DATA }, + { "deauth", DEAUTH }, + { "delete", DELETE }, + { "dir", DIR }, + { "disassoc", DISASSOC }, + { "ds", DS }, + { "expire", EXPIRE }, + { "failure", FAILURE }, + { "frame", FRAME }, + { "from", FROM }, + { "handle", HANDLE }, + { "hostap", HOSTAP }, + { "iapp", IAPP }, + { "ie", IE }, + { "inconsistent", INCONSISTENT }, + { "interface", INTERFACE }, + { "invalid", INVALID }, + { "leave", LEAVE }, + { "limit", LIMIT }, + { "log", LOG }, + { "management", MANAGEMENT }, + { "mic", MIC }, + { "mode", MODE }, + { "multicast", MULTICAST }, + { "no", NO }, + { "not", NOT }, + { "node", NODE }, + { "nwid", NWID }, + { "passive", PASSIVE }, + { "pcap", PCAP }, + { "probe", PROBE }, + { "quick", QUICK }, + { "radiotap", RADIOTAP }, + { "reason", REASON }, + { "reassoc", REASSOC }, + { "request", REQUEST }, + { "required", REQUIRED }, + { "resend", RESEND }, + { "reserved", RESERVED }, + { "response", RESPONSE }, + { "rsn", RSN }, + { "sec", SEC }, + { "set", SET }, + { "skip", SKIP }, + { "subtype", SUBTYPE }, + { "table", TABLE }, + { "to", TO }, + { "toomany", TOOMANY }, + { "type", TYPE }, + { "unspecified", UNSPECIFIED }, + { "usec", USEC }, + { "verbose", VERBOSE }, + { "with", WITH } }; const struct keywords *p; @@ -405,7 +1092,7 @@ symset(const char *nam, const char *val, int persist) free(sym); } } - if ((sym = calloc(1, sizeof(*sym))) == NULL) + if ((sym = (struct sym *)calloc(1, sizeof(*sym))) == NULL) return (-1); sym->nam = strdup(nam); @@ -439,7 +1126,7 @@ hostapd_parse_symset(char *s) return (-1); len = strlen(s) - strlen(val) + 1; - if ((sym = malloc(len)) == NULL) + if ((sym = (char *)malloc(len)) == NULL) hostapd_fatal("cmdline_symset: malloc"); strlcpy(sym, s, len); @@ -483,6 +1170,10 @@ hostapd_parse_file(struct hostapd_config *cfg) return (-1); } + /* Init tables and data structures */ + TAILQ_INIT(&cfg->c_tables); + TAILQ_INIT(&cfg->c_frames); + lineno = 1; errors = 0; @@ -504,7 +1195,7 @@ hostapd_parse_file(struct hostapd_config *cfg) } } - return (ret); + return (errors ? EINVAL : ret); } int @@ -518,7 +1209,8 @@ yyerror(const char *fmt, ...) va_start(ap, fmt); if (asprintf(&nfmt, "%s:%d: %s\n", infile, yylval.lineno, fmt) == -1) hostapd_fatal("yyerror asprintf"); - hostapd_log(HOSTAPD_LOG, nfmt, ap); + vfprintf(stderr, nfmt, ap); + fflush(stderr); va_end(ap); free(nfmt); diff --git a/usr.sbin/hostapd/print-802_11.c b/usr.sbin/hostapd/print-802_11.c new file mode 100644 index 00000000000..c1e7781d516 --- /dev/null +++ b/usr.sbin/hostapd/print-802_11.c @@ -0,0 +1,647 @@ +/* $OpenBSD: print-802_11.c,v 1.1 2005/06/17 19:13:35 reyk Exp $ */ + +/* + * Copyright (c) 2005 Reyk Floeter <reyk@vantronix.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* usr.sbin/tcpdump/print-802_11.c,v 1.3 2005/03/09 11:43:17 deraadt Exp */ + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/file.h> +#include <sys/ioctl.h> + +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_arp.h> +#include <net/if_llc.h> +#include <net/bpf.h> + +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <arpa/inet.h> + +#include <net80211/ieee80211.h> +#include <net80211/ieee80211_radiotap.h> + +#include <pcap.h> +#include <stdio.h> +#include <string.h> + +#include "hostapd.h" + +const char *ieee80211_mgt_subtype_name[] = { + "association request", + "association response", + "reassociation request", + "reassociation response", + "probe request", + "probe response", + "reserved#6", + "reserved#7", + "beacon", + "atim", + "disassociation", + "authentication", + "deauthentication", + "reserved#13", + "reserved#14", + "reserved#15" +}; + +const u_int8_t *snapend; +int vflag = 1, eflag = 1; + +int ieee80211_hdr(struct ieee80211_frame *); +void ieee80211_print_element(u_int8_t *, u_int); +void ieee80211_print_essid(u_int8_t *, u_int); +int ieee80211_elements(struct ieee80211_frame *, u_int); +int ieee80211_frame(struct ieee80211_frame *, u_int); +int ieee80211_print(struct ieee80211_frame *, u_int); +u_int ieee80211_any2ieee(u_int, u_int); +void ieee802_11_if_print(u_int8_t *, u_int); +void ieee802_11_radio_if_print(u_int8_t *, u_int); + +#define TCARR(a) TCHECK2(*a, sizeof(a)) + +int +ieee80211_hdr(struct ieee80211_frame *wh) +{ + struct ieee80211_frame_addr4 *w4; + + switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { + case IEEE80211_FC1_DIR_NODS: + TCARR(wh->i_addr2); + PRINTF("%s", etheraddr_string(wh->i_addr2)); + TCARR(wh->i_addr1); + PRINTF(" > %s", etheraddr_string(wh->i_addr1)); + TCARR(wh->i_addr3); + PRINTF(", bssid %s", etheraddr_string(wh->i_addr3)); + break; + case IEEE80211_FC1_DIR_TODS: + TCARR(wh->i_addr2); + PRINTF("%s", etheraddr_string(wh->i_addr2)); + TCARR(wh->i_addr3); + PRINTF(" > %s", etheraddr_string(wh->i_addr3)); + TCARR(wh->i_addr1); + PRINTF(", bssid %s, > DS", etheraddr_string(wh->i_addr1)); + break; + case IEEE80211_FC1_DIR_FROMDS: + TCARR(wh->i_addr3); + PRINTF("%s", etheraddr_string(wh->i_addr3)); + TCARR(wh->i_addr1); + PRINTF(" > %s", etheraddr_string(wh->i_addr1)); + TCARR(wh->i_addr2); + PRINTF(", bssid %s, DS >", etheraddr_string(wh->i_addr2)); + break; + case IEEE80211_FC1_DIR_DSTODS: + w4 = (struct ieee80211_frame_addr4 *) wh; + TCARR(w4->i_addr4); + PRINTF("%s", etheraddr_string(w4->i_addr4)); + TCARR(w4->i_addr3); + PRINTF(" > %s", etheraddr_string(w4->i_addr3)); + TCARR(w4->i_addr2); + PRINTF(", bssid %s", etheraddr_string(w4->i_addr2)); + TCARR(w4->i_addr1); + PRINTF(" > %s, DS > DS", etheraddr_string(w4->i_addr1)); + break; + } + if (vflag) { + TCARR(wh->i_seq); + PRINTF(" (seq %u)", letoh16(*(u_int16_t *)&wh->i_seq[0])); + } + + return (0); + + trunc: + /* Truncated elements in frame */ + return (1); +} + +/* Caller checks len */ +void +ieee80211_print_element(u_int8_t *data, u_int len) +{ + u_int8_t *p; + u_int i; + + PRINTF(" 0x"); + for (i = 0, p = data; i < len; i++, p++) + PRINTF("%02x", *p); +} + +/* Caller checks len */ +void +ieee80211_print_essid(u_int8_t *essid, u_int len) +{ + u_int8_t *p; + u_int i; + + if (len > IEEE80211_NWID_LEN) + len = IEEE80211_NWID_LEN; + + /* determine printable or not */ + for (i = 0, p = essid; i < len; i++, p++) { + if (*p < ' ' || *p > 0x7e) + break; + } + if (i == len) { + PRINTF(" ("); + for (i = 0, p = essid; i < len; i++, p++) + PRINTF("%c", *p); + PRINTF(")"); + } else + ieee80211_print_element(essid, len); +} + +int +ieee80211_elements(struct ieee80211_frame *wh, u_int flen) +{ + u_int8_t *buf, *frm; + u_int8_t *tstamp, *bintval, *capinfo; + int i; + + buf = (u_int8_t *)wh; + frm = (u_int8_t *)&wh[1]; + + tstamp = frm; + TCHECK2(*tstamp, 8); + frm += 8; + + bintval = frm; + TCHECK2(*bintval, 2); + frm += 2; + + if (vflag) + PRINTF(", interval %u", letoh16(*(u_int16_t *)bintval)); + + capinfo = frm; + TCHECK2(*capinfo, 2); + frm += 2; + +#if 0 + if (vflag) + printb(", caps", letoh16(*(u_int16_t *)capinfo), + IEEE80211_CAPINFO_BITS); +#endif + + while (TTEST2(*frm, 2)) { + u_int len = frm[1]; + u_int8_t *data = frm + 2; + + if (!TTEST2(*data, len)) + break; + +#define ELEM_CHECK(l) if (len != l) break + + switch (*frm) { + case IEEE80211_ELEMID_SSID: + PRINTF(", ssid"); + ieee80211_print_essid(data, len); + break; + case IEEE80211_ELEMID_RATES: + if (!vflag) + break; + PRINTF(", rates"); + for (i = len; i > 0; i--, data++) + PRINTF(" %uM", + (data[0] & IEEE80211_RATE_VAL) / 2); + break; + case IEEE80211_ELEMID_FHPARMS: + ELEM_CHECK(5); + PRINTF(", fh (dwell %u, chan %u, index %u)", + (data[1] << 8) | data[0], + (data[2] - 1) * 80 + data[3], /* FH_CHAN */ + data[4]); + break; + case IEEE80211_ELEMID_DSPARMS: + ELEM_CHECK(1); + if (!vflag) + break; + PRINTF(", ds"); + PRINTF(" (chan %u)", data[0]); + break; + case IEEE80211_ELEMID_CFPARMS: + if (!vflag) + break; + PRINTF(", cf"); + ieee80211_print_element(data, len); + break; + case IEEE80211_ELEMID_TIM: + if (!vflag) + break; + PRINTF(", tim"); + ieee80211_print_element(data, len); + break; + case IEEE80211_ELEMID_IBSSPARMS: + if (!vflag) + break; + PRINTF(", ibss"); + ieee80211_print_element(data, len); + break; + case IEEE80211_ELEMID_COUNTRY: + if (!vflag) + break; + PRINTF(", country"); + for (i = len; i > 0; i--, data++) + PRINTF(" %u", data[0]); + break; + case IEEE80211_ELEMID_CHALLENGE: + if (!vflag) + break; + PRINTF(", challenge"); + ieee80211_print_element(data, len); + break; + case IEEE80211_ELEMID_ERP: + if (!vflag) + break; + PRINTF(", erp"); + ieee80211_print_element(data, len); + break; + case IEEE80211_ELEMID_RSN: + if (!vflag) + break; + PRINTF(", rsn"); + ieee80211_print_element(data, len); + break; + case IEEE80211_ELEMID_XRATES: + if (!vflag) + break; + PRINTF(", xrates"); + for (i = len; i > 0; i--, data++) + PRINTF(" %uM", + (data[0] & IEEE80211_RATE_VAL) / 2); + break; + case IEEE80211_ELEMID_TPC: + if (!vflag) + break; + PRINTF(", tpc"); + ieee80211_print_element(data, len); + break; + case IEEE80211_ELEMID_CCKM: + if (!vflag) + break; + PRINTF(", cckm"); + ieee80211_print_element(data, len); + break; + case IEEE80211_ELEMID_VENDOR: + if (!vflag) + break; + PRINTF(", vendor"); + ieee80211_print_element(data, len); + break; + default: + if (!vflag) + break; + PRINTF(", %u:%u", (u_int) *frm, len); + ieee80211_print_element(data, len); + break; + } + frm += len + 2; + + if (frm >= snapend) + break; + } + +#undef ELEM_CHECK + + return (0); + + trunc: + /* Truncated elements in frame */ + return (1); +} + +int +ieee80211_frame(struct ieee80211_frame *wh, u_int len) +{ + u_int8_t subtype, type, *frm; + + TCARR(wh->i_fc); + + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; + + frm = (u_int8_t *)&wh[1]; + + switch (type) { + case IEEE80211_FC0_TYPE_DATA: + PRINTF(": data"); + break; + case IEEE80211_FC0_TYPE_MGT: + PRINTF(": %s", ieee80211_mgt_subtype_name[ + subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]); + switch (subtype) { + case IEEE80211_FC0_SUBTYPE_BEACON: + case IEEE80211_FC0_SUBTYPE_PROBE_RESP: + if (ieee80211_elements(wh, len) != 0) + goto trunc; + break; + case IEEE80211_FC0_SUBTYPE_AUTH: + TCHECK2(*frm, 2); /* Auth Algorithm */ + switch (IEEE80211_AUTH_ALGORITHM(frm)) { + case IEEE80211_AUTH_ALG_OPEN: + TCHECK2(*frm, 4); /* Auth Transaction */ + switch (IEEE80211_AUTH_TRANSACTION(frm)) { + case IEEE80211_AUTH_OPEN_REQUEST: + PRINTF(" request"); + break; + case IEEE80211_AUTH_OPEN_RESPONSE: + PRINTF(" response"); + break; + } + break; + case IEEE80211_AUTH_ALG_SHARED: + TCHECK2(*frm, 4); /* Auth Transaction */ + switch (IEEE80211_AUTH_TRANSACTION(frm)) { + case IEEE80211_AUTH_SHARED_REQUEST: + PRINTF(" request"); + break; + case IEEE80211_AUTH_SHARED_CHALLENGE: + PRINTF(" challenge"); + break; + case IEEE80211_AUTH_SHARED_RESPONSE: + PRINTF(" response"); + break; + case IEEE80211_AUTH_SHARED_PASS: + PRINTF(" pass"); + break; + } + break; + case IEEE80211_AUTH_ALG_LEAP: + PRINTF(" (leap)"); + break; + } + break; + } + break; + default: + PRINTF(": type#%d", type); + break; + } + + if (wh->i_fc[1] & IEEE80211_FC1_WEP) + PRINTF(", WEP"); + + return (0); + + trunc: + /* Truncated 802.11 frame */ + return (1); +} + +u_int +ieee80211_any2ieee(u_int freq, u_int flags) +{ + if (flags & IEEE80211_CHAN_2GHZ) { + if (freq == 2484) + return 14; + if (freq < 2484) + return (freq - 2407) / 5; + else + return 15 + ((freq - 2512) / 20); + } else if (flags & IEEE80211_CHAN_5GHZ) { + return (freq - 5000) / 5; + } else { + /* Assume channel is already an IEEE number */ + return (freq); + } +} + +int +ieee80211_print(struct ieee80211_frame *wh, u_int len) +{ + if (eflag) + if (ieee80211_hdr(wh)) + return (1); + + return (ieee80211_frame(wh, len)); +} + +void +ieee802_11_if_print(u_int8_t *buf, u_int len) +{ + struct ieee80211_frame *wh = (struct ieee80211_frame*)buf; + + snapend = buf + len; + + if (ieee80211_print(wh, len) != 0) + PRINTF("[|802.11]"); + + PRINTF("\n"); +} + +void +ieee802_11_radio_if_print(u_int8_t *buf, u_int len) +{ + struct ieee80211_radiotap_header *rh = + (struct ieee80211_radiotap_header*)buf; + struct ieee80211_frame *wh; + u_int8_t *t; + u_int32_t present; + u_int rh_len; + + snapend = buf + len; + + TCHECK(*rh); + + rh_len = letoh16(rh->it_len); + if (rh->it_version != 0) { + PRINTF("[?radiotap + 802.11 v:%u]\n", rh->it_version); + goto out; + } + + wh = (struct ieee80211_frame *)(buf + rh_len); + if (len <= rh_len || ieee80211_print(wh, len - rh_len)) + PRINTF("[|802.11]"); + + t = (u_int8_t*)buf + sizeof(struct ieee80211_radiotap_header); + + if ((present = letoh32(rh->it_present)) == 0) + goto out; + + PRINTF(", <radiotap v%u", rh->it_version); + +#define RADIOTAP(_x) \ + (present & (1 << IEEE80211_RADIOTAP_##_x)) + + if (RADIOTAP(TSFT)) { + u_int64_t tsf; + u_int32_t tsf_v[2]; + + TCHECK2(*t, 8); + + tsf = letoh64(*(u_int64_t *)t); + tsf_v[0] = (u_int32_t)(tsf >> 32); + tsf_v[1] = (u_int32_t)(tsf & 0x00000000ffffffff); + if (vflag > 1) + PRINTF(", tsf 0x%08x%08x", tsf_v[0], tsf_v[1]); + t += 8; + } + + if (RADIOTAP(FLAGS)) { + u_int8_t flags = *(u_int8_t*)t; + TCHECK2(*t, 1); + + if (flags & IEEE80211_RADIOTAP_F_CFP) + PRINTF(", CFP"); + if (flags & IEEE80211_RADIOTAP_F_SHORTPRE) + PRINTF(", SHORTPRE"); + if (flags & IEEE80211_RADIOTAP_F_WEP) + PRINTF(", WEP"); + if (flags & IEEE80211_RADIOTAP_F_FRAG) + PRINTF(", FRAG"); + t += 1; + } + + if (RADIOTAP(RATE)) { + TCHECK2(*t, 1); + if (vflag) + PRINTF(", %uMbit/s", (*(u_int8_t*)t) / 2); + t += 1; + } + + if (RADIOTAP(CHANNEL)) { + u_int16_t freq, flags; + TCHECK2(*t, 2); + + freq = letoh16(*(u_int16_t*)t); + t += 2; + TCHECK2(*t, 2); + flags = letoh16(*(u_int16_t*)t); + t += 2; + + PRINTF(", chan %u", ieee80211_any2ieee(freq, flags)); + + if (flags & IEEE80211_CHAN_DYN && + flags & IEEE80211_CHAN_2GHZ) + PRINTF(", 11g"); + else if (flags & IEEE80211_CHAN_CCK && + flags & IEEE80211_CHAN_2GHZ) + PRINTF(", 11b"); + else if (flags & IEEE80211_CHAN_OFDM && + flags & IEEE80211_CHAN_2GHZ) + PRINTF(", 11G"); + else if (flags & IEEE80211_CHAN_OFDM && + flags & IEEE80211_CHAN_5GHZ) + PRINTF(", 11a"); + + if (flags & IEEE80211_CHAN_TURBO) + PRINTF(", TURBO"); + if (flags & IEEE80211_CHAN_XR) + PRINTF(", XR"); + } + + if (RADIOTAP(FHSS)) { + TCHECK2(*t, 2); + PRINTF(", fhss %u/%u", *(u_int8_t*)t, *(u_int8_t*)t + 1); + t += 2; + } + + if (RADIOTAP(DBM_ANTSIGNAL)) { + TCHECK(*t); + PRINTF(", sig %ddBm", *(int8_t*)t); + t += 1; + } + + if (RADIOTAP(DBM_ANTNOISE)) { + TCHECK(*t); + PRINTF(", noise %ddBm", *(int8_t*)t); + t += 1; + } + + if (RADIOTAP(LOCK_QUALITY)) { + TCHECK2(*t, 2); + if (vflag) + PRINTF(", quality %u", letoh16(*(u_int16_t*)t)); + t += 2; + } + + if (RADIOTAP(TX_ATTENUATION)) { + TCHECK2(*t, 2); + if (vflag) + PRINTF(", txatt %u", + letoh16(*(u_int16_t*)t)); + t += 2; + } + + if (RADIOTAP(DB_TX_ATTENUATION)) { + TCHECK2(*t, 2); + if (vflag) + PRINTF(", txatt %udB", + letoh16(*(u_int16_t*)t)); + t += 2; + } + + if (RADIOTAP(DBM_TX_POWER)) { + TCHECK(*t); + PRINTF(", txpower %ddBm", *(int8_t*)t); + t += 1; + } + + if (RADIOTAP(ANTENNA)) { + TCHECK(*t); + if (vflag) + PRINTF(", antenna %u", *(u_int8_t*)t); + t += 1; + } + + if (RADIOTAP(DB_ANTSIGNAL)) { + TCHECK(*t); + PRINTF(", signal %udB", *(u_int8_t*)t); + t += 1; + } + + if (RADIOTAP(DB_ANTNOISE)) { + TCHECK(*t); + PRINTF(", noise %udB", *(u_int8_t*)t); + t += 1; + } + + if (RADIOTAP(FCS)) { + TCHECK2(*t, 4); + if (vflag) + PRINTF(", fcs %08x", letoh32(*(u_int32_t*)t)); + t += 4; + } + +#undef RADIOTAP + + PRINTF(">"); + goto out; + + trunc: + /* Truncated frame */ + PRINTF("[|radiotap + 802.11]"); + + out: + PRINTF("\n"); +} + +void +hostapd_print_ieee80211(u_int dlt, u_int verbose, u_int8_t *buf, u_int len) +{ + if (verbose) + vflag = 1; + else + vflag = 0; + + if (dlt == DLT_IEEE802_11) + ieee802_11_if_print(buf, len); + else + ieee802_11_radio_if_print(buf, len); +} diff --git a/usr.sbin/hostapd/privsep.c b/usr.sbin/hostapd/privsep.c index 40a11b4358a..64cfeb776fb 100644 --- a/usr.sbin/hostapd/privsep.c +++ b/usr.sbin/hostapd/privsep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: privsep.c,v 1.11 2005/05/25 07:40:49 reyk Exp $ */ +/* $OpenBSD: privsep.c,v 1.12 2005/06/17 19:13:35 reyk Exp $ */ /* * Copyright (c) 2004, 2005 Reyk Floeter <reyk@vantronix.net> @@ -54,6 +54,7 @@ enum hostapd_cmd_types { PRIV_APME_BSSID, /* Get the Host AP's BSSID */ PRIV_APME_GETNODE, /* Get a node from the Host AP */ + PRIV_APME_ADDNODE, /* Delete a node from the Host AP */ PRIV_APME_DELNODE, /* Delete a node from the Host AP */ PRIV_LLC_SEND_XID /* Send IEEE 802.3 LLC XID frame */ }; @@ -170,6 +171,7 @@ hostapd_priv(int fd, short sig, void *arg) struct ieee80211_bssid bssid; struct ieee80211_nodereq nr; struct ifreq ifr; + unsigned long request; int ret, cmd; /* Terminate the event if we got an invalid signal */ @@ -233,17 +235,22 @@ hostapd_priv(int fd, short sig, void *arg) } break; + case PRIV_APME_ADDNODE: case PRIV_APME_DELNODE: hostapd_log(HOSTAPD_LOG_DEBUG, - "[priv]: msg PRIV_APME_DELNODE received\n"); + "[priv]: msg PRIV_APME_[ADD|DEL]NODE received\n"); hostapd_must_read(fd, &node, sizeof(struct hostapd_node)); bcopy(node.ni_macaddr, nr.nr_macaddr, IEEE80211_ADDR_LEN); - /* Try to delete a station from the APME */ + strlcpy(nr.nr_ifname, cfg->c_apme_iface, sizeof(ifr.ifr_name)); + + request = cmd == PRIV_APME_ADDNODE ? + SIOCS80211NODE : SIOCS80211DELNODE; + + /* Try to add/delete a station from the APME */ if (cfg->c_flags & HOSTAPD_CFG_F_APME) { - if ((ret = ioctl(cfg->c_apme, - SIOCS80211DELNODE, &nr)) != 0) + if ((ret = ioctl(cfg->c_apme, request, &nr)) != 0) ret = errno; } else ret = ENXIO; @@ -289,12 +296,12 @@ hostapd_priv_apme_getnode(struct hostapd_config *cfg, struct hostapd_node *node) return (ret); hostapd_must_read(priv_fd, node, sizeof(struct hostapd_node)); - cfg->c_stats.cn_tx_apme++; return (ret); } int -hostapd_priv_apme_delnode(struct hostapd_config *cfg, struct hostapd_node *node) +hostapd_priv_apme_setnode(struct hostapd_config *cfg, struct hostapd_node *node, + int add) { int ret, cmd; @@ -304,12 +311,13 @@ hostapd_priv_apme_delnode(struct hostapd_config *cfg, struct hostapd_node *node) if ((cfg->c_flags & HOSTAPD_CFG_F_APME) == 0) hostapd_fatal("%s: Host AP is not available\n", __func__); - cmd = PRIV_APME_DELNODE; + if (add) + cmd = PRIV_APME_ADDNODE; + else + cmd = PRIV_APME_DELNODE; hostapd_must_write(priv_fd, &cmd, sizeof(int)); hostapd_must_write(priv_fd, node, sizeof(struct hostapd_node)); hostapd_must_read(priv_fd, &ret, sizeof(int)); - if (ret == 0) - cfg->c_stats.cn_tx_apme++; return (ret); } |