/*
* WPA Supplicant
- * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-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 "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"
const char *wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi> and contributors";
const char *wpa_supplicant_license =
"This program is free software. You can distribute it and/or modify it\n"
#ifdef CONFIG_AP
wpa_supplicant_ap_deinit(wpa_s);
#endif /* CONFIG_AP */
+
+#ifdef CONFIG_P2P
+ wpas_p2p_deinit(wpa_s);
+#endif /* CONFIG_P2P */
}
return "DISCONNECTED";
case WPA_INACTIVE:
return "INACTIVE";
+ case WPA_INTERFACE_DISABLED:
+ return "INTERFACE_DISABLED";
case WPA_SCANNING:
return "SCANNING";
case WPA_AUTHENTICATING:
void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
enum wpa_states state)
{
+ enum wpa_states old_state = wpa_s->wpa_state;
+
wpa_printf(MSG_DEBUG, "State: %s -> %s",
wpa_supplicant_state_txt(wpa_s->wpa_state),
wpa_supplicant_state_txt(state));
if (state != WPA_SCANNING)
wpa_supplicant_notify_scanning(wpa_s, 0);
- wpas_notify_state_changed(wpa_s, state, wpa_s->wpa_state);
-
if (state == WPA_COMPLETED && wpa_s->new_connection) {
#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
struct wpa_ssid *ssid = wpa_s->current_ssid;
wpa_s->new_connection = 0;
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;
wpa_drv_set_operstate(wpa_s, 0);
}
wpa_s->wpa_state = state;
+
+ if (wpa_s->wpa_state != old_state)
+ wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
}
}
-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;
+
wpa_s->pairwise_cipher = 0;
wpa_s->group_cipher = 0;
wpa_s->mgmt_group_cipher = 0;
wpa_s->key_mgmt = 0;
- wpa_s->wpa_state = WPA_DISCONNECTED;
- wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
+ if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
+ wpa_s->wpa_state = WPA_DISCONNECTED;
+
+ if (wpa_s->wpa_state != old_state)
+ wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
}
"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 &&
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;
}
}
-static enum wpa_cipher cipher_suite2driver(int cipher)
+enum wpa_cipher cipher_suite2driver(int cipher)
{
switch (cipher) {
case WPA_CIPHER_NONE:
}
-static enum wpa_key_mgmt key_mgmt2driver(int key_mgmt)
+enum wpa_key_mgmt key_mgmt2driver(int key_mgmt)
{
switch (key_mgmt) {
case WPA_KEY_MGMT_NONE:
}
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
wpa_s->mgmt_group_cipher);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP, ssid->ieee80211w);
#endif /* CONFIG_IEEE80211W */
if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
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;
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 "
return;
}
+ os_memset(¶ms, 0, sizeof(params));
wpa_s->reassociate = 0;
if (bss) {
#ifdef CONFIG_IEEE80211R
ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
md = ie + 2;
- wpa_sm_set_ft_params(wpa_s->wpa, md, NULL, 0, NULL);
+ wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0);
if (md) {
/* Prepare for the next transition */
- wpa_ft_prepare_auth_request(wpa_s->wpa);
+ wpa_ft_prepare_auth_request(wpa_s->wpa, ie);
}
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_WPS
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);
}
wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
- os_memset(¶ms, 0, sizeof(params));
if (bss) {
params.bssid = bss->bssid;
params.ssid = bss->ssid;
}
#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, ¶ms);
else
}
+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
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)) {
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);
+
+ wpa_supplicant_clear_connection(wpa_s, addr);
}
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)) {
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);
+
+ wpa_supplicant_clear_connection(wpa_s, addr);
}
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;
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 (wpa_s->current_ssid == NULL && ssid->disabled) {
- /*
- * Try to reassociate since there is no current configuration
- * and a new network was made available.
- */
- wpa_s->reassociate = 1;
- wpa_supplicant_req_scan(wpa_s, 0, 0);
+ } else if (ssid->disabled && ssid->disabled != 2) {
+ if (wpa_s->current_ssid == NULL) {
+ /*
+ * Try to reassociate since there is no current
+ * configuration and a new network was made available.
+ */
+ wpa_s->reassociate = 1;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ }
was_disabled = ssid->disabled;
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);
* 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;
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)) {
wpa_drv_flush_pmkid(wpa_s);
wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
- wpa_supplicant_req_scan(wpa_s, interface_count, 100000);
- interface_count++;
+ if (wpa_supplicant_enabled_networks(wpa_s->conf)) {
+ wpa_supplicant_req_scan(wpa_s, interface_count, 100000);
+ interface_count++;
+ } else
+ wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
return 0;
}
return NULL;
wpa_s->scan_req = 1;
wpa_s->new_connection = 1;
+ wpa_s->parent = wpa_s;
return wpa_s;
}
return -1;
}
+ if (wpa_drv_get_capa(wpa_s, &capa) == 0) {
+ wpa_s->drv_flags = capa.flags;
+ if (capa.flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
+ if (ieee80211_sta_init(wpa_s))
+ return -1;
+ }
+ 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;
+
if (wpa_supplicant_driver_init(wpa_s) < 0)
return -1;
return -1;
}
- if (wpa_drv_get_capa(wpa_s, &capa) == 0) {
- wpa_s->drv_flags = capa.flags;
- if (capa.flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
- if (ieee80211_sta_init(wpa_s))
- return -1;
- }
- wpa_s->max_scan_ssids = capa.max_scan_ssids;
- }
-
#ifdef CONFIG_IBSS_RSN
wpa_s->ibss_rsn = ibss_rsn_init(wpa_s);
if (!wpa_s->ibss_rsn) {
}
#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;
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);
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;
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);
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;
+}