Merge branch 'moonshot' of ssh://moonshot.suchdamage.org:822/srv/git/libeap into...
[libeap.git] / wpa_supplicant / wpa_supplicant.c
index 5d67691..61d1c87 100644 (file)
 #include "common/wpa_ctrl.h"
 #include "mlme.h"
 #include "common/ieee802_11_defs.h"
+#include "p2p/p2p.h"
 #include "blacklist.h"
 #include "wpas_glue.h"
 #include "wps_supplicant.h"
 #include "ibss_rsn.h"
 #include "sme.h"
 #include "ap.h"
+#include "p2p_supplicant.h"
 #include "notify.h"
 #include "bgscan.h"
 #include "bss.h"
@@ -427,6 +429,10 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 #ifdef CONFIG_AP
        wpa_supplicant_ap_deinit(wpa_s);
 #endif /* CONFIG_AP */
+
+#ifdef CONFIG_P2P
+       wpas_p2p_deinit(wpa_s);
+#endif /* CONFIG_P2P */
 }
 
 
@@ -545,6 +551,9 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
                wpa_s->reassociated_connection = 1;
                wpa_drv_set_operstate(wpa_s, 1);
                wpa_s->after_wps = 0;
+#ifdef CONFIG_P2P
+               wpas_p2p_completed(wpa_s);
+#endif /* CONFIG_P2P */
        } else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
                   state == WPA_ASSOCIATED) {
                wpa_s->new_connection = 1;
@@ -586,7 +595,7 @@ static void wpa_supplicant_terminate(int sig, void *signal_ctx)
 }
 
 
-static void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
+void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
 {
        enum wpa_states old_state = wpa_s->wpa_state;
 
@@ -628,6 +637,7 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
                        "file '%s' - exiting", wpa_s->confname);
                return -1;
        }
+       conf->changed_parameters = (unsigned int) -1;
 
        reconf_ctrl = !!conf->ctrl_interface != !!wpa_s->conf->ctrl_interface
                || (conf->ctrl_interface && wpa_s->conf->ctrl_interface &&
@@ -670,9 +680,13 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
        if (reconf_ctrl)
                wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
 
+       wpa_supplicant_update_config(wpa_s);
+
        wpa_supplicant_clear_status(wpa_s);
-       wpa_s->reassociate = 1;
-       wpa_supplicant_req_scan(wpa_s, 0, 0);
+       if (wpa_supplicant_enabled_networks(wpa_s->conf)) {
+               wpa_s->reassociate = 1;
+               wpa_supplicant_req_scan(wpa_s, 0, 0);
+       }
        wpa_msg(wpa_s, MSG_DEBUG, "Reconfiguration completed");
        return 0;
 }
@@ -991,7 +1005,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                              struct wpa_bss *bss, struct wpa_ssid *ssid)
 {
-       u8 wpa_ie[80];
+       u8 wpa_ie[200];
        size_t wpa_ie_len;
        int use_crypt, ret, i, bssid_changed;
        int algs = WPA_AUTH_ALG_OPEN;
@@ -1002,7 +1016,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        int assoc_failed = 0;
        struct wpa_ssid *old_ssid;
 
-       if (ssid->mode == WPAS_MODE_AP) {
+       if (ssid->mode == WPAS_MODE_AP || ssid->mode == WPAS_MODE_P2P_GO ||
+           ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
 #ifdef CONFIG_AP
                if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP)) {
                        wpa_printf(MSG_INFO, "Driver does not support AP "
@@ -1024,6 +1039,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                return;
        }
 
+       os_memset(&params, 0, sizeof(params));
        wpa_s->reassociate = 0;
        if (bss) {
 #ifdef CONFIG_IEEE80211R
@@ -1131,12 +1147,46 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
                        wpa_ie_len = 0;
                wpabuf_free(wps_ie);
                wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+               if (!bss || (bss->caps & IEEE80211_CAP_PRIVACY))
+                       params.wps = WPS_MODE_PRIVACY;
+               else
+                       params.wps = WPS_MODE_OPEN;
 #endif /* CONFIG_WPS */
        } else {
                wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
                wpa_ie_len = 0;
        }
 
+#ifdef CONFIG_P2P
+       if (wpa_s->global->p2p) {
+               u8 *pos;
+               size_t len;
+               int res;
+               int p2p_group;
+               p2p_group = wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE;
+               pos = wpa_ie + wpa_ie_len;
+               len = sizeof(wpa_ie) - wpa_ie_len;
+               res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len, p2p_group);
+               if (res >= 0)
+                       wpa_ie_len += res;
+       }
+
+       wpa_s->cross_connect_disallowed = 0;
+       if (bss) {
+               struct wpabuf *p2p;
+               p2p = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
+               if (p2p) {
+                       wpa_s->cross_connect_disallowed =
+                               p2p_get_cross_connect_disallowed(p2p);
+                       wpabuf_free(p2p);
+                       wpa_printf(MSG_DEBUG, "P2P: WLAN AP %s cross "
+                                  "connection",
+                                  wpa_s->cross_connect_disallowed ?
+                                  "disallows" : "allows");
+               }
+       }
+#endif /* CONFIG_P2P */
+
        wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
        use_crypt = 1;
        cipher_pairwise = cipher_suite2driver(wpa_s->pairwise_cipher);
@@ -1175,7 +1225,6 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        }
 
        wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
-       os_memset(&params, 0, sizeof(params));
        if (bss) {
                params.bssid = bss->bssid;
                params.ssid = bss->ssid;
@@ -1228,6 +1277,17 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
        }
 #endif /* CONFIG_IEEE80211W */
 
+#ifdef CONFIG_P2P
+       if (wpa_s->global->p2p &&
+           (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE))
+               params.p2p = 1;
+#endif /* CONFIG_P2P */
+
+       if (wpa_s->parent->set_sta_uapsd)
+               params.uapsd = wpa_s->parent->sta_uapsd;
+       else
+               params.uapsd = -1;
+
        if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
                ret = ieee80211_sta_associate(wpa_s, &params);
        else
@@ -1296,6 +1356,24 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 }
 
 
+static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
+                                           const u8 *addr)
+{
+       struct wpa_ssid *old_ssid;
+
+       wpa_clear_keys(wpa_s, addr);
+       wpa_supplicant_mark_disassoc(wpa_s);
+       old_ssid = wpa_s->current_ssid;
+       wpa_s->current_ssid = NULL;
+       wpa_s->current_bss = NULL;
+       wpa_sm_set_config(wpa_s->wpa, NULL);
+       eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+       if (old_ssid != wpa_s->current_ssid)
+               wpas_notify_network_changed(wpa_s);
+       eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+}
+
+
 /**
  * wpa_supplicant_disassociate - Disassociate the current connection
  * @wpa_s: Pointer to wpa_supplicant data
@@ -1307,7 +1385,6 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
                                 int reason_code)
 {
-       struct wpa_ssid *old_ssid;
        u8 *addr = NULL;
 
        if (!is_zero_ether_addr(wpa_s->bssid)) {
@@ -1317,16 +1394,8 @@ void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
                        wpa_drv_disassociate(wpa_s, wpa_s->bssid, reason_code);
                addr = wpa_s->bssid;
        }
-       wpa_clear_keys(wpa_s, addr);
-       wpa_supplicant_mark_disassoc(wpa_s);
-       old_ssid = wpa_s->current_ssid;
-       wpa_s->current_ssid = NULL;
-       wpa_s->current_bss = NULL;
-       wpa_sm_set_config(wpa_s->wpa, NULL);
-       eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
-       if (old_ssid != wpa_s->current_ssid)
-               wpas_notify_network_changed(wpa_s);
-       eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+
+       wpa_supplicant_clear_connection(wpa_s, addr);
 }
 
 
@@ -1341,7 +1410,6 @@ void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
 void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
                                   int reason_code)
 {
-       struct wpa_ssid *old_ssid;
        u8 *addr = NULL;
 
        if (!is_zero_ether_addr(wpa_s->bssid)) {
@@ -1352,16 +1420,8 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
                                               reason_code);
                addr = wpa_s->bssid;
        }
-       wpa_clear_keys(wpa_s, addr);
-       wpa_supplicant_mark_disassoc(wpa_s);
-       old_ssid = wpa_s->current_ssid;
-       wpa_s->current_ssid = NULL;
-       wpa_s->current_bss = NULL;
-       wpa_sm_set_config(wpa_s->wpa, NULL);
-       eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
-       if (old_ssid != wpa_s->current_ssid)
-               wpas_notify_network_changed(wpa_s);
-       eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+
+       wpa_supplicant_clear_connection(wpa_s, addr);
 }
 
 
@@ -1379,8 +1439,11 @@ void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
        int was_disabled;
 
        if (ssid == NULL) {
-               other_ssid = wpa_s->conf->ssid;
-               while (other_ssid) {
+               for (other_ssid = wpa_s->conf->ssid; other_ssid;
+                    other_ssid = other_ssid->next) {
+                       if (other_ssid->disabled == 2)
+                               continue; /* do not change persistent P2P group
+                                          * data */
                        if (other_ssid == wpa_s->current_ssid &&
                            other_ssid->disabled)
                                wpa_s->reassociate = 1;
@@ -1392,12 +1455,10 @@ void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
                        if (was_disabled != other_ssid->disabled)
                                wpas_notify_network_enabled_changed(
                                        wpa_s, other_ssid);
-
-                       other_ssid = other_ssid->next;
                }
                if (wpa_s->reassociate)
                        wpa_supplicant_req_scan(wpa_s, 0, 0);
-       } else if (ssid->disabled) {
+       } else if (ssid->disabled && ssid->disabled != 2) {
                if (wpa_s->current_ssid == NULL) {
                        /*
                         * Try to reassociate since there is no current
@@ -1431,22 +1492,23 @@ void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
        int was_disabled;
 
        if (ssid == NULL) {
-               other_ssid = wpa_s->conf->ssid;
-               while (other_ssid) {
+               for (other_ssid = wpa_s->conf->ssid; other_ssid;
+                    other_ssid = other_ssid->next) {
                        was_disabled = other_ssid->disabled;
+                       if (was_disabled == 2)
+                               continue; /* do not change persistent P2P group
+                                          * data */
 
                        other_ssid->disabled = 1;
 
                        if (was_disabled != other_ssid->disabled)
                                wpas_notify_network_enabled_changed(
                                        wpa_s, other_ssid);
-
-                       other_ssid = other_ssid->next;
                }
                if (wpa_s->current_ssid)
                        wpa_supplicant_disassociate(
                                wpa_s, WLAN_REASON_DEAUTH_LEAVING);
-       } else {
+       } else if (ssid->disabled != 2) {
                if (ssid == wpa_s->current_ssid)
                        wpa_supplicant_disassociate(
                                wpa_s, WLAN_REASON_DEAUTH_LEAVING);
@@ -1480,16 +1542,16 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
         * Mark all other networks disabled or mark all networks enabled if no
         * network specified.
         */
-       other_ssid = wpa_s->conf->ssid;
-       while (other_ssid) {
+       for (other_ssid = wpa_s->conf->ssid; other_ssid;
+            other_ssid = other_ssid->next) {
                int was_disabled = other_ssid->disabled;
+               if (was_disabled == 2)
+                       continue; /* do not change persistent P2P group data */
 
                other_ssid->disabled = ssid ? (ssid->id != other_ssid->id) : 0;
 
                if (was_disabled != other_ssid->disabled)
                        wpas_notify_network_enabled_changed(wpa_s, other_ssid);
-
-               other_ssid = other_ssid->next;
        }
        wpa_s->disconnected = 0;
        wpa_s->reassociate = 1;
@@ -1800,13 +1862,18 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
                const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
                if (addr)
                        os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
-       } else {
+       } else if (!(wpa_s->drv_flags &
+                    WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)) {
                wpa_s->l2 = l2_packet_init(wpa_s->ifname,
                                           wpa_drv_get_mac_addr(wpa_s),
                                           ETH_P_EAPOL,
                                           wpa_supplicant_rx_eapol, wpa_s, 0);
                if (wpa_s->l2 == NULL)
                        return -1;
+       } else {
+               const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
+               if (addr)
+                       os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
        }
 
        if (wpa_s->l2 && l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
@@ -1869,6 +1936,7 @@ static struct wpa_supplicant * wpa_supplicant_alloc(void)
                return NULL;
        wpa_s->scan_req = 1;
        wpa_s->new_connection = 1;
+       wpa_s->parent = wpa_s;
 
        return wpa_s;
 }
@@ -2033,6 +2101,7 @@ next_driver:
                }
                wpa_s->max_scan_ssids = capa.max_scan_ssids;
                wpa_s->max_remain_on_chan = capa.max_remain_on_chan;
+               wpa_s->max_stations = capa.max_stations;
        }
        if (wpa_s->max_remain_on_chan == 0)
                wpa_s->max_remain_on_chan = 1000;
@@ -2077,6 +2146,13 @@ next_driver:
        }
 #endif /* CONFIG_IBSS_RSN */
 
+#ifdef CONFIG_P2P
+       if (wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
+               wpa_printf(MSG_ERROR, "Failed to init P2P");
+               return -1;
+       }
+#endif /* CONFIG_P2P */
+
        if (wpa_bss_init(wpa_s) < 0)
                return -1;
 
@@ -2205,6 +2281,8 @@ int wpa_supplicant_remove_iface(struct wpa_global *global,
 
        wpa_printf(MSG_DEBUG, "Removing interface %s", wpa_s->ifname);
 
+       if (global->p2p_group_formation == wpa_s)
+               global->p2p_group_formation = NULL;
        wpa_supplicant_deinit_iface(wpa_s, 1);
        os_free(wpa_s);
 
@@ -2264,6 +2342,8 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
        global = os_zalloc(sizeof(*global));
        if (global == NULL)
                return NULL;
+       dl_list_init(&global->p2p_srv_bonjour);
+       dl_list_init(&global->p2p_srv_upnp);
        global->params.daemonize = params->daemonize;
        global->params.wait_for_monitor = params->wait_for_monitor;
        global->params.dbus_ctrl_interface = params->dbus_ctrl_interface;
@@ -2377,6 +2457,10 @@ void wpa_supplicant_deinit(struct wpa_global *global)
        if (global == NULL)
                return;
 
+#ifdef CONFIG_P2P
+       wpas_p2p_deinit_global(global);
+#endif /* CONFIG_P2P */
+
        while (global->ifaces)
                wpa_supplicant_remove_iface(global, global->ifaces);
 
@@ -2411,3 +2495,17 @@ void wpa_supplicant_deinit(struct wpa_global *global)
        wpa_debug_close_syslog();
        wpa_debug_close_file();
 }
+
+
+void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_WPS
+       wpas_wps_update_config(wpa_s);
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+       wpas_p2p_update_config(wpa_s);
+#endif /* CONFIG_P2P */
+
+       wpa_s->conf->changed_parameters = 0;
+}