Merge branch 'moonshot' of ssh://moonshot.suchdamage.org:822/srv/git/libeap into...
[libeap.git] / wpa_supplicant / ap.c
index 5d79503..ea57540 100644 (file)
 
 #include "utils/common.h"
 #include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
 #include "ap/hostapd.h"
 #include "ap/ap_config.h"
 #ifdef NEED_AP_MLME
 #include "ap/ieee802_11.h"
 #endif /* NEED_AP_MLME */
+#include "ap/beacon.h"
 #include "ap/ieee802_1x.h"
 #include "ap/wps_hostapd.h"
 #include "ap/ctrl_iface_ap.h"
 #include "eap_server/eap_methods.h"
 #include "eap_common/eap_wsc_common.h"
 #include "wps/wps.h"
+#include "common/ieee802_11_defs.h"
 #include "config_ssid.h"
 #include "config.h"
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
+#include "p2p_supplicant.h"
 #include "ap.h"
+#include "ap/sta_info.h"
 
 
 static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
@@ -67,6 +72,34 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
        /* TODO: enable HT if driver supports it;
         * drop to 11b if driver does not support 11g */
 
+#ifdef CONFIG_P2P
+       if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
+               /* Remove 802.11b rates from supported and basic rate sets */
+               int *list = os_malloc(4 * sizeof(int));
+               if (list) {
+                       list[0] = 60;
+                       list[1] = 120;
+                       list[2] = 240;
+                       list[3] = -1;
+               }
+               conf->basic_rates = list;
+
+               list = os_malloc(9 * sizeof(int));
+               if (list) {
+                       list[0] = 60;
+                       list[1] = 90;
+                       list[2] = 120;
+                       list[3] = 180;
+                       list[4] = 240;
+                       list[5] = 360;
+                       list[6] = 480;
+                       list[7] = 540;
+                       list[8] = -1;
+               }
+               conf->supported_rates = list;
+       }
+#endif /* CONFIG_P2P */
+
        if (ssid->ssid_len == 0) {
                wpa_printf(MSG_ERROR, "No SSID configured for AP mode");
                return -1;
@@ -129,12 +162,107 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
                bss->config_methods = os_strdup(wpa_s->conf->config_methods);
        if (wpa_s->conf->device_type)
                bss->device_type = os_strdup(wpa_s->conf->device_type);
+       if (wpa_s->conf->device_name) {
+               bss->device_name = os_strdup(wpa_s->conf->device_name);
+               bss->friendly_name = os_strdup(wpa_s->conf->device_name);
+       }
+       if (wpa_s->conf->manufacturer)
+               bss->manufacturer = os_strdup(wpa_s->conf->manufacturer);
+       if (wpa_s->conf->model_name)
+               bss->model_name = os_strdup(wpa_s->conf->model_name);
+       if (wpa_s->conf->model_number)
+               bss->model_number = os_strdup(wpa_s->conf->model_number);
+       if (wpa_s->conf->serial_number)
+               bss->serial_number = os_strdup(wpa_s->conf->serial_number);
+       os_memcpy(bss->uuid, wpa_s->conf->uuid, WPS_UUID_LEN);
+       os_memcpy(bss->os_version, wpa_s->conf->os_version, 4);
 #endif /* CONFIG_WPS */
 
        return 0;
 }
 
 
+static void ap_public_action_rx(void *ctx, const u8 *buf, size_t len, int freq)
+{
+#ifdef CONFIG_P2P
+       struct wpa_supplicant *wpa_s = ctx;
+       const struct ieee80211_mgmt *mgmt;
+       size_t hdr_len;
+
+       mgmt = (const struct ieee80211_mgmt *) buf;
+       hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
+       if (hdr_len > len)
+               return;
+       wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
+                          mgmt->u.action.category,
+                          &mgmt->u.action.u.vs_public_action.action,
+                          len - hdr_len, freq);
+#endif /* CONFIG_P2P */
+}
+
+
+static void ap_wps_event_cb(void *ctx, enum wps_event event,
+                           union wps_event_data *data)
+{
+       struct wpa_supplicant *wpa_s = ctx;
+
+       if (event == WPS_EV_FAIL && wpa_s->parent && wpa_s->parent != wpa_s) {
+               struct wps_event_fail *fail = &data->fail;
+
+               /*
+                * src/ap/wps_hostapd.c has already sent this on the main
+                * interface, so only send on the parent interface here if
+                * needed.
+                */
+               wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
+                       "msg=%d config_error=%d",
+                       fail->msg, fail->config_error);
+       }
+}
+
+
+static int ap_vendor_action_rx(void *ctx, const u8 *buf, size_t len, int freq)
+{
+#ifdef CONFIG_P2P
+       struct wpa_supplicant *wpa_s = ctx;
+       const struct ieee80211_mgmt *mgmt;
+       size_t hdr_len;
+
+       mgmt = (const struct ieee80211_mgmt *) buf;
+       hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
+       if (hdr_len > len)
+               return -1;
+       wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
+                          mgmt->u.action.category,
+                          &mgmt->u.action.u.vs_public_action.action,
+                          len - hdr_len, freq);
+#endif /* CONFIG_P2P */
+       return 0;
+}
+
+
+static int ap_probe_req_rx(void *ctx, const u8 *addr, const u8 *ie,
+                          size_t ie_len)
+{
+#ifdef CONFIG_P2P
+       struct wpa_supplicant *wpa_s = ctx;
+       return wpas_p2p_probe_req_rx(wpa_s, addr, ie, ie_len);
+#else /* CONFIG_P2P */
+       return 0;
+#endif /* CONFIG_P2P */
+}
+
+
+static void ap_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
+                                 const u8 *uuid_e)
+{
+#ifdef CONFIG_P2P
+       struct wpa_supplicant *wpa_s = ctx;
+       wpas_p2p_wps_success(wpa_s, mac_addr, 1);
+#endif /* CONFIG_P2P */
+}
+
+
 int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
                             struct wpa_ssid *ssid)
 {
@@ -164,6 +292,8 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
                params.mode = IEEE80211_MODE_IBSS;
                break;
        case WPAS_MODE_AP:
+       case WPAS_MODE_P2P_GO:
+       case WPAS_MODE_P2P_GROUP_FORMATION:
                params.mode = IEEE80211_MODE_AP;
                break;
        }
@@ -189,6 +319,18 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
        params.pairwise_suite = cipher_suite2driver(wpa_s->pairwise_cipher);
        params.group_suite = params.pairwise_suite;
 
+#ifdef CONFIG_P2P
+       if (ssid->mode == WPAS_MODE_P2P_GO ||
+           ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
+               params.p2p = 1;
+       wpa_drv_set_intra_bss(wpa_s, wpa_s->conf->p2p_intra_bss);
+#endif /* CONFIG_P2P */
+
+       if (wpa_s->parent->set_ap_uapsd)
+               params.uapsd = wpa_s->parent->ap_uapsd;
+       else
+               params.uapsd = -1;
+
        if (wpa_drv_associate(wpa_s, &params) < 0) {
                wpa_msg(wpa_s, MSG_INFO, "Failed to start AP functionality");
                return -1;
@@ -211,6 +353,14 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
                return -1;
        }
 
+#ifdef CONFIG_P2P
+       if (ssid->mode == WPAS_MODE_P2P_GO)
+               conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER;
+       else if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
+               conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER |
+                       P2P_GROUP_FORMATION;
+#endif /* CONFIG_P2P */
+
        hapd_iface->num_bss = conf->num_bss;
        hapd_iface->bss = os_zalloc(conf->num_bss *
                                    sizeof(struct hostapd_data *));
@@ -229,6 +379,22 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
                }
 
                hapd_iface->bss[i]->msg_ctx = wpa_s;
+               hapd_iface->bss[i]->public_action_cb = ap_public_action_rx;
+               hapd_iface->bss[i]->public_action_cb_ctx = wpa_s;
+               hapd_iface->bss[i]->vendor_action_cb = ap_vendor_action_rx;
+               hapd_iface->bss[i]->vendor_action_cb_ctx = wpa_s;
+               hostapd_register_probereq_cb(hapd_iface->bss[i],
+                                            ap_probe_req_rx, wpa_s);
+               hapd_iface->bss[i]->wps_reg_success_cb = ap_wps_reg_success_cb;
+               hapd_iface->bss[i]->wps_reg_success_cb_ctx = wpa_s;
+               hapd_iface->bss[i]->wps_event_cb = ap_wps_event_cb;
+               hapd_iface->bss[i]->wps_event_cb_ctx = wpa_s;
+#ifdef CONFIG_P2P
+               hapd_iface->bss[i]->p2p = wpa_s->global->p2p;
+               hapd_iface->bss[i]->p2p_group = wpas_p2p_group_init(
+                       wpa_s, ssid->p2p_persistent_group,
+                       ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION);
+#endif /* CONFIG_P2P */
        }
 
        os_memcpy(hapd_iface->bss[0]->own_addr, wpa_s->own_addr, ETH_ALEN);
@@ -243,6 +409,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
 
        wpa_s->current_ssid = ssid;
        os_memcpy(wpa_s->bssid, wpa_s->own_addr, ETH_ALEN);
+       wpa_s->assoc_freq = ssid->frequency;
        wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
 
        if (wpa_s->ap_configured_cb)
@@ -259,6 +426,11 @@ void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s)
                return;
 
        wpa_s->current_ssid = NULL;
+#ifdef CONFIG_P2P
+       if (wpa_s->ap_iface->bss)
+               wpa_s->ap_iface->bss[0]->p2p_group = NULL;
+       wpas_p2p_group_deinit(wpa_s);
+#endif /* CONFIG_P2P */
        hostapd_interface_deinit(wpa_s->ap_iface);
        hostapd_interface_free(wpa_s->ap_iface);
        wpa_s->ap_iface = NULL;
@@ -330,6 +502,51 @@ int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid)
 }
 
 
+static int wpa_supplicant_ap_wps_sta_cancel(struct hostapd_data *hapd,
+                                           struct sta_info *sta, void *ctx)
+{
+       if (sta && (sta->flags & WLAN_STA_WPS)) {
+               ap_sta_deauthenticate(hapd, sta,
+                                     WLAN_REASON_PREV_AUTH_NOT_VALID);
+               wpa_printf(MSG_DEBUG, "WPS: %s: Deauth sta=" MACSTR,
+                          __func__, MAC2STR(sta->addr));
+               return 1;
+       }
+
+       return 0;
+}
+
+
+int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s)
+{
+       struct wps_registrar *reg;
+       int reg_sel = 0, wps_sta = 0;
+
+       if (!wpa_s->ap_iface || !wpa_s->ap_iface->bss[0]->wps)
+               return -1;
+
+       reg = wpa_s->ap_iface->bss[0]->wps->registrar;
+       reg_sel = wps_registrar_wps_cancel(reg);
+       wps_sta = ap_for_each_sta(wpa_s->ap_iface->bss[0],
+                                 wpa_supplicant_ap_wps_sta_cancel, NULL);
+
+       if (!reg_sel && !wps_sta) {
+               wpa_printf(MSG_DEBUG, "No WPS operation in progress at this "
+                          "time");
+               return -1;
+       }
+
+       /*
+        * There are 2 cases to return wps cancel as success:
+        * 1. When wps cancel was initiated but no connection has been
+        *    established with client yet.
+        * 2. Client is in the middle of exchanging WPS messages.
+        */
+
+       return 0;
+}
+
+
 int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
                              const char *pin, char *buf, size_t buflen)
 {
@@ -342,9 +559,11 @@ int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
                unsigned int rpin = wps_generate_pin();
                ret_len = os_snprintf(buf, buflen, "%d", rpin);
                pin = buf;
-       }
+       } else
+               ret_len = os_snprintf(buf, buflen, "%s", pin);
 
-       ret = hostapd_wps_add_pin(wpa_s->ap_iface->bss[0], "any", pin, 0);
+       ret = hostapd_wps_add_pin(wpa_s->ap_iface->bss[0], bssid, "any", pin,
+                                 0);
        if (ret)
                return -1;
        return ret_len;
@@ -416,6 +635,31 @@ int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf,
 #endif /* CONFIG_CTRL_IFACE */
 
 
+int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s)
+{
+       struct hostapd_iface *iface = wpa_s->ap_iface;
+       struct wpa_ssid *ssid = wpa_s->current_ssid;
+       struct hostapd_data *hapd;
+
+       if (ssid == NULL || wpa_s->ap_iface == NULL)
+               return -1;
+
+#ifdef CONFIG_P2P
+       if (ssid->mode == WPAS_MODE_P2P_GO)
+               iface->conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER;
+       else if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
+               iface->conf->bss[0].p2p = P2P_ENABLED | P2P_GROUP_OWNER |
+                       P2P_GROUP_FORMATION;
+#endif /* CONFIG_P2P */
+
+       ieee802_11_set_beacons(iface);
+       hapd = iface->bss[0];
+       hapd->drv.set_ap_wps_ie(hapd);
+
+       return 0;
+}
+
+
 int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
                                      const u8 *addr)
 {