aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2004-05-07 01:09:58 (GMT)
committerJouni Malinen <j@w1.fi>2004-05-07 01:09:58 (GMT)
commit80d0dcf3fa68d47a8a95e9365ed71b3723082e9c (patch)
tree88a197afa224d9845ba85b9f315f9b264730f790
parent046fcf55b20fac8d6d9f91ac219eea6a1faedeac (diff)
downloadhostap-history-80d0dcf3fa68d47a8a95e9365ed71b3723082e9c.zip
hostap-history-80d0dcf3fa68d47a8a95e9365ed71b3723082e9c.tar.gz
hostap-history-80d0dcf3fa68d47a8a95e9365ed71b3723082e9c.tar.bz2
Added local Michael MIC failure processing:
- receive Michael MIC failure reports from the driver (using wireless events) - trigger TKIP countermeasures if two or more failures (local or remote) are reported within 60 seconds
-rw-r--r--hostapd/driver.c200
-rw-r--r--hostapd/driver.h2
-rw-r--r--hostapd/hostapd.c4
-rw-r--r--hostapd/hostapd.h1
-rw-r--r--hostapd/priv_netlink.h67
5 files changed, 274 insertions, 0 deletions
diff --git a/hostapd/driver.c b/hostapd/driver.c
index a2e2650..a15266e 100644
--- a/hostapd/driver.c
+++ b/hostapd/driver.c
@@ -13,6 +13,8 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <unistd.h>
+#include <errno.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
@@ -31,6 +33,10 @@
#include "hostapd.h"
#include "driver.h"
#include "ieee802_1x.h"
+#include "eloop.h"
+#include "priv_netlink.h"
+#include "sta_info.h"
+#include "ieee802_11.h"
int hostapd_set_iface_flags(hostapd *hapd, int dev_up)
@@ -289,3 +295,197 @@ int hostapd_set_generic_elem(struct hostapd_data *hapd,
return res;
}
+
+
+static void hostapd_wireless_event_wireless_custom(struct hostapd_data *hapd,
+ char *custom)
+{
+ HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Custom wireless event: '%s'\n",
+ custom);
+
+ if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
+ char *pos;
+ u8 addr[ETH_ALEN];
+ pos = strstr(custom, "addr=");
+ if (pos == NULL) {
+ HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
+ "MLME-MICHAELMICFAILURE.indication "
+ "without sender address ignored\n");
+ return;
+ }
+ pos += 5;
+ if (hwaddr_aton(pos, addr) == 0 &&
+ ap_get_sta(hapd, addr) != NULL) {
+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Michael MIC failure detected in "
+ "received frame");
+ ieee80211_michael_mic_failure(hapd);
+ } else {
+ HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
+ "MLME-MICHAELMICFAILURE.indication "
+ "for not associated STA (" MACSTR
+ ") ignored\n",
+ MAC2STR(addr));
+ return;
+ }
+ }
+}
+
+
+static void hostapd_wireless_event_wireless(struct hostapd_data *hapd,
+ char *data, int len)
+{
+ struct iw_event *iwe;
+ char *pos, *end, *custom, *buf;
+
+ pos = data;
+ end = data + len;
+
+ while (pos + IW_EV_LCP_LEN <= end) {
+ iwe = (struct iw_event *) pos;
+ HOSTAPD_DEBUG(HOSTAPD_DEBUG_VERBOSE, "Wireless event: "
+ "cmd=0x%x len=%d\n", iwe->cmd, iwe->len);
+ if (iwe->len <= IW_EV_LCP_LEN)
+ return;
+ switch (iwe->cmd) {
+ case IWEVCUSTOM:
+ custom = pos + IW_EV_POINT_LEN;
+ if (custom + iwe->u.data.length > end)
+ return;
+ buf = malloc(iwe->u.data.length + 1);
+ if (buf == NULL)
+ return;
+ memcpy(buf, custom, iwe->u.data.length);
+ buf[iwe->u.data.length] = '\0';
+ hostapd_wireless_event_wireless_custom(hapd, buf);
+ free(buf);
+ break;
+ }
+
+ pos += iwe->len;
+ }
+}
+
+
+static void hostapd_wireless_event_rtm_newlink(struct hostapd_data *hapd,
+ struct nlmsghdr *h, int len)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, nlmsg_len, rta_len;
+ struct rtattr * attr;
+
+ if (len < sizeof(*ifi))
+ return;
+
+ ifi = NLMSG_DATA(h);
+
+ /* TODO: use ifi->ifi_index to filter out wireless events from other
+ * interfaces */
+
+ nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - nlmsg_len;
+ if (attrlen < 0)
+ return;
+
+ attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_WIRELESS) {
+ hostapd_wireless_event_wireless(
+ hapd, ((char *) attr) + rta_len,
+ attr->rta_len - rta_len);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+}
+
+
+static void hostapd_wireless_event_receive(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ char buf[256];
+ int left;
+ struct sockaddr_nl from;
+ socklen_t fromlen;
+ struct nlmsghdr *h;
+ struct hostapd_data *hapd = eloop_ctx;
+
+ fromlen = sizeof(from);
+ left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
+ (struct sockaddr *) &from, &fromlen);
+ if (left < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ perror("recvfrom(netlink)");
+ return;
+ }
+
+ h = (struct nlmsghdr *) buf;
+ while (left >= sizeof(*h)) {
+ int len, plen;
+
+ len = h->nlmsg_len;
+ plen = len - sizeof(*h);
+ if (len > left || plen < 0) {
+ printf("Malformed netlink message: "
+ "len=%d left=%d plen=%d\n",
+ len, left, plen);
+ break;
+ }
+
+ switch (h->nlmsg_type) {
+ case RTM_NEWLINK:
+ hostapd_wireless_event_rtm_newlink(hapd, h, plen);
+ break;
+ }
+
+ len = NLMSG_ALIGN(len);
+ left -= len;
+ h = (struct nlmsghdr *) ((char *) h + len);
+ }
+
+ if (left > 0) {
+ printf("%d extra bytes in the end of netlink message\n", left);
+ }
+}
+
+
+int hostapd_wireless_event_init(struct hostapd_data *hapd)
+{
+ int s;
+ struct sockaddr_nl local;
+
+ hapd->wext_sock = -1;
+
+ s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (s < 0) {
+ perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
+ return -1;
+ }
+
+ memset(&local, 0, sizeof(local));
+ local.nl_family = AF_NETLINK;
+ local.nl_groups = RTMGRP_LINK;
+ if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
+ perror("bind(netlink)");
+ close(s);
+ return -1;
+ }
+
+ eloop_register_read_sock(s, hostapd_wireless_event_receive, hapd,
+ NULL);
+ hapd->wext_sock = s;
+
+ return 0;
+}
+
+
+void hostapd_wireless_event_deinit(struct hostapd_data *hapd)
+{
+ if (hapd->wext_sock < 0)
+ return;
+ eloop_unregister_read_sock(hapd->wext_sock);
+ close(hapd->wext_sock);
+}
diff --git a/hostapd/driver.h b/hostapd/driver.h
index 21b4cbc..ec3994e 100644
--- a/hostapd/driver.h
+++ b/hostapd/driver.h
@@ -20,5 +20,7 @@ int hostapd_read_sta_driver_data(hostapd *hapd,
u8 *addr);
int hostapd_set_generic_elem(struct hostapd_data *hapd,
const char *elem, size_t elem_len);
+int hostapd_wireless_event_init(struct hostapd_data *hapd);
+void hostapd_wireless_event_deinit(struct hostapd_data *hapd);
#endif /* DRIVER_H */
diff --git a/hostapd/hostapd.c b/hostapd/hostapd.c
index 1bfa6c9..6f65660 100644
--- a/hostapd/hostapd.c
+++ b/hostapd/hostapd.c
@@ -354,6 +354,7 @@ static void hostapd_cleanup(hostapd *hapd)
close(hapd->sock);
if (hapd->ioctl_sock >= 0)
close(hapd->ioctl_sock);
+ hostapd_wireless_event_deinit(hapd);
hostapd_config_free(hapd->conf);
hapd->conf = NULL;
@@ -472,6 +473,9 @@ static int hostapd_setup_interface(hostapd *hapd)
return -1;
}
+ if (hostapd_wireless_event_init(hapd) < 0)
+ return -1;
+
if (hapd->default_wep_key && hostapd_setup_encryption(hapd))
return -1;
diff --git a/hostapd/hostapd.h b/hostapd/hostapd.h
index 0f43845..d45feed 100644
--- a/hostapd/hostapd.h
+++ b/hostapd/hostapd.h
@@ -50,6 +50,7 @@ typedef struct hostapd_data {
int sock; /* raw packet socket for driver access */
int ioctl_sock; /* socket for ioctl() use */
+ int wext_sock; /* socket for wireless events */
u8 own_addr[6];
int num_sta; /* number of entries in sta_list */
diff --git a/hostapd/priv_netlink.h b/hostapd/priv_netlink.h
new file mode 100644
index 0000000..c9810b4
--- /dev/null
+++ b/hostapd/priv_netlink.h
@@ -0,0 +1,67 @@
+#ifndef PRIV_NETLINK_H
+#define PRIV_NETLINK_H
+
+/* Private copy of needed Linux netlink/rtnetlink definitions.
+ *
+ * This should be replaced with user space header once one is available with C
+ * library, etc..
+ */
+
+#ifndef IFLA_WIRELESS
+#define IFLA_WIRELESS 11
+#endif
+
+#define NETLINK_ROUTE 0
+#define RTMGRP_LINK 1
+#define RTM_BASE 0x10
+#define RTM_NEWLINK (RTM_BASE + 0)
+
+#define NLMSG_ALIGNTO 4
+#define NLMSG_ALIGN(len) (((len) + NLMSG_ALIGNTO - 1) & ~(NLMSG_ALIGNTO - 1))
+#define NLMSG_LENGTH(len) ((len) + NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#define NLMSG_DATA(nlh) ((void*) (((char*) nlh) + NLMSG_LENGTH(0)))
+
+#define RTA_ALIGNTO 4
+#define RTA_ALIGN(len) (((len) + RTA_ALIGNTO - 1) & ~(RTA_ALIGNTO - 1))
+#define RTA_OK(rta,len) \
+((len) > 0 && (rta)->rta_len >= sizeof(struct rtattr) && \
+(rta)->rta_len <= (len))
+#define RTA_NEXT(rta,attrlen) \
+((attrlen) -= RTA_ALIGN((rta)->rta_len), \
+(struct rtattr *) (((char *)(rta)) + RTA_ALIGN((rta)->rta_len)))
+
+
+struct sockaddr_nl
+{
+ sa_family_t nl_family;
+ unsigned short nl_pad;
+ u32 nl_pid;
+ u32 nl_groups;
+};
+
+struct nlmsghdr
+{
+ u32 nlmsg_len;
+ u16 nlmsg_type;
+ u16 nlmsg_flags;
+ u32 nlmsg_seq;
+ u32 nlmsg_pid;
+};
+
+struct ifinfomsg
+{
+ unsigned char ifi_family;
+ unsigned char __ifi_pad;
+ unsigned short ifi_type;
+ int ifi_index;
+ unsigned ifi_flags;
+ unsigned ifi_change;
+};
+
+struct rtattr
+{
+ unsigned short rta_len;
+ unsigned short rta_type;
+};
+
+#endif /* PRIV_NETLINK_H */