mirror of
https://github.com/vanhoefm/fragattacks.git
synced 2024-11-28 18:28:23 -05:00
nl80211: Replace hostapd WEXT events with nl80211 events
This shares the nl80211 event processing with wpa_supplicant and removes the old WEXT code from driver_nl80211.c.
This commit is contained in:
parent
35583f3fa6
commit
5b7b85f669
@ -119,7 +119,6 @@ struct wpa_driver_nl80211_data {
|
||||
#ifdef HOSTAPD
|
||||
struct hostapd_data *hapd;
|
||||
|
||||
int wext_sock; /* socket for wireless events */
|
||||
int eapol_sock; /* socket for EAPOL frames */
|
||||
int monitor_sock; /* socket for monitor */
|
||||
int monitor_ifidx;
|
||||
@ -128,7 +127,6 @@ struct wpa_driver_nl80211_data {
|
||||
int *if_indices;
|
||||
int num_if_indices;
|
||||
|
||||
int we_version;
|
||||
int beacon_int;
|
||||
struct i802_bss bss;
|
||||
unsigned int ht_40mhz_scan:1;
|
||||
@ -154,10 +152,6 @@ static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
|
||||
#endif /* CONFIG_AP */
|
||||
|
||||
|
||||
#ifdef HOSTAPD
|
||||
#define wpa_supplicant_event(c, e, d) do { } while (0)
|
||||
#endif /* HOSTAPD */
|
||||
|
||||
/* nl80211 code */
|
||||
static int ack_handler(struct nl_msg *msg, void *arg)
|
||||
{
|
||||
@ -181,6 +175,13 @@ static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
|
||||
return NL_SKIP;
|
||||
}
|
||||
|
||||
|
||||
static int no_seq_check(struct nl_msg *msg, void *arg)
|
||||
{
|
||||
return NL_OK;
|
||||
}
|
||||
|
||||
|
||||
static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
|
||||
struct nl_msg *msg,
|
||||
int (*valid_handler)(struct nl_msg *, void *),
|
||||
@ -382,6 +383,7 @@ static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
|
||||
}
|
||||
|
||||
|
||||
#ifndef HOSTAPD
|
||||
static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv,
|
||||
void *ctx, char *buf, size_t len,
|
||||
int del)
|
||||
@ -621,12 +623,6 @@ try_again:
|
||||
}
|
||||
|
||||
|
||||
static int no_seq_check(struct nl_msg *msg, void *arg)
|
||||
{
|
||||
return NL_OK;
|
||||
}
|
||||
|
||||
|
||||
static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
|
||||
const u8 *frame, size_t len)
|
||||
{
|
||||
@ -729,10 +725,17 @@ static void mlme_event(struct wpa_driver_nl80211_data *drv,
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HOSTAPD */
|
||||
|
||||
|
||||
static void mlme_event_michael_mic_failure(struct wpa_driver_nl80211_data *drv,
|
||||
struct nlattr *tb[])
|
||||
{
|
||||
#ifdef HOSTAPD
|
||||
if (tb[NL80211_ATTR_MAC])
|
||||
hostapd_michael_mic_failure(drv->hapd,
|
||||
nla_data(tb[NL80211_ATTR_MAC]));
|
||||
#else /* HOSTAPD */
|
||||
union wpa_event_data data;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "nl80211: MLME event Michael MIC failure");
|
||||
@ -762,6 +765,7 @@ static void mlme_event_michael_mic_failure(struct wpa_driver_nl80211_data *drv,
|
||||
}
|
||||
|
||||
wpa_supplicant_event(drv->ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
|
||||
#endif /* HOSTAPD */
|
||||
}
|
||||
|
||||
|
||||
@ -785,6 +789,7 @@ static int process_event(struct nl_msg *msg, void *arg)
|
||||
}
|
||||
|
||||
switch (gnlh->cmd) {
|
||||
#ifndef HOSTAPD
|
||||
case NL80211_CMD_NEW_SCAN_RESULTS:
|
||||
wpa_printf(MSG_DEBUG, "nl80211: New scan results available");
|
||||
drv->scan_complete_events = 1;
|
||||
@ -808,6 +813,7 @@ static int process_event(struct nl_msg *msg, void *arg)
|
||||
case NL80211_CMD_DISASSOCIATE:
|
||||
mlme_event(drv, gnlh->cmd, tb[NL80211_ATTR_FRAME]);
|
||||
break;
|
||||
#endif /* HOSTAPD */
|
||||
case NL80211_CMD_MICHAEL_MIC_FAILURE:
|
||||
mlme_event_michael_mic_failure(drv, tb);
|
||||
break;
|
||||
@ -1116,8 +1122,10 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname)
|
||||
goto err6;
|
||||
}
|
||||
|
||||
#ifndef HOSTAPD
|
||||
eloop_register_read_sock(s, wpa_driver_nl80211_event_receive_link, drv,
|
||||
ctx);
|
||||
#endif /* HOSTAPD */
|
||||
drv->link_event_sock = s;
|
||||
|
||||
if (wpa_driver_nl80211_finish_drv_init(drv))
|
||||
@ -1234,7 +1242,9 @@ static void wpa_driver_nl80211_deinit(void *priv)
|
||||
static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
|
||||
#ifndef HOSTAPD
|
||||
wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
|
||||
#endif /* HOSTAPD */
|
||||
}
|
||||
|
||||
|
||||
@ -4757,6 +4767,7 @@ static int i802_ht_scan(struct wpa_driver_nl80211_data *drv)
|
||||
static int i802_init_sockets(struct wpa_driver_nl80211_data *drv, const u8 *bssid)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
int ret;
|
||||
|
||||
drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (drv->ioctl_sock < 0) {
|
||||
@ -4820,6 +4831,28 @@ static int i802_init_sockets(struct wpa_driver_nl80211_data *drv, const u8 *bssi
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = nl_get_multicast_id(drv, "nl80211", "scan");
|
||||
if (ret >= 0)
|
||||
ret = nl_socket_add_membership(drv->nl_handle, ret);
|
||||
if (ret < 0) {
|
||||
wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
|
||||
"membership for scan events: %d (%s)",
|
||||
ret, strerror(-ret));
|
||||
}
|
||||
|
||||
ret = nl_get_multicast_id(drv, "nl80211", "mlme");
|
||||
if (ret >= 0)
|
||||
ret = nl_socket_add_membership(drv->nl_handle, ret);
|
||||
if (ret < 0) {
|
||||
wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
|
||||
"membership for mlme events: %d (%s)",
|
||||
ret, strerror(-ret));
|
||||
}
|
||||
|
||||
eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle),
|
||||
wpa_driver_nl80211_event_receive, drv,
|
||||
drv->hapd);
|
||||
|
||||
#ifdef CONFIG_IEEE80211N
|
||||
if (drv->ht_40mhz_scan) {
|
||||
if (nl80211_set_mode(drv, drv->ifname, NL80211_IFTYPE_STATION)
|
||||
@ -4899,255 +4932,6 @@ static int i802_sta_clear_stats(void *priv, const u8 *addr)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
hostapd_wireless_event_wireless_custom(struct wpa_driver_nl80211_data *drv,
|
||||
char *custom)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
|
||||
|
||||
if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
|
||||
char *pos;
|
||||
u8 addr[ETH_ALEN];
|
||||
pos = strstr(custom, "addr=");
|
||||
if (pos == NULL) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"MLME-MICHAELMICFAILURE.indication "
|
||||
"without sender address ignored");
|
||||
return;
|
||||
}
|
||||
pos += 5;
|
||||
if (hwaddr_aton(pos, addr) == 0) {
|
||||
hostapd_michael_mic_failure(drv->hapd, addr);
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"MLME-MICHAELMICFAILURE.indication "
|
||||
"with invalid MAC address");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_wireless_event_wireless(struct wpa_driver_nl80211_data *drv,
|
||||
char *data, int len)
|
||||
{
|
||||
struct iw_event iwe_buf, *iwe = &iwe_buf;
|
||||
char *pos, *end, *custom, *buf;
|
||||
|
||||
pos = data;
|
||||
end = data + len;
|
||||
|
||||
while (pos + IW_EV_LCP_LEN <= end) {
|
||||
/* Event data may be unaligned, so make a local, aligned copy
|
||||
* before processing. */
|
||||
memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
|
||||
wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d",
|
||||
iwe->cmd, iwe->len);
|
||||
if (iwe->len <= IW_EV_LCP_LEN)
|
||||
return;
|
||||
|
||||
custom = pos + IW_EV_POINT_LEN;
|
||||
if (drv->we_version > 18 &&
|
||||
(iwe->cmd == IWEVMICHAELMICFAILURE ||
|
||||
iwe->cmd == IWEVCUSTOM)) {
|
||||
/* WE-19 removed the pointer from struct iw_point */
|
||||
char *dpos = (char *) &iwe_buf.u.data.length;
|
||||
int dlen = dpos - (char *) &iwe_buf;
|
||||
memcpy(dpos, pos + IW_EV_LCP_LEN,
|
||||
sizeof(struct iw_event) - dlen);
|
||||
} else {
|
||||
memcpy(&iwe_buf, pos, sizeof(struct iw_event));
|
||||
custom += IW_EV_POINT_OFF;
|
||||
}
|
||||
|
||||
switch (iwe->cmd) {
|
||||
case IWEVCUSTOM:
|
||||
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(drv, buf);
|
||||
free(buf);
|
||||
break;
|
||||
}
|
||||
|
||||
pos += iwe->len;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void hostapd_wireless_event_rtm_newlink(struct wpa_driver_nl80211_data *drv,
|
||||
struct nlmsghdr *h, int len)
|
||||
{
|
||||
struct ifinfomsg *ifi;
|
||||
int attrlen, _nlmsg_len, rta_len;
|
||||
struct rtattr *attr;
|
||||
|
||||
if (len < (int) 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(
|
||||
drv, ((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 wpa_driver_nl80211_data *drv = 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 >= (int) 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(drv, 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int hostap_get_we_version(struct wpa_driver_nl80211_data *drv)
|
||||
{
|
||||
struct iw_range *range;
|
||||
struct iwreq iwr;
|
||||
int minlen;
|
||||
size_t buflen;
|
||||
|
||||
drv->we_version = 0;
|
||||
|
||||
/*
|
||||
* Use larger buffer than struct iw_range in order to allow the
|
||||
* structure to grow in the future.
|
||||
*/
|
||||
buflen = sizeof(struct iw_range) + 500;
|
||||
range = os_zalloc(buflen);
|
||||
if (range == NULL)
|
||||
return -1;
|
||||
|
||||
memset(&iwr, 0, sizeof(iwr));
|
||||
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
|
||||
iwr.u.data.pointer = (caddr_t) range;
|
||||
iwr.u.data.length = buflen;
|
||||
|
||||
minlen = ((char *) &range->enc_capa) - (char *) range +
|
||||
sizeof(range->enc_capa);
|
||||
|
||||
if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
|
||||
perror("ioctl[SIOCGIWRANGE]");
|
||||
free(range);
|
||||
return -1;
|
||||
} else if (iwr.u.data.length >= minlen &&
|
||||
range->we_version_compiled >= 18) {
|
||||
wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
|
||||
"WE(source)=%d enc_capa=0x%x",
|
||||
range->we_version_compiled,
|
||||
range->we_version_source,
|
||||
range->enc_capa);
|
||||
drv->we_version = range->we_version_compiled;
|
||||
}
|
||||
|
||||
free(range);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int i802_wireless_event_init(struct wpa_driver_nl80211_data *drv)
|
||||
{
|
||||
int s;
|
||||
struct sockaddr_nl local;
|
||||
|
||||
hostap_get_we_version(drv);
|
||||
|
||||
drv->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, drv,
|
||||
NULL);
|
||||
drv->wext_sock = s;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void i802_wireless_event_deinit(struct wpa_driver_nl80211_data *drv)
|
||||
{
|
||||
if (drv->wext_sock < 0)
|
||||
return;
|
||||
eloop_unregister_read_sock(drv->wext_sock);
|
||||
close(drv->wext_sock);
|
||||
}
|
||||
|
||||
|
||||
static int i802_sta_deauth(void *priv, const u8 *addr, int reason)
|
||||
{
|
||||
struct wpa_driver_nl80211_data *drv = priv;
|
||||
@ -5219,9 +5003,6 @@ static void *i802_init_bssid(struct hostapd_data *hapd, const u8 *bssid)
|
||||
if (i802_init_sockets(drv, bssid))
|
||||
goto failed;
|
||||
|
||||
if (i802_wireless_event_init(drv))
|
||||
goto failed;
|
||||
|
||||
return drv;
|
||||
|
||||
failed:
|
||||
@ -5241,8 +5022,6 @@ static void i802_deinit(void *priv)
|
||||
struct wpa_driver_nl80211_data *drv = priv;
|
||||
struct i802_bss *bss, *prev;
|
||||
|
||||
i802_wireless_event_deinit(drv);
|
||||
|
||||
if (drv->last_freq_ht) {
|
||||
/* Clear HT flags from the driver */
|
||||
struct hostapd_freq_params freq;
|
||||
@ -5269,6 +5048,7 @@ static void i802_deinit(void *priv)
|
||||
close(drv->eapol_sock);
|
||||
}
|
||||
|
||||
eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle));
|
||||
genl_family_put(drv->nl80211);
|
||||
nl_cache_free(drv->nl_cache);
|
||||
nl_handle_destroy(drv->nl_handle);
|
||||
|
Loading…
Reference in New Issue
Block a user