Cumulative patch from commit 2c0efd9e49b15da163cee659409eee85390620c3
2c0efd9 P2P: Fix stopping on search after SD callback
db3168d OpenSSL: Use SSL_cache_hit() when available
68ae477 OpenSSL: Use library wrapper functions to access cert store
abe96d0 P2P: Clean up Listen channel optimization debug prints
d2ca6ba Fix hostapd obss_interval documentation
d027c7b Fix 20/40 MHz co-ex report processing with obss_interval=0
93eca61 P2PS: Do not remove pending interface on p2p_stop_find
ae2dd83 P2PS: Allow PD retry in SEARCH and LISTEN_ONLY also
87d5ef5 P2PS: Add commands to control interface redir list
0cf12b3 P2PS: Send P2P_FIND_STOPPED event during P2P SD also
306aaf4 P2PS: Start WPS registrar upon GO formation
9e96e46 P2PS: PD Response processing
ab8ee77 P2PS: Provision Discovery fail event
1300cc8 P2PS: PD Request processing and PD Response building
5fefce2 P2PS: Callback to send P2PS provisioning events
9a58e52 P2PS: Callback to create pending group after sending PD Response
895d94d P2PS: Callback to remove stale persistent groups
f309c18 P2PS: ASP provisioning commands to control interface
6d90851 P2PS: Process P2PS provisioning commands
369678a P2PS: Add P2PS attributes into PD Request if requested
59fec34 P2PS: Allow p2p_build_ssid() to use pre-set SSID
d4b43b5 P2PS: Add support to send ASP-RESP events
6df08d0 P2PS: Logic to parse GAS requests for ASP services
5a4102c P2PS: Add support to send ASP service requests
095b3c4 P2PS: Add Application Service Info to device found events
4660e73 P2PS: Add Advertised Service Info into Probe Response frames
9e7321e P2PS: Parse Probe Request frames for matching ASP hashes
ae9d45f P2PS: Extend add/del services logic to support ASP
ea8e033 P2P: Allow p2p_get_group_num_members() to be called with NULL
4f88fc0 P2PS: WPS changes needed for P2PS default PIN
1a94b0a P2PS: Add service hash to Probe Request frames
5177509 P2PS: Add option to specify seek strings into P2P_FIND
5f18501 P2PS: Helper functions to build new P2P attributes
60d1148 P2PS: Add parsing of new P2P attributes
b9348be P2PS: Add new P2P identifier assignments from P2P spec v1.5
c3d6c71 Add helper functions for escaping and unescaping UTF-8
66eaf8a Fix driver-offloaded offchannel TX done processing
c5e154c P2P: Add P2P state into p2p_send_action_cb() debug entry
f2dc06e P2P: Ignore remain-on-channel callback event if not waiting for one
6a6569b HS 2.0R2: Add password to DB in case of machine managed subscription
f0d0a5d Improve BSS selection with default noise floor values
7f7bfba Add an option allow canned EAP-Success for wired IEEE 802.1X
49fcc32 EAP-MSCHAPv2 peer: Add option to disable password retry query
66bc683 hostapd: Simplify vlan_add_dynamic error paths
99805a0 Interworking: Convert wpa_printf() to wpa_msg()
b42f539 Add a variable to handle extra CFLAGS values
e6dd819 Work around Linux packet socket regression
7650f9e Fix resource leaks on rsn_preauth_init() error paths
a565e03 dhcp_snoop: Make IPv4 addresses human readable in debug log
2dd4f3a Fix STA re-bind to another VLAN on reauthentication
4437f8f Free old eap_user_file data on configuration change
1180dd6 WPA auth: Disconnect STA if MSK cannot be fetched
40aaa64 WPA auth: Clear temporary MSK storage from stack explicitly
01b481a Convert couple of remaining printf to wpa_printf in ap_list
bfaefd5 EAP-PEAP server: Fix Phase 2 TLV length in error case
745d936 mesh: Create new station entry on popen frames
41bff86 mesh: Always free the station if peering failed
871ff0b mesh: Sync plink state with kernel
ba42261 Simplify eapol_sm_notify_pmkid_attempt()
993a865 Add eap_session_id to wpa_supplicant STATUS output
f19c907 OpenSSL: Implement aes_wrap() and aes_unwrap()
fee31f7 OpenSSL: Remove support for versions older than 0.9.8
8bf3030 OpenSSL: Use a common helper function for HMAC
983c6a6 OpenSSL: Replace internal HMAC-MD5 implementation
Change-Id: I5743003f14efae324537f7dc2c5e6ada892a33a7
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index ed78bf9..2ec99ad 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -1126,7 +1126,9 @@
AESOBJS += src/crypto/aes-internal.c src/crypto/aes-internal-dec.c
endif
+ifneq ($(CONFIG_TLS), openssl)
AESOBJS += src/crypto/aes-unwrap.c
+endif
ifdef NEED_AES_EAX
AESOBJS += src/crypto/aes-eax.c
NEED_AES_CTR=y
@@ -1147,8 +1149,10 @@
endif
ifdef NEED_AES_WRAP
NEED_AES_ENC=y
+ifneq ($(CONFIG_TLS), openssl)
AESOBJS += src/crypto/aes-wrap.c
endif
+endif
ifdef NEED_AES_CBC
NEED_AES_ENC=y
AESOBJS += src/crypto/aes-cbc.c
@@ -1194,8 +1198,10 @@
MD5OBJS =
ifndef CONFIG_FIPS
+ifneq ($(CONFIG_TLS), openssl)
MD5OBJS += src/crypto/md5.c
endif
+endif
ifdef NEED_MD5
ifdef CONFIG_INTERNAL_MD5
MD5OBJS += src/crypto/md5-internal.c
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 21486c4..95fbe78 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -10,6 +10,7 @@
export BINDIR ?= /usr/local/sbin/
PKG_CONFIG ?= pkg-config
+CFLAGS += $(EXTRA_CFLAGS)
CFLAGS += -I$(abspath ../src)
CFLAGS += -I$(abspath ../src/utils)
@@ -1142,7 +1143,9 @@
AESOBJS += ../src/crypto/aes-internal.o ../src/crypto/aes-internal-dec.o
endif
+ifneq ($(CONFIG_TLS), openssl)
AESOBJS += ../src/crypto/aes-unwrap.o
+endif
ifdef NEED_AES_EAX
AESOBJS += ../src/crypto/aes-eax.o
NEED_AES_CTR=y
@@ -1166,8 +1169,10 @@
endif
ifdef NEED_AES_WRAP
NEED_AES_ENC=y
+ifneq ($(CONFIG_TLS), openssl)
AESOBJS += ../src/crypto/aes-wrap.o
endif
+endif
ifdef NEED_AES_CBC
NEED_AES_ENC=y
AESOBJS += ../src/crypto/aes-cbc.o
@@ -1208,8 +1213,10 @@
endif
ifndef CONFIG_FIPS
+ifneq ($(CONFIG_TLS), openssl)
MD5OBJS += ../src/crypto/md5.o
endif
+endif
ifdef NEED_MD5
ifdef CONFIG_INTERNAL_MD5
MD5OBJS += ../src/crypto/md5-internal.o
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index caa480c..c59ccc3 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -1701,6 +1701,8 @@
#ifdef CONFIG_HS20
const u8 *hs20;
#endif /* CONFIG_HS20 */
+ const u8 *sess_id;
+ size_t sess_id_len;
if (os_strcmp(params, "-DRIVER") == 0)
return wpa_drv_status(wpa_s, buf, buflen);
@@ -1933,6 +1935,24 @@
pos += res;
}
+ sess_id = eapol_sm_get_session_id(wpa_s->eapol, &sess_id_len);
+ if (sess_id) {
+ char *start = pos;
+
+ ret = os_snprintf(pos, end - pos, "eap_session_id=");
+ if (os_snprintf_error(end - pos, ret))
+ return start - buf;
+ pos += ret;
+ ret = wpa_snprintf_hex(pos, end - pos, sess_id, sess_id_len);
+ if (ret <= 0)
+ return start - buf;
+ pos += ret;
+ ret = os_snprintf(pos, end - pos, "\n");
+ if (os_snprintf_error(end - pos, ret))
+ return start - buf;
+ pos += ret;
+ }
+
res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose);
if (res >= 0)
pos += res;
@@ -4463,6 +4483,8 @@
u8 dev_type[WPS_DEV_TYPE_LEN], *_dev_type = NULL;
char *pos;
unsigned int search_delay;
+ const char *seek[P2P_MAX_QUERY_HASH + 1];
+ u8 seek_count = 0;
if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
wpa_dbg(wpa_s, MSG_INFO,
@@ -4497,8 +4519,180 @@
} else
search_delay = wpas_p2p_search_delay(wpa_s);
+ /* Must be searched for last, because it adds nul termination */
+ pos = os_strstr(cmd, " seek=");
+ while (pos && seek_count < P2P_MAX_QUERY_HASH + 1) {
+ char *term;
+
+ term = os_strchr(pos + 1, ' ');
+ seek[seek_count++] = pos + 6;
+ pos = os_strstr(pos + 6, " seek=");
+
+ if (term)
+ *term = '\0';
+ }
+
+ if (!seek_count)
+ return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL,
+ _dev_type, _dev_id,
+ search_delay, 0, NULL);
+
+ if (seek_count > P2P_MAX_QUERY_HASH) {
+ seek[0] = NULL;
+ return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL,
+ _dev_type, _dev_id,
+ search_delay, 1, seek);
+ }
+
return wpas_p2p_find(wpa_s, timeout, type, _dev_type != NULL, _dev_type,
- _dev_id, search_delay);
+ _dev_id, search_delay, seek_count, seek);
+}
+
+
+static struct p2ps_provision * p2p_parse_asp_provision_cmd(const char *cmd)
+{
+ struct p2ps_provision *p2ps_prov;
+ char *pos;
+ size_t info_len = 0;
+ char *info = NULL;
+ u8 role = P2PS_SETUP_NONE;
+ long long unsigned val;
+
+ pos = os_strstr(cmd, "info=");
+ if (pos) {
+ pos += 5;
+ info_len = os_strlen(pos);
+
+ if (info_len) {
+ info = os_malloc(info_len + 1);
+ if (info) {
+ info_len = utf8_unescape(pos, info_len,
+ info, info_len + 1);
+ } else
+ info_len = 0;
+ }
+ }
+
+ p2ps_prov = os_zalloc(sizeof(struct p2ps_provision) + info_len + 1);
+ if (p2ps_prov == NULL) {
+ os_free(info);
+ return NULL;
+ }
+
+ if (info) {
+ os_memcpy(p2ps_prov->info, info, info_len);
+ p2ps_prov->info[info_len] = '\0';
+ os_free(info);
+ }
+
+ pos = os_strstr(cmd, "status=");
+ if (pos)
+ p2ps_prov->status = atoi(pos + 7);
+ else
+ p2ps_prov->status = -1;
+
+ pos = os_strstr(cmd, "adv_id=");
+ if (!pos || sscanf(pos + 7, "%llx", &val) != 1 || val > 0xffffffffULL)
+ goto invalid_args;
+ p2ps_prov->adv_id = val;
+
+ pos = os_strstr(cmd, "method=");
+ if (pos)
+ p2ps_prov->method = strtol(pos + 7, NULL, 16);
+ else
+ p2ps_prov->method = 0;
+
+ pos = os_strstr(cmd, "session=");
+ if (!pos || sscanf(pos + 8, "%llx", &val) != 1 || val > 0xffffffffULL)
+ goto invalid_args;
+ p2ps_prov->session_id = val;
+
+ pos = os_strstr(cmd, "adv_mac=");
+ if (!pos || hwaddr_aton(pos + 8, p2ps_prov->adv_mac))
+ goto invalid_args;
+
+ pos = os_strstr(cmd, "session_mac=");
+ if (!pos || hwaddr_aton(pos + 12, p2ps_prov->session_mac))
+ goto invalid_args;
+
+ /* force conncap with tstCap (no sanity checks) */
+ pos = os_strstr(cmd, "tstCap=");
+ if (pos) {
+ role = strtol(pos + 7, NULL, 16);
+ } else {
+ pos = os_strstr(cmd, "role=");
+ if (pos) {
+ role = strtol(pos + 5, NULL, 16);
+ if (role != P2PS_SETUP_CLIENT &&
+ role != P2PS_SETUP_GROUP_OWNER)
+ role = P2PS_SETUP_NONE;
+ }
+ }
+ p2ps_prov->role = role;
+
+ return p2ps_prov;
+
+invalid_args:
+ os_free(p2ps_prov);
+ return NULL;
+}
+
+
+static int p2p_ctrl_asp_provision_resp(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ struct p2ps_provision *p2ps_prov;
+ char *pos;
+
+ /* <addr> id=<adv_id> [role=<conncap>] [info=<infodata>] */
+
+ wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd);
+
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ pos = cmd + 17;
+ if (*pos != ' ')
+ return -1;
+
+ p2ps_prov = p2p_parse_asp_provision_cmd(pos);
+ if (!p2ps_prov)
+ return -1;
+
+ if (p2ps_prov->status < 0) {
+ os_free(p2ps_prov);
+ return -1;
+ }
+
+ return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP,
+ p2ps_prov);
+}
+
+
+static int p2p_ctrl_asp_provision(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ struct p2ps_provision *p2ps_prov;
+ char *pos;
+
+ /* <addr> id=<adv_id> adv_mac=<adv_mac> conncap=<conncap>
+ * session=<ses_id> mac=<ses_mac> [info=<infodata>]
+ */
+
+ wpa_printf(MSG_DEBUG, "%s: %s", __func__, cmd);
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ pos = cmd + 17;
+ if (*pos != ' ')
+ return -1;
+
+ p2ps_prov = p2p_parse_asp_provision_cmd(pos);
+ if (!p2ps_prov)
+ return -1;
+
+ return wpas_p2p_prov_disc(wpa_s, addr, NULL, WPAS_P2P_PD_FOR_ASP,
+ p2ps_prov);
}
@@ -4520,7 +4714,7 @@
int pd;
int ht40, vht;
- /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad]
+ /* <addr> <"pbc" | "pin" | PIN> [label|display|keypad|p2ps]
* [persistent|persistent=<network id>]
* [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
* [ht40] [vht] */
@@ -4584,6 +4778,8 @@
*pos++ = '\0';
if (os_strncmp(pos, "display", 7) == 0)
wps_method = WPS_PIN_DISPLAY;
+ else if (os_strncmp(pos, "p2ps", 4) == 0)
+ wps_method = WPS_P2PS;
}
if (!wps_pin_str_valid(pin)) {
os_memcpy(buf, "FAIL-INVALID-PIN\n", 17);
@@ -4650,7 +4846,7 @@
else if (os_strstr(pos, " auto") != NULL)
use = WPAS_P2P_PD_AUTO;
- return wpas_p2p_prov_disc(wpa_s, addr, pos, use);
+ return wpas_p2p_prov_disc(wpa_s, addr, pos, use, NULL);
}
@@ -4703,6 +4899,40 @@
} else if (os_strncmp(pos, "wifi-display ", 13) == 0) {
ref = wpas_p2p_sd_request_wifi_display(wpa_s, dst, pos + 13);
#endif /* CONFIG_WIFI_DISPLAY */
+ } else if (os_strncmp(pos, "asp ", 4) == 0) {
+ char *svc_str;
+ char *svc_info = NULL;
+ u32 id;
+
+ pos += 4;
+ if (sscanf(pos, "%x", &id) != 1 || id > 0xff)
+ return -1;
+
+ pos = os_strchr(pos, ' ');
+ if (pos == NULL || pos[1] == '\0' || pos[1] == ' ')
+ return -1;
+
+ svc_str = pos + 1;
+
+ pos = os_strchr(svc_str, ' ');
+
+ if (pos)
+ *pos++ = '\0';
+
+ /* All remaining data is the svc_info string */
+ if (pos && pos[0] && pos[0] != ' ') {
+ len = os_strlen(pos);
+
+ /* Unescape in place */
+ len = utf8_unescape(pos, len, pos, len);
+ if (len > 0xff)
+ return -1;
+
+ svc_info = pos;
+ }
+
+ ref = wpas_p2p_sd_request_asp(wpa_s, dst, (u8) id,
+ svc_str, svc_info);
} else {
len = os_strlen(pos);
if (len & 1)
@@ -4865,6 +5095,106 @@
}
+static int p2p_ctrl_service_add_asp(struct wpa_supplicant *wpa_s,
+ u8 replace, char *cmd)
+{
+ char *pos;
+ char *adv_str;
+ u32 auto_accept, adv_id, svc_state, config_methods;
+ char *svc_info = NULL;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ /* Auto-Accept value is mandatory, and must be one of the
+ * single values (0, 1, 2, 4) */
+ auto_accept = atoi(cmd);
+ switch (auto_accept) {
+ case P2PS_SETUP_NONE: /* No auto-accept */
+ case P2PS_SETUP_NEW:
+ case P2PS_SETUP_CLIENT:
+ case P2PS_SETUP_GROUP_OWNER:
+ break;
+ default:
+ return -1;
+ }
+
+ /* Advertisement ID is mandatory */
+ cmd = pos;
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ /* Handle Adv_ID == 0 (wildcard "org.wi-fi.wfds") internally. */
+ if (sscanf(cmd, "%x", &adv_id) != 1 || adv_id == 0)
+ return -1;
+
+ /* Only allow replacements if exist, and adds if not */
+ if (wpas_p2p_service_p2ps_id_exists(wpa_s, adv_id)) {
+ if (!replace)
+ return -1;
+ } else {
+ if (replace)
+ return -1;
+ }
+
+ /* svc_state between 0 - 0xff is mandatory */
+ if (sscanf(pos, "%x", &svc_state) != 1 || svc_state > 0xff)
+ return -1;
+
+ pos = os_strchr(pos, ' ');
+ if (pos == NULL)
+ return -1;
+
+ /* config_methods is mandatory */
+ pos++;
+ if (sscanf(pos, "%x", &config_methods) != 1)
+ return -1;
+
+ if (!(config_methods &
+ (WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD | WPS_CONFIG_P2PS)))
+ return -1;
+
+ pos = os_strchr(pos, ' ');
+ if (pos == NULL)
+ return -1;
+
+ pos++;
+ adv_str = pos;
+
+ /* Advertisement string is mandatory */
+ if (!pos[0] || pos[0] == ' ')
+ return -1;
+
+ /* Terminate svc string */
+ pos = os_strchr(pos, ' ');
+ if (pos != NULL)
+ *pos++ = '\0';
+
+ /* Service and Response Information are optional */
+ if (pos && pos[0]) {
+ size_t len;
+
+ /* Note the bare ' included, which cannot exist legally
+ * in unescaped string. */
+ svc_info = os_strstr(pos, "svc_info='");
+
+ if (svc_info) {
+ svc_info += 9;
+ len = os_strlen(svc_info);
+ utf8_unescape(svc_info, len, svc_info, len);
+ }
+ }
+
+ return wpas_p2p_service_add_asp(wpa_s, auto_accept, adv_id, adv_str,
+ (u8) svc_state, (u16) config_methods,
+ svc_info);
+}
+
+
static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd)
{
char *pos;
@@ -4878,6 +5208,8 @@
return p2p_ctrl_service_add_bonjour(wpa_s, pos);
if (os_strcmp(cmd, "upnp") == 0)
return p2p_ctrl_service_add_upnp(wpa_s, pos);
+ if (os_strcmp(cmd, "asp") == 0)
+ return p2p_ctrl_service_add_asp(wpa_s, 0, pos);
wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
return -1;
}
@@ -4925,6 +5257,17 @@
}
+static int p2p_ctrl_service_del_asp(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u32 adv_id;
+
+ if (sscanf(cmd, "%x", &adv_id) != 1)
+ return -1;
+
+ return wpas_p2p_service_del_asp(wpa_s, adv_id);
+}
+
+
static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd)
{
char *pos;
@@ -4938,6 +5281,25 @@
return p2p_ctrl_service_del_bonjour(wpa_s, pos);
if (os_strcmp(cmd, "upnp") == 0)
return p2p_ctrl_service_del_upnp(wpa_s, pos);
+ if (os_strcmp(cmd, "asp") == 0)
+ return p2p_ctrl_service_del_asp(wpa_s, pos);
+ wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
+ return -1;
+}
+
+
+static int p2p_ctrl_service_replace(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ char *pos;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+
+ if (os_strcmp(cmd, "asp") == 0)
+ return p2p_ctrl_service_add_asp(wpa_s, 1, pos);
+
wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
return -1;
}
@@ -6201,6 +6563,7 @@
p2p_wpa_s->p2p_disable_ip_addr_req = 0;
os_free(p2p_wpa_s->global->p2p_go_avoid_freq.range);
p2p_wpa_s->global->p2p_go_avoid_freq.range = NULL;
+ p2p_wpa_s->global->pending_p2ps_group = 0;
#endif /* CONFIG_P2P */
#ifdef CONFIG_WPS_TESTING
@@ -7634,13 +7997,19 @@
#endif /* CONFIG_MESH */
#ifdef CONFIG_P2P
} else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
- if (p2p_ctrl_find(wpa_s, buf + 9))
+ if (p2p_ctrl_find(wpa_s, buf + 8))
reply_len = -1;
} else if (os_strcmp(buf, "P2P_FIND") == 0) {
if (p2p_ctrl_find(wpa_s, ""))
reply_len = -1;
} else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) {
wpas_p2p_stop_find(wpa_s);
+ } else if (os_strncmp(buf, "P2P_ASP_PROVISION ", 18) == 0) {
+ if (p2p_ctrl_asp_provision(wpa_s, buf + 18))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "P2P_ASP_PROVISION_RESP ", 23) == 0) {
+ if (p2p_ctrl_asp_provision_resp(wpa_s, buf + 23))
+ reply_len = -1;
} else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) {
reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply,
reply_size);
@@ -7686,6 +8055,9 @@
} else if (os_strncmp(buf, "P2P_SERVICE_DEL ", 16) == 0) {
if (p2p_ctrl_service_del(wpa_s, buf + 16) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "P2P_SERVICE_REP ", 16) == 0) {
+ if (p2p_ctrl_service_replace(wpa_s, buf + 16) < 0)
+ reply_len = -1;
} else if (os_strncmp(buf, "P2P_REJECT ", 11) == 0) {
if (p2p_ctrl_reject(wpa_s, buf + 11) < 0)
reply_len = -1;
@@ -8279,6 +8651,7 @@
"P2P_SERV_DISC_EXTERNAL ",
"P2P_SERVICE_ADD ",
"P2P_SERVICE_DEL ",
+ "P2P_SERVICE_REP ",
"P2P_REJECT ",
"P2P_INVITE ",
"P2P_PEER ",
@@ -8292,6 +8665,8 @@
"NFC_GET_HANDOVER_SEL ",
"NFC_GET_HANDOVER_REQ ",
"NFC_REPORT_HANDOVER ",
+ "P2P_ASP_PROVISION ",
+ "P2P_ASP_PROVISION_RESP ",
NULL
};
int found = 0;
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 9c880a2..24822bf 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -131,7 +131,7 @@
wpa_s = wpa_s->p2p_dev;
wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types,
- NULL, 0);
+ NULL, 0, 0, NULL);
os_free(req_dev_types);
return reply;
@@ -730,7 +730,7 @@
wpa_s = wpa_s->p2p_dev;
if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method,
- WPAS_P2P_PD_FOR_GO_NEG) < 0)
+ WPAS_P2P_PD_FOR_GO_NEG, NULL) < 0)
return wpas_dbus_error_unknown_error(message,
"Failed to send provision discovery request");
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index f1f8864..539832c 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -240,7 +240,7 @@
ie.pmkid + i * PMKID_LEN,
NULL, NULL, 0);
if (pmksa_set == 0) {
- eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
+ eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
break;
}
}
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 5ea046f..5b66211 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -250,8 +250,8 @@
struct wpabuf *extra = NULL;
int all = wpa_s->fetch_all_anqp;
- wpa_printf(MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR,
- MAC2STR(bss->bssid));
+ wpa_msg(wpa_s, MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR,
+ MAC2STR(bss->bssid));
wpa_s->interworking_gas_bss = bss;
info_ids[num_info_ids++] = ANQP_CAPABILITY_LIST;
@@ -312,14 +312,14 @@
res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, buf,
interworking_anqp_resp_cb, wpa_s);
if (res < 0) {
- wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+ wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Failed to send Query Request");
wpabuf_free(buf);
ret = -1;
eloop_register_timeout(0, 0, interworking_continue_anqp, wpa_s,
NULL);
} else
- wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
- "%u", res);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "ANQP: Query started with dialog token %u", res);
return ret;
}
@@ -966,8 +966,8 @@
if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
return -1;
- wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " (3GPP)",
- MAC2STR(bss->bssid));
+ wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Connect with " MACSTR
+ " (3GPP)", MAC2STR(bss->bssid));
if (already_connected(wpa_s, cred, bss)) {
wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
@@ -1024,13 +1024,13 @@
break;
}
if (res < 0) {
- wpa_printf(MSG_DEBUG, "Selected EAP method (%d) not supported",
- eap_type);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Selected EAP method (%d) not supported", eap_type);
goto fail;
}
if (!cred->pcsc && set_root_nai(ssid, cred->imsi, prefix) < 0) {
- wpa_printf(MSG_DEBUG, "Failed to set Root NAI");
+ wpa_msg(wpa_s, MSG_DEBUG, "Failed to set Root NAI");
goto fail;
}
@@ -1503,8 +1503,8 @@
{
struct wpa_ssid *ssid;
- wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " based on "
- "roaming consortium match", MAC2STR(bss->bssid));
+ wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Connect with " MACSTR
+ " based on roaming consortium match", MAC2STR(bss->bssid));
if (already_connected(wpa_s, cred, bss)) {
wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
@@ -1532,8 +1532,8 @@
goto fail;
if (cred->eap_method == NULL) {
- wpa_printf(MSG_DEBUG, "Interworking: No EAP method set for "
- "credential using roaming consortium");
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: No EAP method set for credential using roaming consortium");
goto fail;
}
@@ -1572,8 +1572,9 @@
return -1;
if (disallowed_bssid(wpa_s, bss->bssid) ||
disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
- wpa_printf(MSG_DEBUG, "Interworking: Reject connection to disallowed BSS "
- MACSTR, MAC2STR(bss->bssid));
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Reject connection to disallowed BSS "
+ MACSTR, MAC2STR(bss->bssid));
return -1;
}
@@ -1586,27 +1587,26 @@
* We currently support only HS 2.0 networks and those are
* required to use WPA2-Enterprise.
*/
- wpa_printf(MSG_DEBUG, "Interworking: Network does not use "
- "RSN");
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Network does not use RSN");
return -1;
}
cred_rc = interworking_credentials_available_roaming_consortium(
wpa_s, bss, 0, excl);
if (cred_rc) {
- wpa_printf(MSG_DEBUG, "Interworking: Highest roaming "
- "consortium matching credential priority %d "
- "sp_priority %d",
- cred_rc->priority, cred_rc->sp_priority);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Highest roaming consortium matching credential priority %d sp_priority %d",
+ cred_rc->priority, cred_rc->sp_priority);
if (allow_excluded && excl && !(*excl))
excl = NULL;
}
cred = interworking_credentials_available_realm(wpa_s, bss, 0, excl);
if (cred) {
- wpa_printf(MSG_DEBUG, "Interworking: Highest NAI Realm list "
- "matching credential priority %d sp_priority %d",
- cred->priority, cred->sp_priority);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Highest NAI Realm list matching credential priority %d sp_priority %d",
+ cred->priority, cred->sp_priority);
if (allow_excluded && excl && !(*excl))
excl = NULL;
}
@@ -1614,22 +1614,22 @@
cred_3gpp = interworking_credentials_available_3gpp(wpa_s, bss, 0,
excl);
if (cred_3gpp) {
- wpa_printf(MSG_DEBUG, "Interworking: Highest 3GPP matching "
- "credential priority %d sp_priority %d",
- cred_3gpp->priority, cred_3gpp->sp_priority);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Highest 3GPP matching credential priority %d sp_priority %d",
+ cred_3gpp->priority, cred_3gpp->sp_priority);
if (allow_excluded && excl && !(*excl))
excl = NULL;
}
if (!cred_rc && !cred && !cred_3gpp) {
- wpa_printf(MSG_DEBUG, "Interworking: No full credential matches - consider options without BW(etc.) limits");
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: No full credential matches - consider options without BW(etc.) limits");
cred_rc = interworking_credentials_available_roaming_consortium(
wpa_s, bss, 1, excl);
if (cred_rc) {
- wpa_printf(MSG_DEBUG, "Interworking: Highest roaming "
- "consortium matching credential priority %d "
- "sp_priority %d (ignore BW)",
- cred_rc->priority, cred_rc->sp_priority);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Highest roaming consortium matching credential priority %d sp_priority %d (ignore BW)",
+ cred_rc->priority, cred_rc->sp_priority);
if (allow_excluded && excl && !(*excl))
excl = NULL;
}
@@ -1637,10 +1637,9 @@
cred = interworking_credentials_available_realm(wpa_s, bss, 1,
excl);
if (cred) {
- wpa_printf(MSG_DEBUG, "Interworking: Highest NAI Realm "
- "list matching credential priority %d "
- "sp_priority %d (ignore BW)",
- cred->priority, cred->sp_priority);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Highest NAI Realm list matching credential priority %d sp_priority %d (ignore BW)",
+ cred->priority, cred->sp_priority);
if (allow_excluded && excl && !(*excl))
excl = NULL;
}
@@ -1648,10 +1647,9 @@
cred_3gpp = interworking_credentials_available_3gpp(wpa_s, bss,
1, excl);
if (cred_3gpp) {
- wpa_printf(MSG_DEBUG, "Interworking: Highest 3GPP "
- "matching credential priority %d "
- "sp_priority %d (ignore BW)",
- cred_3gpp->priority, cred_3gpp->sp_priority);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Highest 3GPP matching credential priority %d sp_priority %d (ignore BW)",
+ cred_3gpp->priority, cred_3gpp->sp_priority);
if (allow_excluded && excl && !(*excl))
excl = NULL;
}
@@ -1669,16 +1667,18 @@
}
if (cred == NULL) {
- wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
- "found for " MACSTR, MAC2STR(bss->bssid));
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: No matching credentials found for "
+ MACSTR, MAC2STR(bss->bssid));
return -1;
}
realm = nai_realm_parse(bss->anqp ? bss->anqp->nai_realm : NULL,
&count);
if (realm == NULL) {
- wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
- "Realm list from " MACSTR, MAC2STR(bss->bssid));
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Could not parse NAI Realm list from "
+ MACSTR, MAC2STR(bss->bssid));
return -1;
}
@@ -1691,15 +1691,15 @@
}
if (!eap) {
- wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
- "and EAP method found for " MACSTR,
- MAC2STR(bss->bssid));
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: No matching credentials and EAP method found for "
+ MACSTR, MAC2STR(bss->bssid));
nai_realm_free(realm, count);
return -1;
}
- wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR,
- MAC2STR(bss->bssid));
+ wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Connect with " MACSTR,
+ MAC2STR(bss->bssid));
if (already_connected(wpa_s, cred, bss)) {
wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
@@ -1927,10 +1927,12 @@
#if defined(PCSC_FUNCS) || defined(CONFIG_EAP_PROXY)
compare:
#endif /* PCSC_FUNCS || CONFIG_EAP_PROXY */
- wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from "
- MACSTR, MAC2STR(bss->bssid));
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Parsing 3GPP info from " MACSTR,
+ MAC2STR(bss->bssid));
ret = plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len);
- wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not ");
+ wpa_msg(wpa_s, MSG_DEBUG, "PLMN match %sfound",
+ ret ? "" : "not ");
if (ret) {
if (cred_no_required_oi_match(cred, bss))
continue;
@@ -1982,12 +1984,13 @@
if (wpa_s->conf->cred == NULL)
return NULL;
- wpa_printf(MSG_DEBUG, "Interworking: Parsing NAI Realm list from "
- MACSTR, MAC2STR(bss->bssid));
+ wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Parsing NAI Realm list from "
+ MACSTR, MAC2STR(bss->bssid));
realm = nai_realm_parse(bss->anqp->nai_realm, &count);
if (realm == NULL) {
- wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
- "Realm list from " MACSTR, MAC2STR(bss->bssid));
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Could not parse NAI Realm list from "
+ MACSTR, MAC2STR(bss->bssid));
return NULL;
}
@@ -2026,6 +2029,9 @@
}
}
break;
+ } else {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: realm-find-eap returned false");
}
}
}
@@ -2166,8 +2172,9 @@
realm = os_strchr(nai, '@');
if (realm)
realm++;
- wpa_printf(MSG_DEBUG, "Interworking: Search for match "
- "with SIM/USIM domain %s", realm);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Search for match with SIM/USIM domain %s",
+ realm);
if (realm &&
domain_name_list_contains(domain_names, realm, 1))
return 1;
@@ -2180,8 +2187,9 @@
return ret;
for (i = 0; i < cred->num_domain; i++) {
- wpa_printf(MSG_DEBUG, "Interworking: Search for match with "
- "home SP FQDN %s", cred->domain[i]);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Search for match with home SP FQDN %s",
+ cred->domain[i]);
if (domain_name_list_contains(domain_names, cred->domain[i], 1))
return 1;
}
@@ -2357,14 +2365,16 @@
&excluded);
if (!cred)
continue;
+
if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) {
/*
* We currently support only HS 2.0 networks and those
* are required to use WPA2-Enterprise.
*/
- wpa_printf(MSG_DEBUG, "Interworking: Credential match "
- "with " MACSTR " but network does not use "
- "RSN", MAC2STR(bss->bssid));
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Credential match with " MACSTR
+ " but network does not use RSN",
+ MAC2STR(bss->bssid));
continue;
}
if (!excluded)
@@ -2455,8 +2465,8 @@
* have matching APs.
*/
if (interworking_find_network_match(wpa_s)) {
- wpa_printf(MSG_DEBUG, "Interworking: Possible BSS "
- "match for enabled network configurations");
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Possible BSS match for enabled network configurations");
if (wpa_s->auto_select) {
interworking_reconnect(wpa_s);
return;
@@ -2464,8 +2474,8 @@
}
if (wpa_s->auto_network_select) {
- wpa_printf(MSG_DEBUG, "Interworking: Continue "
- "scanning after ANQP fetch");
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Continue scanning after ANQP fetch");
wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval,
0);
return;
@@ -2516,9 +2526,10 @@
os_memcmp(bss->ssid, other->ssid, bss->ssid_len) != 0)
continue;
- wpa_printf(MSG_DEBUG, "Interworking: Share ANQP data with "
- "already fetched BSSID " MACSTR " and " MACSTR,
- MAC2STR(other->bssid), MAC2STR(bss->bssid));
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Share ANQP data with already fetched BSSID "
+ MACSTR " and " MACSTR,
+ MAC2STR(other->bssid), MAC2STR(bss->bssid));
other->anqp->users++;
return other->anqp;
}
@@ -2661,8 +2672,9 @@
if (freq <= 0)
return -1;
- wpa_printf(MSG_DEBUG, "ANQP: Query Request to " MACSTR " for %u id(s)",
- MAC2STR(dst), (unsigned int) num_ids);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "ANQP: Query Request to " MACSTR " for %u id(s)",
+ MAC2STR(dst), (unsigned int) num_ids);
#ifdef CONFIG_HS20
if (subtypes != 0) {
@@ -2680,12 +2692,13 @@
res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
if (res < 0) {
- wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+ wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Failed to send Query Request");
wpabuf_free(buf);
ret = -1;
- } else
- wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
- "%u", res);
+ } else {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "ANQP: Query started with dialog token %u", res);
+ }
return ret;
}
@@ -2801,22 +2814,23 @@
pos, slen);
break;
default:
- wpa_printf(MSG_DEBUG, "HS20: Unsupported ANQP "
- "vendor type %u", type);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "HS20: Unsupported ANQP vendor type %u",
+ type);
break;
}
break;
#endif /* CONFIG_HS20 */
default:
- wpa_printf(MSG_DEBUG, "Interworking: Unsupported "
- "vendor-specific ANQP OUI %06x",
- WPA_GET_BE24(pos));
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Unsupported vendor-specific ANQP OUI %06x",
+ WPA_GET_BE24(pos));
return;
}
break;
default:
- wpa_printf(MSG_DEBUG, "Interworking: Unsupported ANQP Info ID "
- "%u", info_id);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Unsupported ANQP Info ID %u", info_id);
break;
}
}
@@ -2848,8 +2862,8 @@
pos = wpabuf_head(adv_proto);
if (wpabuf_len(adv_proto) < 4 || pos[0] != WLAN_EID_ADV_PROTO ||
pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) {
- wpa_printf(MSG_DEBUG, "ANQP: Unexpected Advertisement "
- "Protocol in response");
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "ANQP: Unexpected Advertisement Protocol in response");
if (wpa_s->fetch_osu_icon_in_progress)
hs20_icon_fetch_failed(wpa_s);
anqp_result = "INVALID_FRAME";
@@ -2878,7 +2892,7 @@
unsigned int left = end - pos;
if (left < 4) {
- wpa_printf(MSG_DEBUG, "ANQP: Invalid element");
+ wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Invalid element");
anqp_result = "INVALID_FRAME";
goto out_parse_done;
}
@@ -2888,8 +2902,9 @@
pos += 2;
left -= 4;
if (left < slen) {
- wpa_printf(MSG_DEBUG, "ANQP: Invalid element length "
- "for Info ID %u", info_id);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "ANQP: Invalid element length for Info ID %u",
+ info_id);
anqp_result = "INVALID_FRAME";
goto out_parse_done;
}
@@ -2909,8 +2924,8 @@
static void interworking_scan_res_handler(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *scan_res)
{
- wpa_printf(MSG_DEBUG, "Interworking: Scan results available - start "
- "ANQP fetch");
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Scan results available - start ANQP fetch");
interworking_start_fetch_anqp(wpa_s);
}
@@ -2924,8 +2939,8 @@
wpa_s->auto_select = !!auto_select;
wpa_s->fetch_all_anqp = 0;
wpa_s->fetch_osu_info = 0;
- wpa_printf(MSG_DEBUG, "Interworking: Start scan for network "
- "selection");
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Interworking: Start scan for network selection");
wpa_s->scan_res_handler = interworking_scan_res_handler;
wpa_s->normal_scans = 0;
wpa_s->scan_req = MANUAL_SCAN_REQ;
@@ -2986,8 +3001,8 @@
if (freq <= 0)
return -1;
- wpa_printf(MSG_DEBUG, "GAS request to " MACSTR " (freq %d MHz)",
- MAC2STR(dst), freq);
+ wpa_msg(wpa_s, MSG_DEBUG, "GAS request to " MACSTR " (freq %d MHz)",
+ MAC2STR(dst), freq);
wpa_hexdump_buf(MSG_DEBUG, "Advertisement Protocol ID", adv_proto);
wpa_hexdump_buf(MSG_DEBUG, "GAS Query", query);
@@ -3013,12 +3028,12 @@
res = gas_query_req(wpa_s->gas, dst, freq, buf, gas_resp_cb, wpa_s);
if (res < 0) {
- wpa_printf(MSG_DEBUG, "GAS: Failed to send Query Request");
+ wpa_msg(wpa_s, MSG_DEBUG, "GAS: Failed to send Query Request");
wpabuf_free(buf);
ret = -1;
} else
- wpa_printf(MSG_DEBUG, "GAS: Query started with dialog token "
- "%u", res);
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "GAS: Query started with dialog token %u", res);
return ret;
}
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index 4a259ff..1d6f2be 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -193,6 +193,11 @@
sta->my_lid = llid;
sta->peer_lid = 0;
+
+ /*
+ * We do not use wpa_mesh_set_plink_state() here because there is no
+ * entry in kernel yet.
+ */
sta->plink_state = PLINK_LISTEN;
}
@@ -348,9 +353,9 @@
/* configure peering state in ours and driver's station entry */
-static void
-wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s, struct sta_info *sta,
- enum mesh_plink_state state)
+void wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta,
+ enum mesh_plink_state state)
{
struct hostapd_sta_add_params params;
int ret;
@@ -379,14 +384,7 @@
eloop_cancel_timeout(plink_timer, wpa_s, sta);
- if (sta->mpm_close_reason == WLAN_REASON_MESH_CLOSE_RCVD) {
- ap_free_sta(hapd, sta);
- return;
- }
-
- wpa_mesh_set_plink_state(wpa_s, sta, PLINK_LISTEN);
- sta->my_lid = sta->peer_lid = sta->mpm_close_reason = 0;
- sta->mpm_retries = 0;
+ ap_free_sta(hapd, sta);
}
@@ -417,7 +415,7 @@
/* confirm timer */
if (!reason)
reason = WLAN_REASON_MESH_CONFIRM_TIMEOUT;
- sta->plink_state = PLINK_HOLDING;
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
eloop_register_timeout(conf->dot11MeshHoldingTimeout / 1000,
(conf->dot11MeshHoldingTimeout % 1000) * 1000,
plink_timer, wpa_s, sta);
@@ -521,27 +519,34 @@
mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
}
-
-void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
- struct ieee802_11_elems *elems)
+/*
+ * Initialize a sta_info structure for a peer and upload it into the driver
+ * in preparation for beginning authentication or peering. This is done when a
+ * Beacon (secure or open mesh) or a peering open frame (for open mesh) is
+ * received from the peer for the first time.
+ */
+static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s,
+ const u8 *addr,
+ struct ieee802_11_elems *elems)
{
struct hostapd_sta_add_params params;
struct mesh_conf *conf = wpa_s->ifmsh->mconf;
struct hostapd_data *data = wpa_s->ifmsh->bss[0];
struct sta_info *sta;
- struct wpa_ssid *ssid = wpa_s->current_ssid;
- int ret = 0;
+ int ret;
sta = ap_get_sta(data, addr);
if (!sta) {
sta = ap_sta_add(data, addr);
if (!sta)
- return;
+ return NULL;
}
/* initialize sta */
- if (copy_supp_rates(wpa_s, sta, elems))
- return;
+ if (copy_supp_rates(wpa_s, sta, elems)) {
+ ap_free_sta(data, sta);
+ return NULL;
+ }
mesh_mpm_init_link(wpa_s, sta);
@@ -575,9 +580,26 @@
wpa_msg(wpa_s, MSG_ERROR,
"Driver failed to insert " MACSTR ": %d",
MAC2STR(addr), ret);
- return;
+ ap_free_sta(data, sta);
+ return NULL;
}
+ return sta;
+}
+
+
+void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+ struct ieee802_11_elems *elems)
+{
+ struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+ struct hostapd_data *data = wpa_s->ifmsh->bss[0];
+ struct sta_info *sta;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+ sta = mesh_mpm_add_peer(wpa_s, addr, elems);
+ if (!sta)
+ return;
+
if (ssid && ssid->no_auto_peer) {
wpa_msg(wpa_s, MSG_INFO, "will not initiate new peer link with "
MACSTR " because of no_auto_peer", MAC2STR(addr));
@@ -930,6 +952,15 @@
wpa_printf(MSG_DEBUG, "MPM: plid=0x%x llid=0x%x", plid, llid);
sta = ap_get_sta(hapd, mgmt->sa);
+
+ /*
+ * If this is an open frame from an unknown STA, and this is an
+ * open mesh, then go ahead and add the peer before proceeding.
+ */
+ if (!sta && action_field == PLINK_OPEN &&
+ !(mconf->security & MESH_CONF_SEC_AMPE))
+ sta = mesh_mpm_add_peer(wpa_s, mgmt->sa, &elems);
+
if (!sta) {
wpa_printf(MSG_DEBUG, "MPM: No STA entry for peer");
return;
diff --git a/wpa_supplicant/mesh_mpm.h b/wpa_supplicant/mesh_mpm.h
index 2f7f6a7..7ebaef0 100644
--- a/wpa_supplicant/mesh_mpm.h
+++ b/wpa_supplicant/mesh_mpm.h
@@ -15,6 +15,9 @@
void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh);
void mesh_mpm_auth_peer(struct wpa_supplicant *wpa_s, const u8 *addr);
void mesh_mpm_free_sta(struct sta_info *sta);
+void wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s,
+ struct sta_info *sta,
+ enum mesh_plink_state state);
#ifdef CONFIG_MESH
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index aee325a..da4cb03 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -41,7 +41,7 @@
mesh_rsn_auth_sae_sta(wpa_s, sta);
} else {
/* block the STA if exceeded the number of attempts */
- sta->plink_state = PLINK_BLOCKED;
+ wpa_mesh_set_plink_state(wpa_s, sta, PLINK_BLOCKED);
sta->sae->state = SAE_NOTHING;
}
sta->sae_auth_retry++;
diff --git a/wpa_supplicant/offchannel.c b/wpa_supplicant/offchannel.c
index 7a86347..63af83a 100644
--- a/wpa_supplicant/offchannel.c
+++ b/wpa_supplicant/offchannel.c
@@ -354,15 +354,18 @@
*/
void offchannel_send_action_done(struct wpa_supplicant *wpa_s)
{
- wpa_printf(MSG_DEBUG, "Off-channel: Action frame sequence done "
- "notification");
+ wpa_printf(MSG_DEBUG,
+ "Off-channel: Action frame sequence done notification: pending_action_tx=%p drv_offchan_tx=%d action_tx_wait_time=%d off_channel_freq=%d roc_waiting_drv_freq=%d",
+ wpa_s->pending_action_tx,
+ !!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX),
+ wpa_s->action_tx_wait_time, wpa_s->off_channel_freq,
+ wpa_s->roc_waiting_drv_freq);
wpabuf_free(wpa_s->pending_action_tx);
wpa_s->pending_action_tx = NULL;
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX &&
wpa_s->action_tx_wait_time)
wpa_drv_send_action_cancel_wait(wpa_s);
-
- if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
+ else if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
wpa_drv_cancel_remain_on_channel(wpa_s);
wpa_s->off_channel_freq = 0;
wpa_s->roc_waiting_drv_freq = 0;
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 65c1b48..9e1d665 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -123,6 +123,8 @@
static void wpas_stop_listen(void *ctx);
static void wpas_p2p_psk_failure_removal(void *eloop_ctx, void *timeout_ctx);
static void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s);
+static int wpas_p2p_add_group_interface(struct wpa_supplicant *wpa_s,
+ enum wpa_driver_if_type type);
/*
@@ -475,6 +477,287 @@
}
+/* Determine total number of clients in active groups where we are the GO */
+static unsigned int p2p_group_go_member_count(struct wpa_supplicant *wpa_s)
+{
+ unsigned int count = 0;
+ struct wpa_ssid *s;
+
+ for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ for (s = wpa_s->conf->ssid; s; s = s->next) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: sup:%p ssid:%p disabled:%d p2p:%d mode:%d",
+ wpa_s, s, s->disabled, s->p2p_group,
+ s->mode);
+ if (!s->disabled && s->p2p_group &&
+ s->mode == WPAS_MODE_P2P_GO) {
+ count += p2p_get_group_num_members(
+ wpa_s->p2p_group);
+ }
+ }
+ }
+
+ return count;
+}
+
+
+/* Find an interface for a P2P group where we are the GO */
+static struct wpa_supplicant *
+wpas_p2p_get_go_group(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_supplicant *save = NULL;
+ struct wpa_ssid *s;
+
+ if (!wpa_s)
+ return NULL;
+
+ for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ for (s = wpa_s->conf->ssid; s; s = s->next) {
+ if (s->disabled || !s->p2p_group ||
+ s->mode != WPAS_MODE_P2P_GO)
+ continue;
+
+ /* Prefer a group with connected clients */
+ if (p2p_get_group_num_members(wpa_s->p2p_group))
+ return wpa_s;
+ save = wpa_s;
+ }
+ }
+
+ /* No group with connected clients, so pick the one without (if any) */
+ return save;
+}
+
+
+/* Find an active P2P group where we are the GO */
+static struct wpa_ssid * wpas_p2p_group_go_ssid(struct wpa_supplicant *wpa_s,
+ u8 *bssid)
+{
+ struct wpa_ssid *s, *empty = NULL;
+
+ if (!wpa_s)
+ return 0;
+
+ for (wpa_s = wpa_s->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ for (s = wpa_s->conf->ssid; s; s = s->next) {
+ if (s->disabled || !s->p2p_group ||
+ s->mode != WPAS_MODE_P2P_GO)
+ continue;
+
+ os_memcpy(bssid, wpa_s->own_addr, ETH_ALEN);
+ if (p2p_get_group_num_members(wpa_s->p2p_group))
+ return s;
+ empty = s;
+ }
+ }
+
+ return empty;
+}
+
+
+/* Find a persistent group where we are the GO */
+static struct wpa_ssid *
+wpas_p2p_get_persistent_go(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *s;
+
+ for (s = wpa_s->conf->ssid; s; s = s->next) {
+ if (s->disabled == 2 && s->mode == WPAS_MODE_P2P_GO)
+ return s;
+ }
+
+ return NULL;
+}
+
+
+static u8 p2ps_group_capability(void *ctx, u8 incoming, u8 role)
+{
+ struct wpa_supplicant *wpa_s = ctx, *tmp_wpa_s;
+ struct wpa_ssid *s;
+ u8 conncap = P2PS_SETUP_NONE;
+ unsigned int owned_members = 0;
+ unsigned int owner = 0;
+ unsigned int client = 0;
+ struct wpa_supplicant *go_wpa_s;
+ struct wpa_ssid *persistent_go;
+ int p2p_no_group_iface;
+
+ wpa_printf(MSG_DEBUG, "P2P: Conncap - in:%d role:%d", incoming, role);
+
+ /*
+ * For non-concurrent capable devices:
+ * If persistent_go, then no new.
+ * If GO, then no client.
+ * If client, then no GO.
+ */
+ go_wpa_s = wpas_p2p_get_go_group(wpa_s);
+ persistent_go = wpas_p2p_get_persistent_go(wpa_s);
+ p2p_no_group_iface = wpa_s->conf->p2p_no_group_iface;
+
+ wpa_printf(MSG_DEBUG, "P2P: GO(iface)=%p persistent(ssid)=%p",
+ go_wpa_s, persistent_go);
+
+ for (tmp_wpa_s = wpa_s->global->ifaces; tmp_wpa_s;
+ tmp_wpa_s = tmp_wpa_s->next) {
+ for (s = tmp_wpa_s->conf->ssid; s; s = s->next) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: sup:%p ssid:%p disabled:%d p2p:%d mode:%d",
+ tmp_wpa_s, s, s->disabled,
+ s->p2p_group, s->mode);
+ if (!s->disabled && s->p2p_group) {
+ if (s->mode == WPAS_MODE_P2P_GO) {
+ owned_members +=
+ p2p_get_group_num_members(
+ tmp_wpa_s->p2p_group);
+ owner++;
+ } else
+ client++;
+ }
+ }
+ }
+
+ /* If not concurrent, restrict our choices */
+ if (p2p_no_group_iface) {
+ wpa_printf(MSG_DEBUG, "P2P: p2p_no_group_iface");
+
+ if (client)
+ return P2PS_SETUP_NONE;
+
+ if (go_wpa_s) {
+ if (role == P2PS_SETUP_CLIENT ||
+ incoming == P2PS_SETUP_GROUP_OWNER ||
+ p2p_client_limit_reached(go_wpa_s->p2p_group))
+ return P2PS_SETUP_NONE;
+
+ return P2PS_SETUP_GROUP_OWNER;
+ }
+
+ if (persistent_go) {
+ if (role == P2PS_SETUP_NONE || role == P2PS_SETUP_NEW) {
+ if (!incoming)
+ return P2PS_SETUP_GROUP_OWNER |
+ P2PS_SETUP_CLIENT;
+ if (incoming == P2PS_SETUP_NEW) {
+ u8 r;
+
+ if (os_get_random(&r, sizeof(r)) < 0 ||
+ (r & 1))
+ return P2PS_SETUP_CLIENT;
+ return P2PS_SETUP_GROUP_OWNER;
+ }
+ }
+ }
+ }
+
+ /* If a required role has been specified, handle it here */
+ if (role && role != P2PS_SETUP_NEW) {
+ switch (incoming) {
+ case P2PS_SETUP_NONE:
+ case P2PS_SETUP_NEW:
+ case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT:
+ case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW:
+ conncap = role;
+ goto grp_owner;
+
+ case P2PS_SETUP_GROUP_OWNER:
+ /*
+ * Must be a complimentary role - cannot be a client to
+ * more than one peer.
+ */
+ if (incoming == role || client)
+ return P2PS_SETUP_NONE;
+
+ return P2PS_SETUP_CLIENT;
+
+ case P2PS_SETUP_CLIENT:
+ /* Must be a complimentary role */
+ if (incoming != role) {
+ conncap = P2PS_SETUP_GROUP_OWNER;
+ goto grp_owner;
+ }
+
+ default:
+ return P2PS_SETUP_NONE;
+ }
+ }
+
+ /*
+ * For now, we only will support ownership of one group, and being a
+ * client of one group. Therefore, if we have either an existing GO
+ * group, or an existing client group, we will not do a new GO
+ * negotiation, but rather try to re-use the existing groups.
+ */
+ switch (incoming) {
+ case P2PS_SETUP_NONE:
+ case P2PS_SETUP_NEW:
+ if (client)
+ conncap = P2PS_SETUP_GROUP_OWNER;
+ else if (!owned_members)
+ conncap = P2PS_SETUP_NEW;
+ else if (incoming == P2PS_SETUP_NONE)
+ conncap = P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT;
+ else
+ conncap = P2PS_SETUP_CLIENT;
+ break;
+
+ case P2PS_SETUP_CLIENT:
+ conncap = P2PS_SETUP_GROUP_OWNER;
+ break;
+
+ case P2PS_SETUP_GROUP_OWNER:
+ if (!client)
+ conncap = P2PS_SETUP_CLIENT;
+ break;
+
+ case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW:
+ case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT:
+ if (client)
+ conncap = P2PS_SETUP_GROUP_OWNER;
+ else {
+ u8 r;
+
+ if (os_get_random(&r, sizeof(r)) < 0 ||
+ (r & 1))
+ conncap = P2PS_SETUP_CLIENT;
+ else
+ conncap = P2PS_SETUP_GROUP_OWNER;
+ }
+ break;
+
+ default:
+ return P2PS_SETUP_NONE;
+ }
+
+grp_owner:
+ if ((conncap & P2PS_SETUP_GROUP_OWNER) ||
+ (!incoming && (conncap & P2PS_SETUP_NEW))) {
+ if (go_wpa_s && p2p_client_limit_reached(go_wpa_s->p2p_group))
+ conncap &= ~P2PS_SETUP_GROUP_OWNER;
+ wpa_printf(MSG_DEBUG, "P2P: GOs:%d members:%d conncap:%d",
+ owner, owned_members, conncap);
+
+ s = wpas_p2p_get_persistent_go(wpa_s);
+
+ if (!s && !owner && p2p_no_group_iface) {
+ p2p_set_intended_addr(wpa_s->global->p2p,
+ wpa_s->own_addr);
+ } else if (!s && !owner) {
+ if (wpas_p2p_add_group_interface(wpa_s,
+ WPA_IF_P2P_GO) < 0) {
+ wpa_printf(MSG_ERROR,
+ "P2P: Failed to allocate a new interface for the group");
+ return P2PS_SETUP_NONE;
+ }
+ wpa_s->global->pending_group_iface_for_p2ps = 1;
+ p2p_set_intended_addr(wpa_s->global->p2p,
+ wpa_s->pending_interface_addr);
+ }
+ }
+
+ return conncap;
+}
+
+
static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
enum p2p_group_removal_reason removal_reason)
{
@@ -1268,6 +1551,8 @@
#endif /* CONFIG_WPS_NFC */
} else {
u16 dev_pw_id = DEV_PW_DEFAULT;
+ if (wpa_s->p2p_wps_method == WPS_P2PS)
+ dev_pw_id = DEV_PW_P2PS_DEFAULT;
if (wpa_s->p2p_wps_method == WPS_PIN_KEYPAD)
dev_pw_id = DEV_PW_REGISTRAR_SPECIFIED;
wpas_wps_start_pin(wpa_s, res->peer_interface_addr,
@@ -1348,6 +1633,16 @@
}
+static void p2p_config_write(struct wpa_supplicant *wpa_s)
+{
+#ifndef CONFIG_NO_CONFIG_WRITE
+ if (wpa_s->parent->conf->update_config &&
+ wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf))
+ wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
+#endif /* CONFIG_NO_CONFIG_WRITE */
+}
+
+
static void p2p_go_configured(void *ctx, void *data)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -1371,6 +1666,16 @@
params->persistent_group, "");
wpa_s->group_formation_reported = 1;
+ if (wpa_s->parent->p2ps_join_addr_valid) {
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2PS: Setting default PIN for " MACSTR,
+ MAC2STR(wpa_s->parent->p2ps_join_addr));
+ wpa_supplicant_ap_wps_pin(wpa_s,
+ wpa_s->parent->p2ps_join_addr,
+ "12345670", NULL, 0, 0);
+ wpa_s->parent->p2ps_join_addr_valid = 0;
+ }
+
os_get_reltime(&wpa_s->global->p2p_go_wait_client);
if (params->persistent_group) {
network_id = wpas_p2p_store_persistent_group(
@@ -1639,6 +1944,7 @@
wpa_s->pending_interface_name);
os_memset(wpa_s->pending_interface_addr, 0, ETH_ALEN);
wpa_s->pending_interface_name[0] = '\0';
+ wpa_s->global->pending_group_iface_for_p2ps = 0;
}
@@ -1684,6 +1990,7 @@
group_wpa_s->p2p_group_interface = go ? P2P_GROUP_INTERFACE_GO :
P2P_GROUP_INTERFACE_CLIENT;
wpa_s->global->p2p_group_formation = group_wpa_s;
+ wpa_s->global->pending_group_iface_for_p2ps = 0;
wpas_p2p_clone_config(group_wpa_s, wpa_s);
@@ -1847,6 +2154,52 @@
WFD_SUBELEM_DEVICE_INFO);
#endif /* CONFIG_WIFI_DISPLAY */
+ if (info->p2ps_instance) {
+ char str[256];
+ const u8 *buf = wpabuf_head(info->p2ps_instance);
+ size_t len = wpabuf_len(info->p2ps_instance);
+
+ while (len) {
+ u32 id;
+ u16 methods;
+ u8 str_len;
+
+ if (len < 4 + 2 + 1)
+ break;
+ id = WPA_GET_LE32(buf);
+ buf += sizeof(u32);
+ methods = WPA_GET_BE16(buf);
+ buf += sizeof(u16);
+ str_len = *buf++;
+ if (str_len > len - 4 - 2 - 1)
+ break;
+ os_memcpy(str, buf, str_len);
+ str[str_len] = '\0';
+ buf += str_len;
+ len -= str_len + sizeof(u32) + sizeof(u16) + sizeof(u8);
+
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_DEVICE_FOUND MACSTR
+ " p2p_dev_addr=" MACSTR
+ " pri_dev_type=%s name='%s'"
+ " config_methods=0x%x"
+ " dev_capab=0x%x"
+ " group_capab=0x%x"
+ " adv_id=%x asp_svc=%s%s",
+ MAC2STR(addr),
+ MAC2STR(info->p2p_device_addr),
+ wps_dev_type_bin2str(
+ info->pri_dev_type,
+ devtype, sizeof(devtype)),
+ info->device_name, methods,
+ info->dev_capab, info->group_capab,
+ id, str,
+ info->vendor_elems ?
+ " vendor_elems=1" : "");
+ }
+ goto done;
+ }
+
wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_FOUND MACSTR
" p2p_dev_addr=" MACSTR
" pri_dev_type=%s name='%s' config_methods=0x%x "
@@ -1861,6 +2214,7 @@
info->vendor_elems ? " vendor_elems=1" : "",
new_device);
+done:
os_free(wfd_dev_info_hex);
#endif /* CONFIG_NO_STDOUT_DEBUG */
@@ -2187,8 +2541,8 @@
}
-static void wpas_sd_add_proto_not_avail(struct wpabuf *resp, u8 srv_proto,
- u8 srv_trans_id)
+static void wpas_sd_add_empty(struct wpabuf *resp, u8 srv_proto,
+ u8 srv_trans_id, u8 status)
{
u8 *len_pos;
@@ -2200,12 +2554,35 @@
wpabuf_put_u8(resp, srv_proto);
wpabuf_put_u8(resp, srv_trans_id);
/* Status Code */
- wpabuf_put_u8(resp, P2P_SD_PROTO_NOT_AVAILABLE);
+ wpabuf_put_u8(resp, status);
/* Response Data: empty */
WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
}
+static void wpas_sd_add_proto_not_avail(struct wpabuf *resp, u8 srv_proto,
+ u8 srv_trans_id)
+{
+ wpas_sd_add_empty(resp, srv_proto, srv_trans_id,
+ P2P_SD_PROTO_NOT_AVAILABLE);
+}
+
+
+static void wpas_sd_add_bad_request(struct wpabuf *resp, u8 srv_proto,
+ u8 srv_trans_id)
+{
+ wpas_sd_add_empty(resp, srv_proto, srv_trans_id, P2P_SD_BAD_REQUEST);
+}
+
+
+static void wpas_sd_add_not_found(struct wpabuf *resp, u8 srv_proto,
+ u8 srv_trans_id)
+{
+ wpas_sd_add_empty(resp, srv_proto, srv_trans_id,
+ P2P_SD_REQUESTED_INFO_NOT_AVAILABLE);
+}
+
+
static void wpas_sd_all_bonjour(struct wpa_supplicant *wpa_s,
struct wpabuf *resp, u8 srv_trans_id)
{
@@ -2513,6 +2890,148 @@
#endif /* CONFIG_WIFI_DISPLAY */
+static int find_p2ps_substr(struct p2ps_advertisement *adv_data,
+ const u8 *needle, size_t needle_len)
+{
+ const u8 *haystack = (const u8 *) adv_data->svc_info;
+ size_t haystack_len, i;
+
+ /* Allow search term to be empty */
+ if (!needle || !needle_len)
+ return 1;
+
+ if (!haystack)
+ return 0;
+
+ haystack_len = os_strlen(adv_data->svc_info);
+ for (i = 0; i < haystack_len; i++) {
+ if (haystack_len - i < needle_len)
+ break;
+ if (os_memcmp(haystack + i, needle, needle_len) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void wpas_sd_req_asp(struct wpa_supplicant *wpa_s,
+ struct wpabuf *resp, u8 srv_trans_id,
+ const u8 *query, size_t query_len)
+{
+ struct p2ps_advertisement *adv_data;
+ const u8 *svc = &query[1];
+ const u8 *info = NULL;
+ size_t svc_len = query[0];
+ size_t info_len = 0;
+ int prefix = 0;
+ u8 *count_pos = NULL;
+ u8 *len_pos = NULL;
+
+ wpa_hexdump(MSG_DEBUG, "P2P: SD Request for ASP", query, query_len);
+
+ if (!wpa_s->global->p2p) {
+ wpa_printf(MSG_DEBUG, "P2P: ASP protocol not available");
+ wpas_sd_add_proto_not_avail(resp, P2P_SERV_P2PS, srv_trans_id);
+ return;
+ }
+
+ /* Info block is optional */
+ if (svc_len + 1 < query_len) {
+ info = &svc[svc_len];
+ info_len = *info++;
+ }
+
+ /* Range check length of svc string and info block */
+ if (svc_len + (info_len ? info_len + 2 : 1) > query_len) {
+ wpa_printf(MSG_DEBUG, "P2P: ASP bad request");
+ wpas_sd_add_bad_request(resp, P2P_SERV_P2PS, srv_trans_id);
+ return;
+ }
+
+ /* Detect and correct for prefix search */
+ if (svc_len && svc[svc_len - 1] == '*') {
+ prefix = 1;
+ svc_len--;
+ }
+
+ for (adv_data = p2p_get_p2ps_adv_list(wpa_s->global->p2p);
+ adv_data; adv_data = adv_data->next) {
+ /* If not a prefix match, reject length mismatches */
+ if (!prefix && svc_len != os_strlen(adv_data->svc_name))
+ continue;
+
+ /* Search each service for request */
+ if (os_memcmp(adv_data->svc_name, svc, svc_len) == 0 &&
+ find_p2ps_substr(adv_data, info, info_len)) {
+ size_t len = os_strlen(adv_data->svc_name);
+ size_t svc_info_len = 0;
+
+ if (adv_data->svc_info)
+ svc_info_len = os_strlen(adv_data->svc_info);
+
+ if (len > 0xff || svc_info_len > 0xffff)
+ return;
+
+ /* Length & Count to be filled as we go */
+ if (!len_pos && !count_pos) {
+ if (wpabuf_tailroom(resp) <
+ len + svc_info_len + 16)
+ return;
+
+ len_pos = wpabuf_put(resp, 2);
+ wpabuf_put_u8(resp, P2P_SERV_P2PS);
+ wpabuf_put_u8(resp, srv_trans_id);
+ /* Status Code */
+ wpabuf_put_u8(resp, P2P_SD_SUCCESS);
+ count_pos = wpabuf_put(resp, 1);
+ *count_pos = 0;
+ } else if (wpabuf_tailroom(resp) <
+ len + svc_info_len + 10)
+ return;
+
+ if (svc_info_len) {
+ wpa_printf(MSG_DEBUG,
+ "P2P: Add Svc: %s info: %s",
+ adv_data->svc_name,
+ adv_data->svc_info);
+ } else {
+ wpa_printf(MSG_DEBUG, "P2P: Add Svc: %s",
+ adv_data->svc_name);
+ }
+
+ /* Advertisement ID */
+ wpabuf_put_le32(resp, adv_data->id);
+
+ /* Config Methods */
+ wpabuf_put_be16(resp, adv_data->config_methods);
+
+ /* Service Name */
+ wpabuf_put_u8(resp, (u8) len);
+ wpabuf_put_data(resp, adv_data->svc_name, len);
+
+ /* Service State */
+ wpabuf_put_u8(resp, adv_data->state);
+
+ /* Service Information */
+ wpabuf_put_le16(resp, (u16) svc_info_len);
+ wpabuf_put_data(resp, adv_data->svc_info, svc_info_len);
+
+ /* Update length and count */
+ (*count_pos)++;
+ WPA_PUT_LE16(len_pos,
+ (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
+ }
+ }
+
+ /* Return error if no matching svc found */
+ if (count_pos == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: ASP service not found");
+ wpas_sd_add_not_found(resp, P2P_SERV_P2PS, srv_trans_id);
+ }
+}
+
+
static void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
u16 update_indic, const u8 *tlvs, size_t tlvs_len)
{
@@ -2610,6 +3129,10 @@
pos, tlv_end - pos);
break;
#endif /* CONFIG_WIFI_DISPLAY */
+ case P2P_SERV_P2PS:
+ wpas_sd_req_asp(wpa_s, resp, srv_trans_id,
+ pos, tlv_end - pos);
+ break;
default:
wpa_printf(MSG_DEBUG, "P2P: Unavailable service "
"protocol %u", srv_proto);
@@ -2631,6 +3154,80 @@
}
+static void wpas_sd_p2ps_serv_response(struct wpa_supplicant *wpa_s,
+ const u8 *sa, u8 srv_trans_id,
+ const u8 *pos, const u8 *tlv_end)
+{
+ u8 left = *pos++;
+ u32 adv_id;
+ u8 svc_status;
+ u16 config_methods;
+ char svc_str[256];
+
+ while (left-- && pos < tlv_end) {
+ char *buf = NULL;
+ size_t buf_len;
+ u8 svc_len;
+
+ /* Sanity check fixed length+svc_str */
+ if (pos + 6 >= tlv_end)
+ break;
+ svc_len = pos[6];
+ if (pos + svc_len + 10 > tlv_end)
+ break;
+
+ /* Advertisement ID */
+ adv_id = WPA_GET_LE32(pos);
+ pos += sizeof(u32);
+
+ /* Config Methods */
+ config_methods = WPA_GET_BE16(pos);
+ pos += sizeof(u16);
+
+ /* Service Name */
+ pos++; /* svc_len */
+ os_memcpy(svc_str, pos, svc_len);
+ svc_str[svc_len] = '\0';
+ pos += svc_len;
+
+ /* Service Status */
+ svc_status = *pos++;
+
+ /* Service Information Length */
+ buf_len = WPA_GET_LE16(pos);
+ pos += sizeof(u16);
+
+ /* Sanity check buffer length */
+ if (buf_len > (unsigned int) (tlv_end - pos))
+ break;
+
+ if (buf_len) {
+ buf = os_zalloc(2 * buf_len + 1);
+ if (buf) {
+ utf8_escape((const char *) pos, buf_len, buf,
+ 2 * buf_len + 1);
+ }
+ }
+
+ pos += buf_len;
+
+ if (buf) {
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_SERV_ASP_RESP
+ MACSTR " %x %x %x %x %s '%s'",
+ MAC2STR(sa), srv_trans_id, adv_id,
+ svc_status, config_methods, svc_str,
+ buf);
+ os_free(buf);
+ } else {
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_SERV_ASP_RESP
+ MACSTR " %x %x %x %x %s",
+ MAC2STR(sa), srv_trans_id, adv_id,
+ svc_status, config_methods, svc_str);
+ }
+ }
+}
+
+
static void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
const u8 *tlvs, size_t tlvs_len)
{
@@ -2689,6 +3286,11 @@
wpa_hexdump(MSG_MSGDUMP, "P2P: Response Data",
pos, tlv_end - pos);
+ if (srv_proto == P2P_SERV_P2PS && pos < tlv_end) {
+ wpas_sd_p2ps_serv_response(wpa_s, sa, srv_trans_id,
+ pos, tlv_end);
+ }
+
pos = tlv_end;
}
@@ -2725,6 +3327,39 @@
}
+u64 wpas_p2p_sd_request_asp(struct wpa_supplicant *wpa_s, const u8 *dst, u8 id,
+ const char *svc_str, const char *info_substr)
+{
+ struct wpabuf *tlvs;
+ size_t plen, svc_len, substr_len = 0;
+ u64 ret;
+
+ svc_len = os_strlen(svc_str);
+ if (info_substr)
+ substr_len = os_strlen(info_substr);
+
+ if (svc_len > 0xff || substr_len > 0xff)
+ return 0;
+
+ plen = 1 + 1 + 1 + svc_len + 1 + substr_len;
+ tlvs = wpabuf_alloc(2 + plen);
+ if (tlvs == NULL)
+ return 0;
+
+ wpabuf_put_le16(tlvs, plen);
+ wpabuf_put_u8(tlvs, P2P_SERV_P2PS);
+ wpabuf_put_u8(tlvs, id); /* Service Transaction ID */
+ wpabuf_put_u8(tlvs, (u8) svc_len); /* Service String Length */
+ wpabuf_put_data(tlvs, svc_str, svc_len);
+ wpabuf_put_u8(tlvs, (u8) substr_len); /* Info Substring Length */
+ wpabuf_put_data(tlvs, info_substr, substr_len);
+ ret = wpas_p2p_sd_request(wpa_s, dst, tlvs);
+ wpabuf_free(tlvs);
+
+ return ret;
+}
+
+
#ifdef CONFIG_WIFI_DISPLAY
static u64 wpas_p2p_sd_request_wfd(struct wpa_supplicant *wpa_s, const u8 *dst,
@@ -2866,6 +3501,35 @@
}
+int wpas_p2p_service_p2ps_id_exists(struct wpa_supplicant *wpa_s, u32 adv_id)
+{
+ if (adv_id == 0)
+ return 1;
+
+ if (p2p_service_p2ps_id(wpa_s->global->p2p, adv_id))
+ return 1;
+
+ return 0;
+}
+
+
+int wpas_p2p_service_del_asp(struct wpa_supplicant *wpa_s, u32 adv_id)
+{
+ return p2p_service_del_asp(wpa_s->global->p2p, adv_id);
+}
+
+
+int wpas_p2p_service_add_asp(struct wpa_supplicant *wpa_s,
+ int auto_accept, u32 adv_id,
+ const char *adv_str, u8 svc_state,
+ u16 config_methods, const char *svc_info)
+{
+ return p2p_service_add_asp(wpa_s->global->p2p, auto_accept, adv_id,
+ adv_str, svc_state, config_methods,
+ svc_info);
+}
+
+
int wpas_p2p_service_add_bonjour(struct wpa_supplicant *wpa_s,
struct wpabuf *query, struct wpabuf *resp)
{
@@ -3055,7 +3719,9 @@
static void wpas_prov_disc_fail(void *ctx, const u8 *peer,
- enum p2p_prov_disc_status status)
+ enum p2p_prov_disc_status status,
+ u32 adv_id, const u8 *adv_mac,
+ const char *deferred_session_resp)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -3075,9 +3741,21 @@
return;
}
- wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
- " p2p_dev_addr=" MACSTR " status=%d",
- MAC2STR(peer), status);
+ if (adv_id && adv_mac && deferred_session_resp) {
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
+ " p2p_dev_addr=" MACSTR " status=%d adv_id=%x"
+ " deferred_session_resp='%s'",
+ MAC2STR(peer), status, adv_id,
+ deferred_session_resp);
+ } else if (adv_id && adv_mac) {
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
+ " p2p_dev_addr=" MACSTR " status=%d adv_id=%x",
+ MAC2STR(peer), status, adv_id);
+ } else {
+ wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_PROV_DISC_FAILURE
+ " p2p_dev_addr=" MACSTR " status=%d",
+ MAC2STR(peer), status);
+ }
wpas_notify_p2p_provision_discovery(wpa_s, peer, 0 /* response */,
status, 0, 0);
@@ -4012,6 +4690,337 @@
}
+static int wpas_get_persistent_group(void *ctx, const u8 *addr, const u8 *ssid,
+ size_t ssid_len, u8 *go_dev_addr,
+ u8 *ret_ssid, size_t *ret_ssid_len)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct wpa_ssid *s;
+
+ s = wpas_p2p_get_persistent(wpa_s, addr, ssid, ssid_len);
+ if (s) {
+ os_memcpy(ret_ssid, s->ssid, s->ssid_len);
+ *ret_ssid_len = s->ssid_len;
+ os_memcpy(go_dev_addr, s->bssid, ETH_ALEN);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int wpas_get_go_info(void *ctx, u8 *intended_addr,
+ u8 *ssid, size_t *ssid_len, int *group_iface)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct wpa_ssid *s;
+ u8 bssid[ETH_ALEN];
+
+ s = wpas_p2p_group_go_ssid(wpa_s, bssid);
+ if (!s) {
+ s = wpas_p2p_get_persistent_go(wpa_s);
+ if (s)
+ os_memcpy(bssid, s->bssid, ETH_ALEN);
+ }
+
+ *group_iface = wpas_p2p_create_iface(wpa_s);
+ if (!s)
+ return 0;
+
+ os_memcpy(intended_addr, bssid, ETH_ALEN);
+ os_memcpy(ssid, s->ssid, s->ssid_len);
+ *ssid_len = s->ssid_len;
+
+ return 1;
+}
+
+
+static int wpas_remove_stale_groups(void *ctx, const u8 *peer, const u8 *go,
+ const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct wpa_ssid *s;
+ int save_config = 0;
+ size_t i;
+
+ /* Start with our first choice of Persistent Groups */
+ while ((s = wpas_p2p_get_persistent(wpa_s, peer, NULL, 0))) {
+ if (go && ssid && ssid_len &&
+ s->ssid_len == ssid_len &&
+ os_memcmp(go, s->bssid, ETH_ALEN) == 0 &&
+ os_memcmp(ssid, s->ssid, ssid_len) == 0)
+ break;
+
+ /* Remove stale persistent group */
+ if (s->mode != WPAS_MODE_P2P_GO || s->num_p2p_clients <= 1) {
+ wpa_config_remove_network(wpa_s->conf, s->id);
+ save_config = 1;
+ continue;
+ }
+
+ for (i = 0; i < s->num_p2p_clients; i++) {
+ if (os_memcmp(s->p2p_client_list + i * 2 * ETH_ALEN,
+ peer, ETH_ALEN) != 0)
+ continue;
+
+ os_memmove(s->p2p_client_list + i * 2 * ETH_ALEN,
+ s->p2p_client_list + (i + 1) * 2 * ETH_ALEN,
+ (s->num_p2p_clients - i - 1) * 2 * ETH_ALEN);
+ break;
+ }
+ s->num_p2p_clients--;
+ save_config = 1;
+ }
+
+ if (save_config)
+ p2p_config_write(wpa_s);
+
+ /* Return TRUE if valid SSID remains */
+ return s != NULL;
+}
+
+
+static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev,
+ const u8 *adv_mac, const u8 *ses_mac,
+ const u8 *grp_mac, u32 adv_id, u32 ses_id,
+ u8 conncap, int passwd_id,
+ const u8 *persist_ssid,
+ size_t persist_ssid_size, int response_done,
+ int prov_start, const char *session_info)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ u8 mac[ETH_ALEN];
+ struct wpa_ssid *persistent_go, *stale, *s;
+ int save_config = 0;
+ struct wpa_supplicant *go_wpa_s;
+
+ if (!dev)
+ return;
+
+ os_memset(mac, 0, ETH_ALEN);
+ if (!adv_mac)
+ adv_mac = mac;
+ if (!ses_mac)
+ ses_mac = mac;
+ if (!grp_mac)
+ grp_mac = mac;
+
+ if (prov_start) {
+ if (session_info == NULL) {
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_P2PS_PROVISION_START MACSTR
+ " adv_id=%x conncap=%x"
+ " adv_mac=" MACSTR
+ " session=%x mac=" MACSTR
+ " dev_passwd_id=%d",
+ MAC2STR(dev), adv_id, conncap,
+ MAC2STR(adv_mac),
+ ses_id, MAC2STR(ses_mac),
+ passwd_id);
+ } else {
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_P2PS_PROVISION_START MACSTR
+ " adv_id=%x conncap=%x"
+ " adv_mac=" MACSTR
+ " session=%x mac=" MACSTR
+ " dev_passwd_id=%d info='%s'",
+ MAC2STR(dev), adv_id, conncap,
+ MAC2STR(adv_mac),
+ ses_id, MAC2STR(ses_mac),
+ passwd_id, session_info);
+ }
+ return;
+ }
+
+ go_wpa_s = wpas_p2p_get_go_group(wpa_s);
+ persistent_go = wpas_p2p_get_persistent_go(wpa_s);
+
+ if (status && status != P2P_SC_SUCCESS_DEFERRED) {
+ if (go_wpa_s && !p2p_group_go_member_count(wpa_s))
+ wpas_p2p_group_remove(wpa_s, go_wpa_s->ifname);
+
+ if (persistent_go && !persistent_go->num_p2p_clients) {
+ /* remove empty persistent GO */
+ wpa_config_remove_network(wpa_s->conf,
+ persistent_go->id);
+ }
+
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_P2PS_PROVISION_DONE MACSTR
+ " status=%d"
+ " adv_id=%x adv_mac=" MACSTR
+ " session=%x mac=" MACSTR,
+ MAC2STR(dev), status,
+ adv_id, MAC2STR(adv_mac),
+ ses_id, MAC2STR(ses_mac));
+ return;
+ }
+
+ /* Clean up stale persistent groups with this device */
+ s = wpas_p2p_get_persistent(wpa_s, dev, persist_ssid,
+ persist_ssid_size);
+ for (;;) {
+ stale = wpas_p2p_get_persistent(wpa_s, dev, NULL, 0);
+ if (!stale)
+ break;
+
+ if (s && s->ssid_len == stale->ssid_len &&
+ os_memcmp(stale->bssid, s->bssid, ETH_ALEN) == 0 &&
+ os_memcmp(stale->ssid, s->ssid, s->ssid_len) == 0)
+ break;
+
+ /* Remove stale persistent group */
+ if (stale->mode != WPAS_MODE_P2P_GO ||
+ stale->num_p2p_clients <= 1) {
+ wpa_config_remove_network(wpa_s->conf, stale->id);
+ } else {
+ size_t i;
+
+ for (i = 0; i < stale->num_p2p_clients; i++) {
+ if (os_memcmp(stale->p2p_client_list +
+ i * ETH_ALEN,
+ dev, ETH_ALEN) == 0) {
+ os_memmove(stale->p2p_client_list +
+ i * ETH_ALEN,
+ stale->p2p_client_list +
+ (i + 1) * ETH_ALEN,
+ (stale->num_p2p_clients -
+ i - 1) * ETH_ALEN);
+ break;
+ }
+ }
+ stale->num_p2p_clients--;
+ }
+ save_config = 1;
+ }
+
+ if (save_config)
+ p2p_config_write(wpa_s);
+
+ if (s) {
+ if (go_wpa_s && !p2p_group_go_member_count(wpa_s))
+ wpas_p2p_group_remove(wpa_s, go_wpa_s->ifname);
+
+ if (persistent_go && s != persistent_go &&
+ !persistent_go->num_p2p_clients) {
+ /* remove empty persistent GO */
+ wpa_config_remove_network(wpa_s->conf,
+ persistent_go->id);
+ /* Save config */
+ }
+
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_P2PS_PROVISION_DONE MACSTR
+ " status=%d"
+ " adv_id=%x adv_mac=" MACSTR
+ " session=%x mac=" MACSTR
+ " persist=%d",
+ MAC2STR(dev), status,
+ adv_id, MAC2STR(adv_mac),
+ ses_id, MAC2STR(ses_mac), s->id);
+ return;
+ }
+
+ if (conncap == P2PS_SETUP_GROUP_OWNER) {
+ const char *go_ifname = NULL;
+ if (!go_wpa_s) {
+ wpa_s->global->pending_p2ps_group = 1;
+
+ if (wpa_s->conf->p2p_no_group_iface)
+ go_ifname = wpa_s->ifname;
+ else if (wpa_s->pending_interface_name[0])
+ go_ifname = wpa_s->pending_interface_name;
+
+ if (!go_ifname) {
+ wpas_p2ps_prov_complete(
+ wpa_s, P2P_SC_FAIL_UNKNOWN_GROUP,
+ dev, adv_mac, ses_mac,
+ NULL, adv_id, ses_id, 0, 0,
+ NULL, 0, 0, 0, NULL);
+ return;
+ }
+
+ /* If PD Resp complete, start up the GO */
+ if (response_done && persistent_go) {
+ wpas_p2p_group_add_persistent(
+ wpa_s, persistent_go,
+ 0, 0, 0, 0, 0, NULL,
+ persistent_go->mode ==
+ WPAS_MODE_P2P_GO ?
+ P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
+ 0);
+ } else if (response_done) {
+ wpas_p2p_group_add(wpa_s, 1, 0, 0, 0);
+ }
+
+ if (passwd_id == DEV_PW_P2PS_DEFAULT) {
+ os_memcpy(wpa_s->p2ps_join_addr, dev, ETH_ALEN);
+ wpa_s->p2ps_join_addr_valid = 1;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2PS: Saving PIN for " MACSTR,
+ MAC2STR(dev));
+ }
+ } else if (passwd_id == DEV_PW_P2PS_DEFAULT) {
+ go_ifname = go_wpa_s->ifname;
+
+ wpa_dbg(go_wpa_s, MSG_DEBUG,
+ "P2P: Setting PIN-1 For " MACSTR, MAC2STR(dev));
+ wpa_supplicant_ap_wps_pin(go_wpa_s, dev, "12345670",
+ NULL, 0, 0);
+
+ os_memcpy(wpa_s->p2ps_join_addr, dev, ETH_ALEN);
+ wpa_s->p2ps_join_addr_valid = 1;
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ "P2PS: Saving PIN for " MACSTR, MAC2STR(dev));
+ }
+
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_P2PS_PROVISION_DONE MACSTR
+ " status=%d conncap=%x"
+ " adv_id=%x adv_mac=" MACSTR
+ " session=%x mac=" MACSTR
+ " dev_passwd_id=%d go=%s",
+ MAC2STR(dev), status, conncap,
+ adv_id, MAC2STR(adv_mac),
+ ses_id, MAC2STR(ses_mac),
+ passwd_id, go_ifname);
+ return;
+ }
+
+ if (go_wpa_s && !p2p_group_go_member_count(wpa_s))
+ wpas_p2p_group_remove(wpa_s, go_wpa_s->ifname);
+
+ if (persistent_go && !persistent_go->num_p2p_clients) {
+ /* remove empty persistent GO */
+ wpa_config_remove_network(wpa_s->conf, persistent_go->id);
+ }
+
+ if (conncap == P2PS_SETUP_CLIENT) {
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_P2PS_PROVISION_DONE MACSTR
+ " status=%d conncap=%x"
+ " adv_id=%x adv_mac=" MACSTR
+ " session=%x mac=" MACSTR
+ " dev_passwd_id=%d join=" MACSTR,
+ MAC2STR(dev), status, conncap,
+ adv_id, MAC2STR(adv_mac),
+ ses_id, MAC2STR(ses_mac),
+ passwd_id, MAC2STR(grp_mac));
+ } else {
+ wpa_msg_global(wpa_s, MSG_INFO,
+ P2P_EVENT_P2PS_PROVISION_DONE MACSTR
+ " status=%d conncap=%x"
+ " adv_id=%x adv_mac=" MACSTR
+ " session=%x mac=" MACSTR
+ " dev_passwd_id=%d",
+ MAC2STR(dev), status, conncap,
+ adv_id, MAC2STR(adv_mac),
+ ses_id, MAC2STR(ses_mac),
+ passwd_id);
+ }
+}
+
+
static int _wpas_p2p_in_progress(void *ctx)
{
struct wpa_supplicant *wpa_s = ctx;
@@ -4019,6 +5028,33 @@
}
+static int wpas_prov_disc_resp_cb(void *ctx)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ struct wpa_ssid *persistent_go;
+
+ if (!wpa_s->global->pending_p2ps_group)
+ return 0;
+
+ wpa_s->global->pending_p2ps_group = 0;
+
+ if (wpas_p2p_get_go_group(wpa_s))
+ return 0;
+ persistent_go = wpas_p2p_get_persistent_go(wpa_s);
+
+ if (persistent_go) {
+ wpas_p2p_group_add_persistent(
+ wpa_s, persistent_go, 0, 0, 0, 0, 0, NULL,
+ persistent_go->mode == WPAS_MODE_P2P_GO ?
+ P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0);
+ } else {
+ wpas_p2p_group_add(wpa_s, 1, 0, 0, 0);
+ }
+
+ return 1;
+}
+
+
/**
* wpas_p2p_init - Initialize P2P module for %wpa_supplicant
* @global: Pointer to global data from wpa_supplicant_init()
@@ -4066,6 +5102,12 @@
p2p.presence_resp = wpas_presence_resp;
p2p.is_concurrent_session_active = wpas_is_concurrent_session_active;
p2p.is_p2p_in_progress = _wpas_p2p_in_progress;
+ p2p.get_persistent_group = wpas_get_persistent_group;
+ p2p.get_go_info = wpas_get_go_info;
+ p2p.remove_stale_groups = wpas_remove_stale_groups;
+ p2p.p2ps_prov_complete = wpas_p2ps_prov_complete;
+ p2p.prov_disc_resp_cb = wpas_prov_disc_resp_cb;
+ p2p.p2ps_group_capability = p2ps_group_capability;
os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN);
@@ -4485,7 +5527,7 @@
wpa_printf(MSG_DEBUG, "P2P: Auto PD with " MACSTR " join=%d",
MAC2STR(wpa_s->pending_join_dev_addr), join);
if (p2p_prov_disc_req(wpa_s->global->p2p,
- wpa_s->pending_join_dev_addr,
+ wpa_s->pending_join_dev_addr, NULL,
wpa_s->pending_pd_config_methods, join,
0, wpa_s->user_initiated_pd) < 0) {
wpa_s->p2p_auto_pd = 0;
@@ -4614,7 +5656,8 @@
}
if (p2p_prov_disc_req(wpa_s->global->p2p,
- wpa_s->pending_join_dev_addr, method, 1,
+ wpa_s->pending_join_dev_addr,
+ NULL, method, 1,
freq, wpa_s->user_initiated_pd) < 0) {
wpa_printf(MSG_DEBUG, "P2P: Failed to send Provision "
"Discovery Request before joining an "
@@ -4971,6 +6014,7 @@
wpa_s->global->add_psk = NULL;
wpa_s->global->p2p_fail_on_wps_complete = 0;
+ wpa_s->global->pending_p2ps_group = 0;
if (go_intent < 0)
go_intent = wpa_s->conf->p2p_go_intent;
@@ -5089,7 +6133,11 @@
{
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return;
- if (wpa_s->off_channel_freq == wpa_s->pending_listen_freq) {
+ wpa_printf(MSG_DEBUG, "P2P: remain-on-channel callback (off_channel_freq=%u pending_listen_freq=%d roc_waiting_drv_freq=%d freq=%u duration=%u)",
+ wpa_s->off_channel_freq, wpa_s->pending_listen_freq,
+ wpa_s->roc_waiting_drv_freq, freq, duration);
+ if (wpa_s->off_channel_freq &&
+ wpa_s->off_channel_freq == wpa_s->pending_listen_freq) {
p2p_listen_cb(wpa_s->global->p2p, wpa_s->pending_listen_freq,
wpa_s->pending_listen_duration);
wpa_s->pending_listen_freq = 0;
@@ -5841,13 +6889,25 @@
int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
const char *config_method,
- enum wpas_p2p_prov_disc_use use)
+ enum wpas_p2p_prov_disc_use use,
+ struct p2ps_provision *p2ps_prov)
{
u16 config_methods;
+ wpa_s->global->pending_p2ps_group = 0;
wpa_s->p2p_fallback_to_go_neg = 0;
wpa_s->pending_pd_use = NORMAL_PD;
- if (os_strncmp(config_method, "display", 7) == 0)
+ if (p2ps_prov && use == WPAS_P2P_PD_FOR_ASP) {
+ p2ps_prov->conncap = p2ps_group_capability(
+ wpa_s, P2PS_SETUP_NONE, p2ps_prov->role);
+ wpa_printf(MSG_DEBUG,
+ "P2P: %s conncap: %d - ASP parsed: %x %x %d %s",
+ __func__, p2ps_prov->conncap,
+ p2ps_prov->adv_id, p2ps_prov->conncap,
+ p2ps_prov->status, p2ps_prov->info);
+
+ config_methods = 0;
+ } else if (os_strncmp(config_method, "display", 7) == 0)
config_methods = WPS_CONFIG_DISPLAY;
else if (os_strncmp(config_method, "keypad", 6) == 0)
config_methods = WPS_CONFIG_KEYPAD;
@@ -5856,6 +6916,7 @@
config_methods = WPS_CONFIG_PUSHBUTTON;
else {
wpa_printf(MSG_DEBUG, "P2P: Unknown config method");
+ os_free(p2ps_prov);
return -1;
}
@@ -5876,10 +6937,12 @@
return 0;
}
- if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
+ if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled) {
+ os_free(p2ps_prov);
return -1;
+ }
- return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr,
+ return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr, p2ps_prov,
config_methods, use == WPAS_P2P_PD_FOR_JOIN,
0, 1);
}
@@ -5908,7 +6971,8 @@
int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
enum p2p_discovery_type type,
unsigned int num_req_dev_types, const u8 *req_dev_types,
- const u8 *dev_id, unsigned int search_delay)
+ const u8 *dev_id, unsigned int search_delay,
+ u8 seek_cnt, const char **seek_string)
{
wpas_p2p_clear_pending_action_tx(wpa_s);
wpa_s->p2p_long_listen = 0;
@@ -5921,7 +6985,7 @@
return p2p_find(wpa_s->global->p2p, timeout, type,
num_req_dev_types, req_dev_types, dev_id,
- search_delay);
+ search_delay, seek_cnt, seek_string);
}
@@ -5968,7 +7032,8 @@
void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
{
wpas_p2p_stop_find_oper(wpa_s);
- wpas_p2p_remove_pending_group_interface(wpa_s);
+ if (!wpa_s->global->pending_group_iface_for_p2ps)
+ wpas_p2p_remove_pending_group_interface(wpa_s);
}
@@ -8102,7 +9167,7 @@
if (cand) {
wpa_dbg(wpa_s, MSG_DEBUG,
- "P2P: Update Listen channel to %u baased on operating channel",
+ "P2P: Update Listen channel to %u based on operating channel",
cand);
p2p_set_listen_channel(wpa_s->global->p2p, 81, cand, 0);
}
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 9f5a83b..1cf1573 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -15,6 +15,7 @@
struct p2p_peer_info;
struct p2p_channels;
struct wps_event_fail;
+struct p2ps_provision;
int wpas_p2p_add_p2pdev_interface(struct wpa_supplicant *wpa_s,
const char *conf_p2p_dev);
@@ -41,11 +42,13 @@
enum wpas_p2p_prov_disc_use {
WPAS_P2P_PD_FOR_GO_NEG,
WPAS_P2P_PD_FOR_JOIN,
- WPAS_P2P_PD_AUTO
+ WPAS_P2P_PD_AUTO,
+ WPAS_P2P_PD_FOR_ASP
};
int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
const char *config_method,
- enum wpas_p2p_prov_disc_use use);
+ enum wpas_p2p_prov_disc_use use,
+ struct p2ps_provision *p2ps_prov);
void wpas_send_action_tx_status(struct wpa_supplicant *wpa_s, const u8 *dst,
const u8 *data, size_t data_len,
enum p2p_send_action_result result);
@@ -55,7 +58,8 @@
int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
enum p2p_discovery_type type,
unsigned int num_req_dev_types, const u8 *req_dev_types,
- const u8 *dev_id, unsigned int search_delay);
+ const u8 *dev_id, unsigned int search_delay,
+ u8 seek_cnt, const char **seek_string);
void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s);
int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout);
int wpas_p2p_listen_start(struct wpa_supplicant *wpa_s, unsigned int timeout);
@@ -65,6 +69,8 @@
void wpas_p2p_group_formation_failed(struct wpa_supplicant *wpa_s);
u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
const struct wpabuf *tlvs);
+u64 wpas_p2p_sd_request_asp(struct wpa_supplicant *wpa_s, const u8 *dst, u8 id,
+ const char *svc_str, const char *info_substr);
u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
u8 version, const char *query);
u64 wpas_p2p_sd_request_wifi_display(struct wpa_supplicant *wpa_s,
@@ -83,6 +89,11 @@
const char *service);
int wpas_p2p_service_del_upnp(struct wpa_supplicant *wpa_s, u8 version,
const char *service);
+int wpas_p2p_service_add_asp(struct wpa_supplicant *wpa_s, int auto_accept,
+ u32 adv_id, const char *adv_str, u8 svc_state,
+ u16 config_methods, const char *svc_info);
+int wpas_p2p_service_del_asp(struct wpa_supplicant *wpa_s, u32 adv_id);
+int wpas_p2p_service_p2ps_id_exists(struct wpa_supplicant *wpa_s, u32 adv_id);
int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr);
int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 0653cc2..c1f3efc 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -1594,11 +1594,12 @@
*/
#define GREAT_SNR 30
+#define IS_5GHZ(n) (n > 4000)
+
/* Compare function for sorting scan results. Return >0 if @b is considered
* better. */
static int wpa_scan_result_compar(const void *a, const void *b)
{
-#define IS_5GHZ(n) (n > 4000)
#define MIN(a,b) a < b ? a : b
struct wpa_scan_res **_wa = (void *) a;
struct wpa_scan_res **_wb = (void *) b;
@@ -1626,18 +1627,18 @@
(wb->caps & IEEE80211_CAP_PRIVACY) == 0)
return -1;
- if ((wa->flags & wb->flags & WPA_SCAN_LEVEL_DBM) &&
- !((wa->flags | wb->flags) & WPA_SCAN_NOISE_INVALID)) {
+ if (wa->flags & wb->flags & WPA_SCAN_LEVEL_DBM) {
snr_a = MIN(wa->level - wa->noise, GREAT_SNR);
snr_b = MIN(wb->level - wb->noise, GREAT_SNR);
} else {
- /* Not suitable information to calculate SNR, so use level */
+ /* Level is not in dBm, so we can't calculate
+ * SNR. Just use raw level (units unknown). */
snr_a = wa->level;
snr_b = wb->level;
}
- /* best/max rate preferred if SNR close enough */
- if ((snr_a && snr_b && abs(snr_b - snr_a) < 5) ||
+ /* if SNR is close, decide by max rate or frequency band */
+ if ((snr_a && snr_b && abs(snr_b - snr_a) < 5) ||
(wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) {
maxrate_a = wpa_scan_get_max_rate(wa);
maxrate_b = wpa_scan_get_max_rate(wb);
@@ -1647,8 +1648,6 @@
return IS_5GHZ(wa->freq) ? -1 : 1;
}
- /* use freq for channel preference */
-
/* all things being equal, use SNR; if SNRs are
* identical, use quality values since some drivers may only report
* that value and leave the signal level zero */
@@ -1656,7 +1655,6 @@
return wb->qual - wa->qual;
return snr_b - snr_a;
#undef MIN
-#undef IS_5GHZ
}
@@ -1721,15 +1719,15 @@
for (i = 0; i < scan_res->num; i++) {
struct wpa_scan_res *r = scan_res->res[i];
u8 *pos;
- if ((r->flags & (WPA_SCAN_LEVEL_DBM | WPA_SCAN_NOISE_INVALID))
- == WPA_SCAN_LEVEL_DBM) {
+ if (r->flags & WPA_SCAN_LEVEL_DBM) {
int snr = r->level - r->noise;
+ int noise_valid = !(r->flags & WPA_SCAN_NOISE_INVALID);
+
wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d "
- "noise=%d level=%d snr=%d%s flags=0x%x "
- "age=%u",
+ "noise=%d%s level=%d snr=%d%s flags=0x%x age=%u",
MAC2STR(r->bssid), r->freq, r->qual,
- r->noise, r->level, snr,
- snr >= GREAT_SNR ? "*" : "", r->flags,
+ r->noise, noise_valid ? "" : "~", r->level,
+ snr, snr >= GREAT_SNR ? "*" : "", r->flags,
r->age);
} else {
wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d "
@@ -1802,6 +1800,14 @@
}
+/*
+ * Noise floor values to use when we have signal strength
+ * measurements, but no noise floor measurments. These values were
+ * measured in an office environment with many APs.
+ */
+#define DEFAULT_NOISE_FLOOR_2GHZ (-89)
+#define DEFAULT_NOISE_FLOOR_5GHZ (-92)
+
/**
* wpa_supplicant_get_scan_results - Get scan results
* @wpa_s: Pointer to wpa_supplicant data
@@ -1835,6 +1841,17 @@
}
filter_scan_res(wpa_s, scan_res);
+ for (i = 0; i < scan_res->num; i++) {
+ struct wpa_scan_res *scan_res_item = scan_res->res[i];
+
+ if (scan_res_item->flags & WPA_SCAN_NOISE_INVALID) {
+ scan_res_item->noise =
+ IS_5GHZ(scan_res_item->freq) ?
+ DEFAULT_NOISE_FLOOR_5GHZ :
+ DEFAULT_NOISE_FLOOR_2GHZ;
+ }
+ }
+
#ifdef CONFIG_WPS
if (wpas_wps_searching(wpa_s)) {
wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Order scan results with WPS "
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index c2b0990..6c05707 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -297,7 +297,7 @@
if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
wpa_s->current_ssid,
try_opportunistic) == 0)
- eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
+ eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
wpa_s->sme.assoc_req_ie,
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 911effe..2f06c35 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1825,6 +1825,20 @@
}
+static int wpa_cli_cmd_p2p_asp_provision(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "P2P_ASP_PROVISION", 3, argc, argv);
+}
+
+
+static int wpa_cli_cmd_p2p_asp_provision_resp(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "P2P_ASP_PROVISION_RESP", 2, argc, argv);
+}
+
+
static int wpa_cli_cmd_p2p_connect(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
@@ -1909,11 +1923,9 @@
{
char cmd[4096];
- if (argc != 2 && argc != 4) {
+ if (argc < 2) {
printf("Invalid P2P_SERV_DISC_REQ command: needs two "
- "arguments (address and TLVs) or four arguments "
- "(address, \"upnp\", version, search target "
- "(SSDP ST:)\n");
+ "or more arguments (address and TLVs)\n");
return -1;
}
@@ -1975,27 +1987,25 @@
static int wpa_cli_cmd_p2p_service_add(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[4096];
- int res;
+ if (argc < 3) {
+ printf("Invalid P2P_SERVICE_ADD command: needs 3-6 arguments\n");
+ return -1;
+ }
- if (argc != 3 && argc != 4) {
- printf("Invalid P2P_SERVICE_ADD command: needs three or four "
+ return wpa_cli_cmd(ctrl, "P2P_SERVICE_ADD", 3, argc, argv);
+}
+
+
+static int wpa_cli_cmd_p2p_service_rep(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ if (argc < 5 || argc > 6) {
+ printf("Invalid P2P_SERVICE_REP command: needs 5-6 "
"arguments\n");
return -1;
}
- if (argc == 4)
- res = os_snprintf(cmd, sizeof(cmd),
- "P2P_SERVICE_ADD %s %s %s %s",
- argv[0], argv[1], argv[2], argv[3]);
- else
- res = os_snprintf(cmd, sizeof(cmd),
- "P2P_SERVICE_ADD %s %s %s",
- argv[0], argv[1], argv[2]);
- if (os_snprintf_error(sizeof(cmd), res))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_SERVICE_REP", 5, argc, argv);
}
@@ -2882,6 +2892,12 @@
"[timeout] [type=*] = find P2P Devices for up-to timeout seconds" },
{ "p2p_stop_find", wpa_cli_cmd_p2p_stop_find, NULL, cli_cmd_flag_none,
"= stop P2P Devices search" },
+ { "p2p_asp_provision", wpa_cli_cmd_p2p_asp_provision, NULL,
+ cli_cmd_flag_none,
+ "<addr> adv_id=<adv_id> conncap=<conncap> [info=<infodata>] = provision with a P2P ASP Device" },
+ { "p2p_asp_provision_resp", wpa_cli_cmd_p2p_asp_provision_resp, NULL,
+ cli_cmd_flag_none,
+ "<addr> adv_id=<adv_id> [role<conncap>] [info=<infodata>] = provision with a P2P ASP Device" },
{ "p2p_connect", wpa_cli_cmd_p2p_connect, wpa_cli_complete_p2p_connect,
cli_cmd_flag_none,
"<addr> <\"pbc\"|PIN> [ht40] = connect to a P2P Device" },
@@ -2918,8 +2934,12 @@
"= remove all stored service entries" },
{ "p2p_service_add", wpa_cli_cmd_p2p_service_add, NULL,
cli_cmd_flag_none,
- "<bonjour|upnp> <query|version> <response|service> = add a local "
+ "<bonjour|upnp|asp> <query|version> <response|service> = add a local "
"service" },
+ { "p2p_service_rep", wpa_cli_cmd_p2p_service_rep, NULL,
+ cli_cmd_flag_none,
+ "asp <auto> <adv_id> <svc_state> <svc_string> [<svc_info>] = replace "
+ "local ASP service" },
{ "p2p_service_del", wpa_cli_cmd_p2p_service_del, NULL,
cli_cmd_flag_none,
"<bonjour|upnp> <query|version> [|service] = remove a local "
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 434847d..6ad09a8 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1906,7 +1906,7 @@
(ssid->proto & WPA_PROTO_RSN);
if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
ssid, try_opportunistic) == 0)
- eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
+ eapol_sm_notify_pmkid_attempt(wpa_s->eapol);
wpa_ie_len = sizeof(wpa_ie);
if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
wpa_ie, &wpa_ie_len)) {
@@ -3086,11 +3086,9 @@
if (wpa_s->bridge_ifname[0]) {
wpa_dbg(wpa_s, MSG_DEBUG, "Receiving packets from bridge "
"interface '%s'", wpa_s->bridge_ifname);
- wpa_s->l2_br = l2_packet_init(wpa_s->bridge_ifname,
- wpa_s->own_addr,
- ETH_P_EAPOL,
- wpa_supplicant_rx_eapol_bridge,
- wpa_s, 1);
+ wpa_s->l2_br = l2_packet_init_bridge(
+ wpa_s->bridge_ifname, wpa_s->ifname, wpa_s->own_addr,
+ ETH_P_EAPOL, wpa_supplicant_rx_eapol_bridge, wpa_s, 1);
if (wpa_s->l2_br == NULL) {
wpa_msg(wpa_s, MSG_ERROR, "Failed to open l2_packet "
"connection for the bridge interface '%s'",
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 23c2299..8964b3f 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -940,9 +940,20 @@
# * 2 = require cryptobinding
# EAP-WSC (WPS) uses following options: pin=<Device Password> or
# pbc=1.
+#
+# For wired IEEE 802.1X authentication, "allow_canned_success=1" can be
+# used to configure a mode that allows EAP-Success (and EAP-Failure)
+# without going through authentication step. Some switches use such
+# sequence when forcing the port to be authorized/unauthorized or as a
+# fallback option if the authentication server is unreachable. By default,
+# wpa_supplicant discards such frames to protect against potential attacks
+# by rogue devices, but this option can be used to disable that protection
+# for cases where the server/authenticator does not need to be
+# authenticated.
# phase2: Phase2 (inner authentication with TLS tunnel) parameters
# (string with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or
-# "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS)
+# "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS). "mschapv2_retry=0" can be
+# used to disable MSCHAPv2 password retry in authentication failure cases.
#
# TLS-based methods can use the following parameters to control TLS behavior
# (these are normally in the phase1 parameter, but can be used also in the
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 7d22000..c80a620 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -275,6 +275,8 @@
unsigned int p2p_per_sta_psk:1;
unsigned int p2p_fail_on_wps_complete:1;
unsigned int p2p_24ghz_social_channels:1;
+ unsigned int pending_p2ps_group:1;
+ unsigned int pending_group_iface_for_p2ps:1;
#ifdef CONFIG_WIFI_DISPLAY
int wifi_display;
@@ -771,7 +773,7 @@
int force_long_sd;
u16 pending_pd_config_methods;
enum {
- NORMAL_PD, AUTO_PD_GO_NEG, AUTO_PD_JOIN
+ NORMAL_PD, AUTO_PD_GO_NEG, AUTO_PD_JOIN, AUTO_PD_ASP
} pending_pd_use;
/*
@@ -810,6 +812,7 @@
unsigned int p2p_nfc_tag_enabled:1;
unsigned int p2p_peer_oob_pk_hash_known:1;
unsigned int p2p_disable_ip_addr_req:1;
+ unsigned int p2ps_join_addr_valid:1;
int p2p_persistent_go_freq;
int p2p_persistent_id;
int p2p_go_intent;
@@ -829,6 +832,7 @@
/* group common frequencies */
int *p2p_group_common_freqs;
unsigned int p2p_group_common_freqs_num;
+ u8 p2ps_join_addr[ETH_ALEN];
#endif /* CONFIG_P2P */
struct wpa_ssid *bgscan_ssid;