P2P: Extend P2P manager functionality to work with driver MLME
[libeap.git] / src / ap / ieee802_11.c
index 316965b..c73a794 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / IEEE 802.11 Management
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
 #include "utils/eloop.h"
 #include "crypto/crypto.h"
 #include "drivers/driver.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
 #include "common/wpa_ctrl.h"
 #include "radius/radius.h"
 #include "radius/radius_client.h"
+#include "p2p/p2p.h"
+#include "wps/wps.h"
 #include "hostapd.h"
-#include "ieee802_11.h"
 #include "beacon.h"
 #include "ieee802_11_auth.h"
 #include "sta_info.h"
 #include "ieee802_1x.h"
-#include "wpa.h"
+#include "wpa_auth.h"
 #include "wmm.h"
 #include "ap_list.h"
 #include "accounting.h"
-#include "config.h"
-#include "mlme.h"
+#include "ap_config.h"
+#include "ap_mlme.h"
+#include "p2p_hostapd.h"
+#include "ieee802_11.h"
 
 
 u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
@@ -188,33 +193,6 @@ void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len)
 }
 
 
-/**
- * ieee802_11_send_deauth - Send Deauthentication frame
- * @hapd: hostapd BSS data
- * @addr: Address of the destination STA
- * @reason: Reason code for Deauthentication
- */
-void ieee802_11_send_deauth(struct hostapd_data *hapd, const u8 *addr,
-                           u16 reason)
-{
-       struct ieee80211_mgmt mgmt;
-
-       hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
-                      HOSTAPD_LEVEL_DEBUG,
-                      "deauthenticate - reason %d", reason);
-       os_memset(&mgmt, 0, sizeof(mgmt));
-       mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-                                         WLAN_FC_STYPE_DEAUTH);
-       os_memcpy(mgmt.da, addr, ETH_ALEN);
-       os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
-       os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
-       mgmt.u.deauth.reason_code = host_to_le16(reason);
-       if (hapd->drv.send_mgmt_frame(hapd, &mgmt, IEEE80211_HDRLEN +
-                                      sizeof(mgmt.u.deauth)) < 0)
-               perror("ieee802_11_send_deauth: send");
-}
-
-
 static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
                           u16 auth_transaction, const u8 *challenge,
                           int iswep)
@@ -679,21 +657,24 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
 
 #ifdef CONFIG_WPS
        sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
-       if (hapd->conf->wps_state && wpa_ie == NULL) {
-               if (elems.wps_ie) {
-                       wpa_printf(MSG_DEBUG, "STA included WPS IE in "
-                                  "(Re)Association Request - assume WPS is "
-                                  "used");
-                       sta->flags |= WLAN_STA_WPS;
-                       wpabuf_free(sta->wps_ie);
-                       sta->wps_ie = wpabuf_alloc_copy(elems.wps_ie + 4,
-                                                       elems.wps_ie_len - 4);
-               } else {
-                       wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE "
-                                  "in (Re)Association Request - possible WPS "
-                                  "use");
-                       sta->flags |= WLAN_STA_MAYBE_WPS;
+       if (hapd->conf->wps_state && elems.wps_ie) {
+               wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
+                          "Request - assume WPS is used");
+               sta->flags |= WLAN_STA_WPS;
+               wpabuf_free(sta->wps_ie);
+               sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
+                                                         WPS_IE_VENDOR_TYPE);
+               wpa_ie = NULL;
+               wpa_ie_len = 0;
+               if (sta->wps_ie && wps_validate_assoc_req(sta->wps_ie) < 0) {
+                       wpa_printf(MSG_DEBUG, "WPS: Invalid WPS IE in "
+                                  "(Re)Association Request - reject");
+                       return WLAN_STATUS_INVALID_IE;
                }
+       } else if (hapd->conf->wps_state && wpa_ie == NULL) {
+               wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE in "
+                          "(Re)Association Request - possible WPS use");
+               sta->flags |= WLAN_STA_MAYBE_WPS;
        } else
 #endif /* CONFIG_WPS */
        if (hapd->conf->wpa && wpa_ie == NULL) {
@@ -794,6 +775,25 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
        } else
                wpa_auth_sta_no_wpa(sta->wpa_sm);
 
+#ifdef CONFIG_P2P
+       if (elems.p2p) {
+               wpabuf_free(sta->p2p_ie);
+               sta->p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
+                                                         P2P_IE_VENDOR_TYPE);
+
+               if (p2p_group_notif_assoc(hapd->p2p_group, sta->addr,
+                                         ies, ies_len) < 0) {
+                       wpa_printf(MSG_DEBUG, "P2P: Invalid P2P IE in "
+                                  "(Re)Association Request frame from "
+                                  MACSTR, MAC2STR(sta->addr));
+                       return WLAN_STATUS_UNSPECIFIED_FAILURE;
+               }
+       } else {
+               wpabuf_free(sta->p2p_ie);
+               sta->p2p_ie = NULL;
+       }
+#endif /* CONFIG_P2P */
+
        return WLAN_STATUS_SUCCESS;
 }
 
@@ -850,13 +850,6 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
        p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable);
        /* Extended supported rates */
        p = hostapd_eid_ext_supp_rates(hapd, p);
-       if (sta->flags & WLAN_STA_WMM)
-               p = hostapd_eid_wmm(hapd, p);
-
-#ifdef CONFIG_IEEE80211N
-       p = hostapd_eid_ht_capabilities(hapd, p);
-       p = hostapd_eid_ht_operation(hapd, p);
-#endif /* CONFIG_IEEE80211N */
 
 #ifdef CONFIG_IEEE80211R
        if (status_code == WLAN_STATUS_SUCCESS) {
@@ -873,6 +866,55 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
                p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
 #endif /* CONFIG_IEEE80211W */
 
+#ifdef CONFIG_IEEE80211N
+       p = hostapd_eid_ht_capabilities(hapd, p);
+       p = hostapd_eid_ht_operation(hapd, p);
+#endif /* CONFIG_IEEE80211N */
+
+       if (sta->flags & WLAN_STA_WMM)
+               p = hostapd_eid_wmm(hapd, p);
+
+#ifdef CONFIG_WPS
+       if (sta->flags & WLAN_STA_WPS) {
+               struct wpabuf *wps = wps_build_assoc_resp_ie();
+               if (wps) {
+                       os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps));
+                       p += wpabuf_len(wps);
+                       wpabuf_free(wps);
+               }
+       }
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+       if (sta->p2p_ie) {
+               struct wpabuf *p2p_resp_ie;
+               enum p2p_status_code status;
+               switch (status_code) {
+               case WLAN_STATUS_SUCCESS:
+                       status = P2P_SC_SUCCESS;
+                       break;
+               case WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA:
+                       status = P2P_SC_FAIL_LIMIT_REACHED;
+                       break;
+               default:
+                       status = P2P_SC_FAIL_INVALID_PARAMS;
+                       break;
+               }
+               p2p_resp_ie = p2p_group_assoc_resp_ie(hapd->p2p_group, status);
+               if (p2p_resp_ie) {
+                       os_memcpy(p, wpabuf_head(p2p_resp_ie),
+                                 wpabuf_len(p2p_resp_ie));
+                       p += wpabuf_len(p2p_resp_ie);
+                       wpabuf_free(p2p_resp_ie);
+               }
+       }
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_P2P_MANAGER
+       if (hapd->conf->p2p & P2P_MANAGE)
+               p = hostapd_eid_p2p_manage(hapd, p);
+#endif /* CONFIG_P2P_MANAGER */
+
        send_len += p - reply->u.assoc_resp.variable;
 
        if (hapd->drv.send_mgmt_frame(hapd, reply, send_len) < 0)
@@ -1190,6 +1232,46 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
 }
 
 
+static void hostapd_sa_query_request(struct hostapd_data *hapd,
+                                    const struct ieee80211_mgmt *mgmt)
+{
+       struct sta_info *sta;
+       struct ieee80211_mgmt resp;
+       u8 *end;
+
+       wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from "
+                  MACSTR, MAC2STR(mgmt->sa));
+       wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
+                   mgmt->u.action.u.sa_query_resp.trans_id,
+                   WLAN_SA_QUERY_TR_ID_LEN);
+
+       sta = ap_get_sta(hapd, mgmt->sa);
+       if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
+               wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request "
+                          "from unassociated STA " MACSTR, MAC2STR(mgmt->sa));
+               return;
+       }
+
+       wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to "
+                  MACSTR, MAC2STR(mgmt->sa));
+
+       os_memset(&resp, 0, sizeof(resp));
+       resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+                                         WLAN_FC_STYPE_ACTION);
+       os_memcpy(resp.da, mgmt->sa, ETH_ALEN);
+       os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN);
+       os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN);
+       resp.u.action.category = WLAN_ACTION_SA_QUERY;
+       resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
+       os_memcpy(resp.u.action.u.sa_query_req.trans_id,
+                 mgmt->u.action.u.sa_query_req.trans_id,
+                 WLAN_SA_QUERY_TR_ID_LEN);
+       end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
+       if (hapd->drv.send_mgmt_frame(hapd, &resp, end - (u8 *) &resp) < 0)
+               perror("hostapd_sa_query_request: send");
+}
+
+
 static void hostapd_sa_query_action(struct hostapd_data *hapd,
                                    const struct ieee80211_mgmt *mgmt,
                                    size_t len)
@@ -1206,6 +1288,11 @@ static void hostapd_sa_query_action(struct hostapd_data *hapd,
                return;
        }
 
+       if (mgmt->u.action.u.sa_query_resp.action == WLAN_SA_QUERY_REQUEST) {
+               hostapd_sa_query_request(hapd, mgmt);
+               return;
+       }
+
        if (mgmt->u.action.u.sa_query_resp.action != WLAN_SA_QUERY_RESPONSE) {
                wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query "
                           "Action %d", mgmt->u.action.u.sa_query_resp.action);
@@ -1308,6 +1395,22 @@ static void handle_action(struct hostapd_data *hapd,
                hostapd_sa_query_action(hapd, mgmt, len);
                return;
 #endif /* CONFIG_IEEE80211W */
+       case WLAN_ACTION_PUBLIC:
+               if (hapd->public_action_cb) {
+                       hapd->public_action_cb(hapd->public_action_cb_ctx,
+                                              (u8 *) mgmt, len,
+                                              hapd->iface->freq);
+                       return;
+               }
+               break;
+       case WLAN_ACTION_VENDOR_SPECIFIC:
+               if (hapd->vendor_action_cb) {
+                       if (hapd->vendor_action_cb(hapd->vendor_action_cb_ctx,
+                                                  (u8 *) mgmt, len,
+                                                  hapd->iface->freq) == 0)
+                               return;
+               }
+               break;
        }
 
        hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
@@ -1520,8 +1623,12 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
        if (sta->flags & WLAN_STA_ASSOC)
                new_assoc = 0;
        sta->flags |= WLAN_STA_ASSOC;
-       if (!hapd->conf->ieee802_1x && !hapd->conf->wpa) {
-               /* Open or static WEP; no separate authorization */
+       if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa) ||
+           sta->auth_alg == WLAN_AUTH_FT) {
+               /*
+                * Open, static WEP, or FT protocol; no separate authorization
+                * step.
+                */
                sta->flags |= WLAN_STA_AUTHORIZED;
                wpa_msg(hapd->msg_ctx, MSG_INFO,
                        AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
@@ -1548,9 +1655,9 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
                hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
 #endif /* CONFIG_IEEE80211N */
 
-       if (hapd->drv.sta_add(hapd->conf->iface, hapd, sta->addr, sta->aid,
-                             sta->capability, sta->supported_rates,
-                             sta->supported_rates_len, sta->listen_interval,
+       if (hapd->drv.sta_add(hapd, sta->addr, sta->aid, sta->capability,
+                             sta->supported_rates, sta->supported_rates_len,
+                             sta->listen_interval,
                              sta->flags & WLAN_STA_HT ? &ht_cap : NULL)) {
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
                               HOSTAPD_LEVEL_NOTICE,
@@ -1563,10 +1670,12 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
                 * so bind it to the selected VLAN interface now, since the
                 * interface selection is not going to change anymore.
                 */
-               ap_sta_bind_vlan(hapd, sta, 0);
+               if (ap_sta_bind_vlan(hapd, sta, 0) < 0)
+                       goto fail;
        } else if (sta->vlan_id) {
                /* VLAN ID already set (e.g., by PMKSA caching), so bind STA */
-               ap_sta_bind_vlan(hapd, sta, 0);
+               if (ap_sta_bind_vlan(hapd, sta, 0) < 0)
+                       goto fail;
        }
 
        hapd->drv.set_sta_flags(hapd, sta);
@@ -1617,7 +1726,7 @@ void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
                handle_assoc_cb(hapd, mgmt, len, 1, ok);
                break;
        case WLAN_FC_STYPE_PROBE_RESP:
-               wpa_printf(MSG_DEBUG, "mgmt::proberesp cb");
+               wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb");
                break;
        case WLAN_FC_STYPE_DEAUTH:
                /* ignore */