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:
Jouni Malinen 2009-04-09 17:10:22 +03:00 committed by Jouni Malinen
parent 35583f3fa6
commit 5b7b85f669

View file

@ -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);