]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - src/drivers/driver_nl80211.c
Move struct hostapd_frame_info definition away from driver API
[thirdparty/hostap.git] / src / drivers / driver_nl80211.c
index 67043a622cd85ad27190a43b7069e363f9e9a24c..f4e45e77aee910bdb4c9b5a80bff583e2ead9263 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Driver interaction with Linux nl80211/cfg80211
- * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
  * Copyright (c) 2003-2004, Instant802 Networks, Inc.
  * Copyright (c) 2005-2006, Devicescape Software, Inc.
  * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
@@ -91,6 +91,7 @@ struct wpa_driver_nl80211_data {
        size_t ssid_len;
        int nlmode;
        int ap_scan_as_station;
+       unsigned int assoc_freq;
 
        int monitor_sock;
        int monitor_ifidx;
@@ -536,6 +537,8 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
                        len - 24 - sizeof(mgmt->u.assoc_resp);
        }
 
+       event.assoc_info.freq = drv->assoc_freq;
+
        wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
 }
 
@@ -704,6 +707,47 @@ static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
 }
 
 
+static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
+                           struct nlattr *tb[])
+{
+       union wpa_event_data event;
+       struct nlattr *nl;
+       int rem;
+       struct scan_info *info;
+#define MAX_REPORT_FREQS 50
+       int freqs[MAX_REPORT_FREQS];
+       int num_freqs = 0;
+
+       os_memset(&event, 0, sizeof(event));
+       info = &event.scan_info;
+       info->aborted = aborted;
+
+       if (tb[NL80211_ATTR_SCAN_SSIDS]) {
+               nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) {
+                       struct wpa_driver_scan_ssid *s =
+                               &info->ssids[info->num_ssids];
+                       s->ssid = nla_data(nl);
+                       s->ssid_len = nla_len(nl);
+                       info->num_ssids++;
+                       if (info->num_ssids == WPAS_MAX_SCAN_SSIDS)
+                               break;
+               }
+       }
+       if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
+               nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem)
+               {
+                       freqs[num_freqs] = nla_get_u32(nl);
+                       num_freqs++;
+                       if (num_freqs == MAX_REPORT_FREQS - 1)
+                               break;
+               }
+               info->freqs = freqs;
+               info->num_freqs = num_freqs;
+       }
+       wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
+}
+
+
 static int process_event(struct nl_msg *msg, void *arg)
 {
        struct wpa_driver_nl80211_data *drv = arg;
@@ -739,7 +783,7 @@ static int process_event(struct nl_msg *msg, void *arg)
                drv->scan_complete_events = 1;
                eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
                                     drv->ctx);
-               wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
+               send_scan_event(drv, 0, tb);
                break;
        case NL80211_CMD_SCAN_ABORTED:
                wpa_printf(MSG_DEBUG, "nl80211: Scan aborted");
@@ -749,7 +793,7 @@ static int process_event(struct nl_msg *msg, void *arg)
                 */
                eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
                                     drv->ctx);
-               wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
+               send_scan_event(drv, 1, tb);
                break;
        case NL80211_CMD_AUTHENTICATE:
        case NL80211_CMD_ASSOCIATE:
@@ -976,6 +1020,9 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
                WPA_DRIVER_CAPA_ENC_WEP104 |
                WPA_DRIVER_CAPA_ENC_TKIP |
                WPA_DRIVER_CAPA_ENC_CCMP;
+       drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
+               WPA_DRIVER_AUTH_SHARED |
+               WPA_DRIVER_AUTH_LEAP;
 
        drv->capa.max_scan_ssids = info.max_scan_ssids;
        if (info.ap_supported)
@@ -1620,8 +1667,8 @@ nla_put_failure:
 
 
 static int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
-                                     wpa_alg alg, const u8 *addr, int key_idx,
-                                     int set_tx,
+                                     enum wpa_alg alg, const u8 *addr,
+                                     int key_idx, int set_tx,
                                      const u8 *seq, size_t seq_len,
                                      const u8 *key, size_t key_len)
 {
@@ -1730,7 +1777,7 @@ nla_put_failure:
 }
 
 
-static int nl_add_key(struct nl_msg *msg, wpa_alg alg,
+static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
                      int key_idx, int defkey,
                      const u8 *seq, size_t seq_len,
                      const u8 *key, size_t key_len)
@@ -2532,6 +2579,8 @@ static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
 {
        struct nl_msg *msg;
 
+       wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx);
+
 #ifdef HOSTAPD
        /* stop listening for EAPOL on this interface */
        del_ifidx(drv, ifidx);
@@ -2600,6 +2649,8 @@ static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
        }
 
        ifidx = if_nametoindex(ifname);
+       wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
+                  ifname, ifidx);
 
        if (ifidx <= 0)
                return -1;
@@ -2664,19 +2715,18 @@ static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok)
 
 
 static void from_unknown_sta(struct wpa_driver_nl80211_data *drv,
-                            struct ieee80211_hdr *hdr, size_t len)
+                            u8 *buf, size_t len)
 {
        union wpa_event_data event;
        os_memset(&event, 0, sizeof(event));
-       event.rx_from_unknown.hdr = hdr;
+       event.rx_from_unknown.frame = buf;
        event.rx_from_unknown.len = len;
        wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
 }
 
 
 static void handle_frame(struct wpa_driver_nl80211_data *drv,
-                        u8 *buf, size_t len,
-                        struct hostapd_frame_info *hfi)
+                        u8 *buf, size_t len, int datarate, int ssi_signal)
 {
        struct ieee80211_hdr *hdr;
        u16 fc;
@@ -2690,16 +2740,17 @@ static void handle_frame(struct wpa_driver_nl80211_data *drv,
                os_memset(&event, 0, sizeof(event));
                event.rx_mgmt.frame = buf;
                event.rx_mgmt.frame_len = len;
-               event.rx_mgmt.fi = hfi;
+               event.rx_mgmt.datarate = datarate;
+               event.rx_mgmt.ssi_signal = ssi_signal;
                wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
                break;
        case WLAN_FC_TYPE_CTRL:
                /* can only get here with PS-Poll frames */
                wpa_printf(MSG_DEBUG, "CTRL");
-               from_unknown_sta(drv, hdr, len);
+               from_unknown_sta(drv, buf, len);
                break;
        case WLAN_FC_TYPE_DATA:
-               from_unknown_sta(drv, hdr, len);
+               from_unknown_sta(drv, buf, len);
                break;
        }
 }
@@ -2712,7 +2763,7 @@ static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
        unsigned char buf[3000];
        struct ieee80211_radiotap_iterator iter;
        int ret;
-       struct hostapd_frame_info hfi;
+       int datarate = 0, ssi_signal = 0;
        int injected = 0, failed = 0, rxflags = 0;
 
        len = recv(sock, buf, sizeof(buf), 0);
@@ -2726,8 +2777,6 @@ static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
                return;
        }
 
-       memset(&hfi, 0, sizeof(hfi));
-
        while (1) {
                ret = ieee80211_radiotap_iterator_next(&iter);
                if (ret == -ENOENT)
@@ -2752,15 +2801,13 @@ static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
                case IEEE80211_RADIOTAP_DATA_RETRIES:
                        break;
                case IEEE80211_RADIOTAP_CHANNEL:
-                       /* TODO convert from freq/flags to channel number
-                       hfi.channel = XXX;
-                        */
+                       /* TODO: convert from freq/flags to channel number */
                        break;
                case IEEE80211_RADIOTAP_RATE:
-                       hfi.datarate = *iter.this_arg * 5;
+                       datarate = *iter.this_arg * 5;
                        break;
                case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
-                       hfi.ssi_signal = *iter.this_arg;
+                       ssi_signal = *iter.this_arg;
                        break;
                }
        }
@@ -2770,7 +2817,7 @@ static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
 
        if (!injected)
                handle_frame(drv, buf + iter.max_length,
-                            len - iter.max_length, &hfi);
+                            len - iter.max_length, datarate, ssi_signal);
        else
                handle_tx_callback(drv->ctx, buf + iter.max_length,
                                   len - iter.max_length, !failed);
@@ -3442,7 +3489,9 @@ static int wpa_driver_nl80211_associate(
        if (params->freq) {
                wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
                NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
-       }
+               drv->assoc_freq = params->freq;
+       } else
+               drv->assoc_freq = 0;
        if (params->ssid) {
                wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
                                  params->ssid, params->ssid_len);
@@ -3541,6 +3590,8 @@ static int wpa_driver_nl80211_set_mode(void *priv, int mode)
        }
 
        if (nlmode == drv->nlmode) {
+               wpa_printf(MSG_DEBUG, "nl80211: Interface already in "
+                          "requested mode - ignore error");
                ret = 0;
                goto done; /* Already in the requested mode */
        }
@@ -3556,8 +3607,11 @@ static int wpa_driver_nl80211_set_mode(void *priv, int mode)
                        ret = -1;
        }
 
-       if (!ret)
+       if (!ret) {
+               wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while "
+                          "interface is down");
                drv->nlmode = nlmode;
+       }
 
 done:
        if (!ret && nlmode == NL80211_IFTYPE_AP) {
@@ -3570,6 +3624,10 @@ done:
                nl80211_remove_monitor_interface(drv);
        }
 
+       if (ret)
+               wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
+                          "from %d failed", nlmode, drv->nlmode);
+
        return ret;
 }