Cumulative patch from commit 8b3b803ab9fe69650da7e3b2ee9e44f0f054ee0a
8b3b803 Include Extended Capabilities element based on scan results
6903ee6 P2P Extend postponing of concurrent scans for persistent GO
77e3094 hlr_auc_gw: Fix max_chal value validation
3e6547b hlr_auc_gw: Add support for processing command line operations
2b5b875 EAP-AKA server: Fix AUTS processing
9a50ee6 hlr_auc_gw: Update file comments to mention Milenage
5388dc9 Document use of Linux capabilities instead of privileged process
a771c07 Add driver status information to control interface
739faee nl80211: Add some more debug prints for mgmt frame TX
f78f278 nl80211: Fix off-channel Action frame TX from GO with use_monitor
298f518 Get rid of compiler warning in no-CONFIG_CTRL_IFACE builds
ea61aa1 Add no_ctrl_interface config param to clear ctrl_interface
25b65a1 Make sure updated BSS entry does not get added twice to the list
bbc6c72 P2P: Use group formation timeout on persistent group GO
41f8532 P2P: Extend group formation timeout on GO to first data connection
20625e9 P2P: Remove P2P groups on process termination
76fe79e Register wpa_msg callback even if only global ctrl_iface is used
af96448 nl80211: Add more debug prints for send_mlme operations
5d4c78f nl80211: Reset nlmode to station on leaving IBSS
0249c12 Avoid compiler warning with CONFIG_NO_STDOUT_DEBUG=y
ed1bf01 Allow hostapd config file for dynamically added interface
97bacf7 Do not clear hostapd configuration parameters on disable-iface
66f4dd1 hostapd: Fix couple of deinit path cases to clear pointers
f18b781 nl80211: Print more debug info on management frame RX information
89286e9 Re-open ctrl_iface socket on some failure cases as a workaround
3ca96df atheros: Compile fix for driver code not defining IEEE80211_APPIE_FRAME_WNM
762c92a OpenSSL: Split OCSP peer_cert/peer_issuer debug output into parts
f224cf0 HS 2.0: Allow printf format parsing with language:name strings
913c19c Fix wpa_config_parse_string() to null terminate printf decoded values
04e533e Fix language string length validation in parse_lang_string()
742e715 Simplify ctrl_iface sendto() use
6668efd Clear frequency list on empty value
1a9f247 Make scan_freq field to be saved by save_config
aa78cd3 Drop EAP packet with code 10 before EAPOL state machine processing
3cc247a Use configured sched_scan interval for the PNO scan
d047ae6 WPS: Ignore PBC-to-PIN change from M1 to M2 as a workaround
79986bf Print ctrl_iface sendto() failures into debug log
eab2b50 P2P: Cancel group formation timeout on client connection
00eb299 P2P: Fix operation channel configuration update
Change-Id: I9269e23bc8019b951c2a2d3c707562b2e006148b
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/wpa_supplicant/README b/wpa_supplicant/README
index 78df89e..8e9cc45 100644
--- a/wpa_supplicant/README
+++ b/wpa_supplicant/README
@@ -949,3 +949,37 @@
wpa_priv can control multiple interface with one process, but it is
also possible to run multiple wpa_priv processes at the same time, if
desired.
+
+
+Linux capabilities instead of privileged process
+------------------------------------------------
+
+wpa_supplicant performs operations that need special permissions, e.g.,
+to control the network connection. Traditionally this has been achieved
+by running wpa_supplicant as a privileged process with effective user id
+0 (root). Linux capabilities can be used to provide restricted set of
+capabilities to match the functions needed by wpa_supplicant. The
+minimum set of capabilities needed for the operations is CAP_NET_ADMIN
+and CAP_NET_RAW.
+
+setcap(8) can be used to set file capabilities. For example:
+
+sudo setcap cap_net_raw,cap_net_admin+ep wpa_supplicant
+
+Please note that this would give anyone being able to run that
+wpa_supplicant binary access to the additional capabilities. This can
+further be limited by file owner/group and mode bits. For example:
+
+sudo chown wpas wpa_supplicant
+sudo chmod 0100 wpa_supplicant
+
+This combination of setcap, chown, and chmod commands would allow wpas
+user to execute wpa_supplicant with additional network admin/raw
+capabilities.
+
+Common way style of creating a control interface socket in
+/var/run/wpa_supplicant could not be done by this user, but this
+directory could be created before starting the wpa_supplicant and set to
+suitable mode to allow wpa_supplicant to create sockets
+there. Alternatively, other directory or abstract socket namespace could
+be used for the control interface.
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 67a9f97..7d9bac5 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -625,8 +625,18 @@
bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
if (bss == NULL)
bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time);
- else
+ else {
bss = wpa_bss_update(wpa_s, bss, res, fetch_time);
+ if (wpa_s->last_scan_res) {
+ unsigned int i;
+ for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+ if (bss == wpa_s->last_scan_res[i]) {
+ /* Already in the list */
+ return;
+ }
+ }
+ }
+ }
if (bss == NULL)
return;
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index d666c91..f8ebc0d 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -873,6 +873,10 @@
freqs = wpa_config_parse_int_array(value);
if (freqs == NULL)
return -1;
+ if (freqs[0] == 0) {
+ os_free(freqs);
+ freqs = NULL;
+ }
os_free(ssid->scan_freq);
ssid->scan_freq = freqs;
@@ -889,6 +893,10 @@
freqs = wpa_config_parse_int_array(value);
if (freqs == NULL)
return -1;
+ if (freqs[0] == 0) {
+ os_free(freqs);
+ freqs = NULL;
+ }
os_free(ssid->freq_list);
ssid->freq_list = freqs;
@@ -2808,6 +2816,10 @@
freqs = wpa_config_parse_int_array(value);
if (freqs == NULL)
return -1;
+ if (freqs[0] == 0) {
+ os_free(freqs);
+ freqs = NULL;
+ }
os_free(config->freq_list);
config->freq_list = freqs;
return 0;
@@ -3070,6 +3082,19 @@
}
+#ifdef CONFIG_CTRL_IFACE
+static int wpa_config_process_no_ctrl_interface(
+ const struct global_parse_data *data,
+ struct wpa_config *config, int line, const char *pos)
+{
+ wpa_printf(MSG_DEBUG, "no_ctrl_interface -> ctrl_interface=NULL");
+ os_free(config->ctrl_interface);
+ config->ctrl_interface = NULL;
+ return 0;
+}
+#endif /* CONFIG_CTRL_IFACE */
+
+
#ifdef OFFSET
#undef OFFSET
#endif /* OFFSET */
@@ -3089,6 +3114,7 @@
static const struct global_parse_data global_fields[] = {
#ifdef CONFIG_CTRL_IFACE
{ STR(ctrl_interface), 0 },
+ { FUNC_NO_VAR(no_ctrl_interface), 0 },
{ STR(ctrl_interface_group), 0 } /* deprecated */,
#endif /* CONFIG_CTRL_IFACE */
{ INT_RANGE(eapol_version, 1, 2), 0 },
@@ -3125,8 +3151,8 @@
{ FUNC(sec_device_type), CFG_CHANGED_SEC_DEVICE_TYPE },
{ INT(p2p_listen_reg_class), 0 },
{ INT(p2p_listen_channel), 0 },
- { INT(p2p_oper_reg_class), 0 },
- { INT(p2p_oper_channel), 0 },
+ { INT(p2p_oper_reg_class), CFG_CHANGED_P2P_OPER_CHANNEL },
+ { INT(p2p_oper_channel), CFG_CHANGED_P2P_OPER_CHANNEL },
{ INT_RANGE(p2p_go_intent, 0, 15), 0 },
{ STR(p2p_ssid_postfix), CFG_CHANGED_P2P_SSID_POSTFIX },
{ INT_RANGE(persistent_reconnect, 0, 1), 0 },
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index a2791eb..0d2bd8c 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -653,6 +653,7 @@
write_auth_alg(f, ssid);
STR(bgscan);
STR(autoscan);
+ STR(scan_freq);
#ifdef IEEE8021X_EAPOL
write_eap(f, ssid);
STR(identity);
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index af57afa..fc78e83 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -50,7 +50,7 @@
static int pno_start(struct wpa_supplicant *wpa_s)
{
- int ret;
+ int ret, interval;
size_t i, num_ssid;
struct wpa_ssid *ssid;
struct wpa_driver_scan_params params;
@@ -108,7 +108,10 @@
if (wpa_s->conf->filter_rssi)
params.filter_rssi = wpa_s->conf->filter_rssi;
- ret = wpa_drv_sched_scan(wpa_s, ¶ms, 10 * 1000);
+ interval = wpa_s->conf->sched_scan_interval ?
+ wpa_s->conf->sched_scan_interval : 10;
+
+ ret = wpa_drv_sched_scan(wpa_s, ¶ms, interval * 1000);
os_free(params.filter_ssids);
if (ret == 0)
wpa_s->pno = 1;
@@ -1411,6 +1414,8 @@
char *pos, *end, tmp[30];
int res, verbose, wps, ret;
+ if (os_strcmp(params, "-DRIVER") == 0)
+ return wpa_drv_status(wpa_s, buf, buflen);
verbose = os_strcmp(params, "-VERBOSE") == 0;
wps = os_strcmp(params, "-WPS") == 0;
pos = buf;
@@ -4222,7 +4227,8 @@
return -1;
}
- return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40, NULL);
+ return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40, NULL,
+ 0);
}
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index e35d2c3..5fe9a4e 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -57,10 +57,17 @@
};
-static void wpa_supplicant_ctrl_iface_send(const char *ifname, int sock,
+static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
+ const char *ifname, int sock,
struct dl_list *ctrl_dst,
int level, const char *buf,
- size_t len);
+ size_t len,
+ struct ctrl_iface_priv *priv,
+ struct ctrl_iface_global_priv *gp);
+static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s,
+ struct ctrl_iface_priv *priv);
+static int wpas_ctrl_iface_global_reinit(struct wpa_global *global,
+ struct ctrl_iface_global_priv *priv);
static int wpa_supplicant_ctrl_iface_attach(struct dl_list *ctrl_dst,
@@ -143,7 +150,7 @@
int res;
struct sockaddr_un from;
socklen_t fromlen = sizeof(from);
- char *reply = NULL;
+ char *reply = NULL, *reply_buf = NULL;
size_t reply_len = 0;
int new_attached = 0;
@@ -177,21 +184,49 @@
else
reply_len = 2;
} else {
- reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
- &reply_len);
+ reply_buf = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
+ &reply_len);
+ reply = reply_buf;
+ }
+
+ if (!reply && reply_len == 1) {
+ reply = "FAIL\n";
+ reply_len = 5;
+ } else if (!reply && reply_len == 2) {
+ reply = "OK\n";
+ reply_len = 3;
}
if (reply) {
- sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
- fromlen);
- os_free(reply);
- } else if (reply_len == 1) {
- sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
- fromlen);
- } else if (reply_len == 2) {
- sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
- fromlen);
+ if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+ fromlen) < 0) {
+ int _errno = errno;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "ctrl_iface sendto failed: %d - %s",
+ _errno, strerror(_errno));
+ if (_errno == ENOBUFS || _errno == EAGAIN) {
+ /*
+ * The socket send buffer could be full. This
+ * may happen if client programs are not
+ * receiving their pending messages. Close and
+ * reopen the socket as a workaround to avoid
+ * getting stuck being unable to send any new
+ * responses.
+ */
+ sock = wpas_ctrl_iface_reinit(wpa_s, priv);
+ if (sock < 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Failed to reinitialize ctrl_iface socket");
+ }
+ }
+ if (new_attached) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Failed to send response to ATTACH - detaching");
+ new_attached = 0;
+ wpa_supplicant_ctrl_iface_detach(
+ &priv->ctrl_dst, &from, fromlen);
+ }
+ }
}
+ os_free(reply_buf);
if (new_attached)
eapol_sm_notify_ctrl_attached(wpa_s->eapol);
@@ -262,26 +297,27 @@
if (global != 2 && wpa_s->global->ctrl_iface) {
struct ctrl_iface_global_priv *priv = wpa_s->global->ctrl_iface;
if (!dl_list_empty(&priv->ctrl_dst)) {
- wpa_supplicant_ctrl_iface_send(global ? NULL :
+ wpa_supplicant_ctrl_iface_send(wpa_s, global ? NULL :
wpa_s->ifname,
priv->sock,
&priv->ctrl_dst,
- level, txt, len);
+ level, txt, len, NULL,
+ priv);
}
}
if (wpa_s->ctrl_iface == NULL)
return;
- wpa_supplicant_ctrl_iface_send(NULL, wpa_s->ctrl_iface->sock,
+ wpa_supplicant_ctrl_iface_send(wpa_s, NULL, wpa_s->ctrl_iface->sock,
&wpa_s->ctrl_iface->ctrl_dst,
- level, txt, len);
+ level, txt, len, wpa_s->ctrl_iface,
+ NULL);
}
-struct ctrl_iface_priv *
-wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
+static int wpas_ctrl_iface_open_sock(struct wpa_supplicant *wpa_s,
+ struct ctrl_iface_priv *priv)
{
- struct ctrl_iface_priv *priv;
struct sockaddr_un addr;
char *fname = NULL;
gid_t gid = 0;
@@ -291,16 +327,6 @@
char *endp;
int flags;
- priv = os_zalloc(sizeof(*priv));
- if (priv == NULL)
- return NULL;
- dl_list_init(&priv->ctrl_dst);
- priv->wpa_s = wpa_s;
- priv->sock = -1;
-
- if (wpa_s->conf->ctrl_interface == NULL)
- return priv;
-
buf = os_strdup(wpa_s->conf->ctrl_interface);
if (buf == NULL)
goto fail;
@@ -476,18 +502,61 @@
wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
os_free(buf);
- return priv;
+ return 0;
fail:
- if (priv->sock >= 0)
+ if (priv->sock >= 0) {
close(priv->sock);
- os_free(priv);
+ priv->sock = -1;
+ }
if (fname) {
unlink(fname);
os_free(fname);
}
os_free(buf);
- return NULL;
+ return -1;
+}
+
+
+struct ctrl_iface_priv *
+wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
+{
+ struct ctrl_iface_priv *priv;
+
+ priv = os_zalloc(sizeof(*priv));
+ if (priv == NULL)
+ return NULL;
+ dl_list_init(&priv->ctrl_dst);
+ priv->wpa_s = wpa_s;
+ priv->sock = -1;
+
+ if (wpa_s->conf->ctrl_interface == NULL)
+ return priv;
+
+ if (wpas_ctrl_iface_open_sock(wpa_s, priv) < 0) {
+ os_free(priv);
+ return NULL;
+ }
+
+ return priv;
+}
+
+
+static int wpas_ctrl_iface_reinit(struct wpa_supplicant *wpa_s,
+ struct ctrl_iface_priv *priv)
+{
+ int res;
+
+ if (priv->sock <= 0)
+ return -1;
+
+ eloop_unregister_read_sock(priv->sock);
+ close(priv->sock);
+ priv->sock = -1;
+ res = wpas_ctrl_iface_open_sock(wpa_s, priv);
+ if (res < 0)
+ return -1;
+ return priv->sock;
}
@@ -517,6 +586,8 @@
os_free(fname);
}
+ if (priv->wpa_s->conf->ctrl_interface == NULL)
+ goto free_dst;
buf = os_strdup(priv->wpa_s->conf->ctrl_interface);
if (buf == NULL)
goto free_dst;
@@ -563,10 +634,13 @@
*
* Send a packet to all monitor programs attached to the control interface.
*/
-static void wpa_supplicant_ctrl_iface_send(const char *ifname, int sock,
+static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
+ const char *ifname, int sock,
struct dl_list *ctrl_dst,
int level, const char *buf,
- size_t len)
+ size_t len,
+ struct ctrl_iface_priv *priv,
+ struct ctrl_iface_global_priv *gp)
{
struct wpa_ctrl_dst *dst, *next;
char levelstr[10];
@@ -602,31 +676,56 @@
msg.msg_iov = io;
msg.msg_iovlen = idx;
- idx = 0;
+ idx = -1;
dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) {
- if (level >= dst->debug_level) {
- wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
- (u8 *) dst->addr.sun_path, dst->addrlen -
- offsetof(struct sockaddr_un, sun_path));
- msg.msg_name = (void *) &dst->addr;
- msg.msg_namelen = dst->addrlen;
- if (sendmsg(sock, &msg, MSG_DONTWAIT) < 0) {
- int _errno = errno;
- wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
- "%d - %s",
- idx, errno, strerror(errno));
- dst->errors++;
- if (dst->errors > 1000 ||
- (_errno != ENOBUFS && dst->errors > 10) ||
- _errno == ENOENT) {
- wpa_supplicant_ctrl_iface_detach(
- ctrl_dst, &dst->addr,
- dst->addrlen);
- }
- } else
- dst->errors = 0;
- }
+ int _errno;
+
idx++;
+ if (level < dst->debug_level)
+ continue;
+
+ wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
+ (u8 *) dst->addr.sun_path, dst->addrlen -
+ offsetof(struct sockaddr_un, sun_path));
+ msg.msg_name = (void *) &dst->addr;
+ msg.msg_namelen = dst->addrlen;
+ if (sendmsg(sock, &msg, MSG_DONTWAIT) >= 0) {
+ dst->errors = 0;
+ idx++;
+ continue;
+ }
+
+ _errno = errno;
+ wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: %d - %s",
+ idx, errno, strerror(errno));
+ dst->errors++;
+
+ if (dst->errors > 10 || _errno == ENOENT || _errno == EPERM) {
+ wpa_printf(MSG_INFO, "CTRL_IFACE: Detach monitor that cannot receive messages");
+ wpa_supplicant_ctrl_iface_detach(ctrl_dst, &dst->addr,
+ dst->addrlen);
+ }
+
+ if (_errno == ENOBUFS || _errno == EAGAIN) {
+ /*
+ * The socket send buffer could be full. This may happen
+ * if client programs are not receiving their pending
+ * messages. Close and reopen the socket as a workaround
+ * to avoid getting stuck being unable to send any new
+ * responses.
+ */
+ if (priv)
+ sock = wpas_ctrl_iface_reinit(wpa_s, priv);
+ else if (gp)
+ sock = wpas_ctrl_iface_global_reinit(
+ wpa_s->global, gp);
+ else
+ break;
+ if (sock < 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "Failed to reinitialize ctrl_iface socket");
+ }
+ }
}
}
@@ -656,18 +755,30 @@
/* handle ATTACH signal of first monitor interface */
if (!wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
&from, fromlen)) {
- sendto(priv->sock, "OK\n", 3, 0,
- (struct sockaddr *) &from, fromlen);
+ if (sendto(priv->sock, "OK\n", 3, 0,
+ (struct sockaddr *) &from, fromlen) <
+ 0) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s",
+ strerror(errno));
+ }
/* OK to continue */
return;
} else {
- sendto(priv->sock, "FAIL\n", 5, 0,
- (struct sockaddr *) &from, fromlen);
+ if (sendto(priv->sock, "FAIL\n", 5, 0,
+ (struct sockaddr *) &from, fromlen) <
+ 0) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s",
+ strerror(errno));
+ }
}
} else {
/* return FAIL for all other signals */
- sendto(priv->sock, "FAIL\n", 5, 0,
- (struct sockaddr *) &from, fromlen);
+ if (sendto(priv->sock, "FAIL\n", 5, 0,
+ (struct sockaddr *) &from, fromlen) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "ctrl_iface sendto failed: %s",
+ strerror(errno));
+ }
}
}
}
@@ -684,7 +795,7 @@
int res;
struct sockaddr_un from;
socklen_t fromlen = sizeof(from);
- char *reply = NULL;
+ char *reply = NULL, *reply_buf = NULL;
size_t reply_len;
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
@@ -709,41 +820,37 @@
else
reply_len = 2;
} else {
- reply = wpa_supplicant_global_ctrl_iface_process(global, buf,
- &reply_len);
+ reply_buf = wpa_supplicant_global_ctrl_iface_process(
+ global, buf, &reply_len);
+ reply = reply_buf;
+ }
+
+ if (!reply && reply_len == 1) {
+ reply = "FAIL\n";
+ reply_len = 5;
+ } else if (!reply && reply_len == 2) {
+ reply = "OK\n";
+ reply_len = 3;
}
if (reply) {
- sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
- fromlen);
- os_free(reply);
- } else if (reply_len == 1) {
- sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
- fromlen);
- } else if (reply_len == 2) {
- sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from, fromlen);
+ if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+ fromlen) < 0) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface sendto failed: %s",
+ strerror(errno));
+ }
}
+ os_free(reply_buf);
}
-struct ctrl_iface_global_priv *
-wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
+static int wpas_global_ctrl_iface_open_sock(struct wpa_global *global,
+ struct ctrl_iface_global_priv *priv)
{
- struct ctrl_iface_global_priv *priv;
struct sockaddr_un addr;
const char *ctrl = global->params.ctrl_interface;
int flags;
- priv = os_zalloc(sizeof(*priv));
- if (priv == NULL)
- return NULL;
- dl_list_init(&priv->ctrl_dst);
- priv->global = global;
- priv->sock = -1;
-
- if (ctrl == NULL)
- return priv;
-
wpa_printf(MSG_DEBUG, "Global control interface '%s'", ctrl);
#ifdef ANDROID
@@ -899,13 +1006,58 @@
wpa_supplicant_global_ctrl_iface_receive,
global, priv);
- return priv;
+ return 0;
fail:
- if (priv->sock >= 0)
+ if (priv->sock >= 0) {
close(priv->sock);
- os_free(priv);
- return NULL;
+ priv->sock = -1;
+ }
+ return -1;
+}
+
+
+struct ctrl_iface_global_priv *
+wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
+{
+ struct ctrl_iface_global_priv *priv;
+
+ priv = os_zalloc(sizeof(*priv));
+ if (priv == NULL)
+ return NULL;
+ dl_list_init(&priv->ctrl_dst);
+ priv->global = global;
+ priv->sock = -1;
+
+ if (global->params.ctrl_interface == NULL)
+ return priv;
+
+ if (wpas_global_ctrl_iface_open_sock(global, priv) < 0) {
+ os_free(priv);
+ return NULL;
+ }
+
+ wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
+
+ return priv;
+}
+
+
+static int wpas_ctrl_iface_global_reinit(struct wpa_global *global,
+ struct ctrl_iface_global_priv *priv)
+{
+ int res;
+
+ if (priv->sock <= 0)
+ return -1;
+
+ eloop_unregister_read_sock(priv->sock);
+ close(priv->sock);
+ priv->sock = -1;
+ res = wpas_global_ctrl_iface_open_sock(global, priv);
+ if (res < 0)
+ return -1;
+ return priv->sock;
}
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 6ec96df..52b36b4 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -347,7 +347,7 @@
goto inv_args;
if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0,
- NULL)) {
+ NULL, 0)) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 5e7dbf7..6a96331 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -710,4 +710,12 @@
buf_len);
}
+static inline int wpa_drv_status(struct wpa_supplicant *wpa_s,
+ char *buf, size_t buflen)
+{
+ if (!wpa_s->driver->status)
+ return -1;
+ return wpa_s->driver->status(wpa_s->drv_priv, buf, buflen);
+}
+
#endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index d7b3189..a0a7157 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -73,6 +73,15 @@
#define P2P_MAX_INITIAL_CONN_WAIT_GO 10
#endif /* P2P_MAX_INITIAL_CONN_WAIT_GO */
+#ifndef P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE
+/*
+ * How many seconds to wait for initial 4-way handshake to get completed after
+ * re-invocation of a persistent group on the GO when the client is expected
+ * to connect automatically (no user interaction).
+ */
+#define P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE 15
+#endif /* P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE */
+
#ifndef P2P_CONCURRENT_SEARCH_DELAY
#define P2P_CONCURRENT_SEARCH_DELAY 500
#endif /* P2P_CONCURRENT_SEARCH_DELAY */
@@ -728,8 +737,10 @@
*/
if (wpa_s->global->p2p_group_formation)
wpa_s = wpa_s->global->p2p_group_formation;
- wpa_s->global->p2p_group_formation = NULL;
- wpa_s->p2p_in_provisioning = 0;
+ if (wpa_s->p2p_go_group_formation_completed) {
+ wpa_s->global->p2p_group_formation = NULL;
+ wpa_s->p2p_in_provisioning = 0;
+ }
if (!success) {
wpa_msg_global(wpa_s->parent, MSG_INFO,
@@ -996,6 +1007,7 @@
" [PERSISTENT]" : "");
}
+ os_get_time(&wpa_s->global->p2p_go_wait_client);
if (params->persistent_group) {
network_id = wpas_p2p_store_persistent_group(
wpa_s->parent, ssid,
@@ -1007,6 +1019,21 @@
wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
wpas_p2p_cross_connect_setup(wpa_s);
wpas_p2p_set_group_idle_timeout(wpa_s);
+
+ if (wpa_s->p2p_first_connection_timeout) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Start group formation timeout of %d seconds until first data connection on GO",
+ wpa_s->p2p_first_connection_timeout);
+ wpa_s->p2p_go_group_formation_completed = 0;
+ wpa_s->global->p2p_group_formation = wpa_s;
+ eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
+ eloop_register_timeout(
+ wpa_s->p2p_first_connection_timeout, 0,
+ wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
+ }
+
return;
}
@@ -2706,7 +2733,8 @@
if (s) {
int go = s->mode == WPAS_MODE_P2P_GO;
wpas_p2p_group_add_persistent(
- wpa_s, s, go, go ? op_freq : 0, 0, NULL);
+ wpa_s, s, go, go ? op_freq : 0, 0, NULL,
+ go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0);
} else if (bssid) {
wpa_s->user_initiated_pd = 0;
wpas_p2p_join(wpa_s, bssid, go_dev_addr,
@@ -2881,7 +2909,10 @@
wpas_p2p_group_add_persistent(wpa_s, ssid,
ssid->mode == WPAS_MODE_P2P_GO,
wpa_s->p2p_persistent_go_freq,
- wpa_s->p2p_go_ht40, channels);
+ wpa_s->p2p_go_ht40, channels,
+ ssid->mode == WPAS_MODE_P2P_GO ?
+ P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
+ 0);
}
@@ -4516,6 +4547,7 @@
if (!wpas_p2p_create_iface(wpa_s)) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use same interface for group "
"operations");
+ wpa_s->p2p_first_connection_timeout = 0;
return wpa_s;
}
@@ -4535,6 +4567,7 @@
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use separate group interface %s",
group_wpa_s->ifname);
+ group_wpa_s->p2p_first_connection_timeout = 0;
return group_wpa_s;
}
@@ -4637,7 +4670,8 @@
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
int freq, int ht40,
- const struct p2p_channels *channels)
+ const struct p2p_channels *channels,
+ int connection_timeout)
{
struct p2p_go_neg_results params;
int go = 0;
@@ -4694,6 +4728,7 @@
if (wpa_s == NULL)
return -1;
+ wpa_s->p2p_first_connection_timeout = connection_timeout;
wpas_start_wps_go(wpa_s, ¶ms, 0);
return 0;
@@ -4801,6 +4836,7 @@
eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent,
NULL);
+ wpa_s->p2p_go_group_formation_completed = 1;
if (ssid && ssid->mode == WPAS_MODE_INFRA) {
/*
* Use a separate timeout for initial data connection to
@@ -4808,9 +4844,28 @@
* something goes wrong in this step before the P2P group idle
* timeout mechanism is taken into use.
*/
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Re-start group formation timeout (%d seconds) as client for initial connection",
+ P2P_MAX_INITIAL_CONN_WAIT);
eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT, 0,
wpas_p2p_group_formation_timeout,
wpa_s->parent, NULL);
+ } else if (ssid) {
+ /*
+ * Use a separate timeout for initial data connection to
+ * complete to allow the group to be removed automatically if
+ * the client does not complete data connection successfully.
+ */
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2P: Re-start group formation timeout (%d seconds) as GO for initial connection",
+ P2P_MAX_INITIAL_CONN_WAIT_GO);
+ eloop_register_timeout(P2P_MAX_INITIAL_CONN_WAIT_GO, 0,
+ wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL);
+ /*
+ * Complete group formation on first successful data connection
+ */
+ wpa_s->p2p_go_group_formation_completed = 0;
}
if (wpa_s->global->p2p)
p2p_wps_success_cb(wpa_s->global->p2p, peer_addr);
@@ -6007,6 +6062,25 @@
void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
const u8 *addr)
{
+ if (eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+ wpa_s->parent, NULL) > 0) {
+ /*
+ * This can happen if WPS provisioning step is not terminated
+ * cleanly (e.g., P2P Client does not send WSC_Done). Since the
+ * peer was able to connect, there is no need to time out group
+ * formation after this, though. In addition, this is used with
+ * the initial connection wait on the GO as a separate formation
+ * timeout and as such, expected to be hit after the initial WPS
+ * provisioning step.
+ */
+ wpa_printf(MSG_DEBUG, "P2P: Canceled P2P group formation timeout on data connection");
+ }
+ if (!wpa_s->p2p_go_group_formation_completed) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Marking group formation completed on GO on first data connection");
+ wpa_s->p2p_go_group_formation_completed = 1;
+ wpa_s->global->p2p_group_formation = NULL;
+ wpa_s->p2p_in_provisioning = 0;
+ }
wpa_s->global->p2p_go_wait_client.sec = 0;
if (addr == NULL)
return;
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 65ccbf9..64c5857 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -39,7 +39,8 @@
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
int freq, int ht40,
- const struct p2p_channels *channels);
+ const struct p2p_channels *channels,
+ int connection_timeout);
struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index a379d65..6727526 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -496,6 +496,8 @@
return wpa_ctrl_command(ctrl, "STATUS-VERBOSE");
if (argc > 0 && os_strcmp(argv[0], "wps") == 0)
return wpa_ctrl_command(ctrl, "STATUS-WPS");
+ if (argc > 0 && os_strcmp(argv[0], "driver") == 0)
+ return wpa_ctrl_command(ctrl, "STATUS-DRIVER");
return wpa_ctrl_command(ctrl, "STATUS");
}
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 9ae898b..f924316 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -722,6 +722,11 @@
#ifdef CONFIG_WPS
struct wpa_supplicant *wpa_s = global->ifaces;
while (wpa_s) {
+#ifdef CONFIG_P2P
+ if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE ||
+ (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group))
+ wpas_p2p_disconnect(wpa_s);
+#endif /* CONFIG_P2P */
if (wpas_wps_terminate_pending(wpa_s) == 1)
pending = 1;
wpa_s = wpa_s->next;
@@ -1279,8 +1284,6 @@
int wep_keys_set = 0;
int assoc_failed = 0;
struct wpa_ssid *old_ssid;
- u8 ext_capab[10];
- int ext_capab_len;
#ifdef CONFIG_HT_OVERRIDES
struct ieee80211_ht_capabilities htcaps;
struct ieee80211_ht_capabilities htcaps_mask;
@@ -1495,15 +1498,27 @@
}
#endif /* CONFIG_HS20 */
- ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab);
- if (ext_capab_len > 0) {
- u8 *pos = wpa_ie;
- if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
- pos += 2 + pos[1];
- os_memmove(pos + ext_capab_len, pos,
- wpa_ie_len - (pos - wpa_ie));
- wpa_ie_len += ext_capab_len;
- os_memcpy(pos, ext_capab, ext_capab_len);
+ /*
+ * Workaround: Add Extended Capabilities element only if the AP
+ * included this element in Beacon/Probe Response frames. Some older
+ * APs seem to have interoperability issues if this element is
+ * included, so while the standard may require us to include the
+ * element in all cases, it is justifiable to skip it to avoid
+ * interoperability issues.
+ */
+ if (!bss || wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB)) {
+ u8 ext_capab[10];
+ int ext_capab_len;
+ ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab);
+ if (ext_capab_len > 0) {
+ u8 *pos = wpa_ie;
+ if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
+ pos += 2 + pos[1];
+ os_memmove(pos + ext_capab_len, pos,
+ wpa_ie_len - (pos - wpa_ie));
+ wpa_ie_len += ext_capab_len;
+ os_memcpy(pos, ext_capab, ext_capab_len);
+ }
}
wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index d69cd61..be493cf 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -647,6 +647,8 @@
unsigned int p2p_pd_before_go_neg:1;
unsigned int p2p_go_ht40:1;
unsigned int user_initiated_pd:1;
+ unsigned int p2p_go_group_formation_completed:1;
+ int p2p_first_connection_timeout;
int p2p_persistent_go_freq;
int p2p_persistent_id;
int p2p_go_intent;