nl80211: Replace hostapd WEXT events with nl80211 events
authorJouni Malinen <jouni.malinen@atheros.com>
Thu, 9 Apr 2009 14:10:22 +0000 (17:10 +0300)
committerJouni Malinen <j@w1.fi>
Thu, 9 Apr 2009 14:10:22 +0000 (17:10 +0300)
This shares the nl80211 event processing with wpa_supplicant and removes
the old WEXT code from driver_nl80211.c.

src/drivers/driver_nl80211.c

index 41819a6..96acef9 100644 (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);