From 5b7b85f669afbd508f9a06d1b7729556b0a75ff4 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 9 Apr 2009 17:10:22 +0300 Subject: [PATCH] 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. --- src/drivers/driver_nl80211.c | 312 ++++++----------------------------- 1 file changed, 46 insertions(+), 266 deletions(-) diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 41819a6c8..96acef9a2 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -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);