summaryrefslogtreecommitdiff
path: root/usr.sbin/hostapd/apme.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/hostapd/apme.c')
-rw-r--r--usr.sbin/hostapd/apme.c120
1 files changed, 112 insertions, 8 deletions
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));
+}