1d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt/*
2d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt * Hotspot 2.0 SPP client
36cb1f6521a84955752c2b99100cf1df87637f86cDmitry Shmidt * Copyright (c) 2012-2014, Qualcomm Atheros, Inc.
4d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt *
5d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt * This software may be distributed under the terms of the BSD license.
6d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt * See README for more details.
7d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt */
8d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
9d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt#include "includes.h"
10d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt#include <sys/stat.h>
11d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
12d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt#include "common.h"
13d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt#include "browser.h"
14d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt#include "wpa_ctrl.h"
15d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt#include "wpa_helpers.h"
16d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt#include "xml-utils.h"
17d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt#include "http-utils.h"
18d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt#include "utils/base64.h"
19d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt#include "crypto/crypto.h"
20d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt#include "crypto/sha256.h"
21d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt#include "osu_client.h"
22d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
23d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
24af9da3180dc20f57df1fc1e1811f3df9fa9e6ab5Dmitry Shmidtextern const char *spp_xsd_fname;
25af9da3180dc20f57df1fc1e1811f3df9fa9e6ab5Dmitry Shmidt
26d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidtstatic int hs20_spp_update_response(struct hs20_osu_client *ctx,
27d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt				    const char *session_id,
28d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt				    const char *spp_status,
29d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt				    const char *error_code);
30d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidtstatic void hs20_policy_update_complete(
31d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	struct hs20_osu_client *ctx, const char *pps_fname);
32d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
33d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
34d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidtstatic char * get_spp_attr_value(struct xml_node_ctx *ctx, xml_node_t *node,
35d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt				 char *attr_name)
36d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt{
37d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	return xml_node_get_attr_value_ns(ctx, node, SPP_NS_URI, attr_name);
38d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt}
39d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
40d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
41d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidtstatic int hs20_spp_validate(struct hs20_osu_client *ctx, xml_node_t *node,
42d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			     const char *expected_name)
43d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt{
44d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	struct xml_node_ctx *xctx = ctx->xml;
45d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	const char *name;
46d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	char *err;
47d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	int ret;
48d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
49d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (!xml_node_is_element(xctx, node))
50d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
51d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
52d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	name = xml_node_get_localname(xctx, node);
53d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (name == NULL)
54d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
55d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
56d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (strcmp(expected_name, name) != 0) {
57d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "Unexpected SOAP method name '%s' (expected '%s')",
58d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			   name, expected_name);
59d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		write_summary(ctx, "Unexpected SOAP method name '%s' (expected '%s')",
60d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			      name, expected_name);
61d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
62d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
63d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
64af9da3180dc20f57df1fc1e1811f3df9fa9e6ab5Dmitry Shmidt	ret = xml_validate(xctx, node, spp_xsd_fname, &err);
65d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (ret < 0) {
66d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "XML schema validation error(s)\n%s", err);
67d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		write_summary(ctx, "SPP XML schema validation failed");
68d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		os_free(err);
69d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
70d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	return ret;
71d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt}
72d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
73d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
74d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidtstatic void add_mo_container(struct xml_node_ctx *ctx, xml_namespace_t *ns,
75d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			     xml_node_t *parent, const char *urn,
76d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			     const char *fname)
77d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt{
78d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_t *node;
79d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_t *fnode, *tnds;
80d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	char *str;
81d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
82b1e52102c211357f585e9ff6d54501e90254326eDmitry Shmidt	errno = 0;
83d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	fnode = node_from_file(ctx, fname);
84b1e52102c211357f585e9ff6d54501e90254326eDmitry Shmidt	if (!fnode) {
85b1e52102c211357f585e9ff6d54501e90254326eDmitry Shmidt		wpa_printf(MSG_ERROR,
86b1e52102c211357f585e9ff6d54501e90254326eDmitry Shmidt			   "Failed to create XML node from file: %s, possible error: %s",
87b1e52102c211357f585e9ff6d54501e90254326eDmitry Shmidt			   fname, strerror(errno));
88d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return;
89b1e52102c211357f585e9ff6d54501e90254326eDmitry Shmidt	}
90d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	tnds = mo_to_tnds(ctx, fnode, 0, urn, "syncml:dmddf1.2");
91d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_free(ctx, fnode);
92d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (!tnds)
93d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return;
94d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
95d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	str = xml_node_to_str(ctx, tnds);
96d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_free(ctx, tnds);
97d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (str == NULL)
98d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return;
99d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
100d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	node = xml_node_create_text(ctx, parent, ns, "moContainer", str);
101d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (node)
102d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_add_attr(ctx, node, ns, "moURN", urn);
103d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	os_free(str);
104d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt}
105d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
106d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
107d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidtstatic xml_node_t * build_spp_post_dev_data(struct hs20_osu_client *ctx,
108d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt					    xml_namespace_t **ret_ns,
109d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt					    const char *session_id,
110d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt					    const char *reason)
111d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt{
112d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_namespace_t *ns;
113d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_t *spp_node;
114d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
115d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	write_summary(ctx, "Building sppPostDevData requestReason='%s'",
116d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		      reason);
117d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
118d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt					"sppPostDevData");
119d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (spp_node == NULL)
120d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return NULL;
121d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (ret_ns)
122d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		*ret_ns = ns;
123d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
124d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
125d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_add_attr(ctx->xml, spp_node, NULL, "requestReason", reason);
126d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (session_id)
127d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID",
128d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt				  session_id);
129d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_add_attr(ctx->xml, spp_node, NULL, "redirectURI",
130d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			  "http://localhost:12345/");
131d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
132d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_create_text(ctx->xml, spp_node, ns, "supportedSPPVersions",
133d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			     "1.0");
134d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_create_text(ctx->xml, spp_node, ns, "supportedMOList",
135d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			     URN_HS20_PPS " " URN_OMA_DM_DEVINFO " "
136d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			     URN_OMA_DM_DEVDETAIL " " URN_HS20_DEVDETAIL_EXT);
137d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
138d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	add_mo_container(ctx->xml, ns, spp_node, URN_OMA_DM_DEVINFO,
139d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			 "devinfo.xml");
140d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	add_mo_container(ctx->xml, ns, spp_node, URN_OMA_DM_DEVDETAIL,
141d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			 "devdetail.xml");
142d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
143d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	return spp_node;
144d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt}
145d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
146d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
147d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidtstatic int process_update_node(struct hs20_osu_client *ctx, xml_node_t *pps,
148d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			       xml_node_t *update)
149d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt{
150d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_t *node, *parent, *tnds, *unode;
151d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	char *str;
152d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	const char *name;
153d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	char *uri, *pos;
154d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	char *cdata, *cdata_end;
155d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	size_t fqdn_len;
156d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
157d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	wpa_printf(MSG_INFO, "Processing updateNode");
158d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	debug_dump_node(ctx, "updateNode", update);
159d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
160d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	uri = get_spp_attr_value(ctx->xml, update, "managementTreeURI");
161d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (uri == NULL) {
162d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "No managementTreeURI present");
163d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
164d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
165d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	wpa_printf(MSG_INFO, "managementTreeUri: '%s'", uri);
166d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
167d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	name = os_strrchr(uri, '/');
168d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (name == NULL) {
169d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "Unexpected URI");
170d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_get_attr_value_free(ctx->xml, uri);
171d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
172d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
173d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	name++;
174d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	wpa_printf(MSG_INFO, "Update interior node: '%s'", name);
175d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
176d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	str = xml_node_get_text(ctx->xml, update);
177d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (str == NULL) {
178d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "Could not extract MO text");
179d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_get_attr_value_free(ctx->xml, uri);
180d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
181d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
182d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	wpa_printf(MSG_DEBUG, "[hs20] nodeContainer text: '%s'", str);
183d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	cdata = strstr(str, "<![CDATA[");
184d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	cdata_end = strstr(str, "]]>");
185d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (cdata && cdata_end && cdata_end > cdata &&
186d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	    cdata < strstr(str, "MgmtTree") &&
187d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	    cdata_end > strstr(str, "/MgmtTree")) {
188d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		char *tmp;
189d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_DEBUG, "[hs20] Removing extra CDATA container");
190d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		tmp = strdup(cdata + 9);
191d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (tmp) {
192d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			cdata_end = strstr(tmp, "]]>");
193d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			if (cdata_end)
194d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt				*cdata_end = '\0';
195d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			wpa_printf(MSG_DEBUG, "[hs20] nodeContainer text with CDATA container removed: '%s'",
196d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt				   tmp);
197d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			tnds = xml_node_from_buf(ctx->xml, tmp);
198d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			free(tmp);
199d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		} else
200d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			tnds = NULL;
201d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	} else
202d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		tnds = xml_node_from_buf(ctx->xml, str);
203d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_get_text_free(ctx->xml, str);
204d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (tnds == NULL) {
205d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "[hs20] Could not parse nodeContainer text");
206d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_get_attr_value_free(ctx->xml, uri);
207d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
208d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
209d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
210d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	unode = tnds_to_mo(ctx->xml, tnds);
211d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_free(ctx->xml, tnds);
212d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (unode == NULL) {
213d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "[hs20] Could not parse nodeContainer TNDS text");
214d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_get_attr_value_free(ctx->xml, uri);
215d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
216d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
217d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
218d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	debug_dump_node(ctx, "Parsed TNDS", unode);
219d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
220d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (get_node_uri(ctx->xml, unode, name) == NULL) {
221d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "[hs20] %s node not found", name);
222d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_free(ctx->xml, unode);
223d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_get_attr_value_free(ctx->xml, uri);
224d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
225d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
226d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
227d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (os_strncasecmp(uri, "./Wi-Fi/", 8) != 0) {
228d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi");
229d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_free(ctx->xml, unode);
230d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_get_attr_value_free(ctx->xml, uri);
231d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
232d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
233d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	pos = uri + 8;
234d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
235d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (ctx->fqdn == NULL) {
236d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "FQDN not known");
237d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_free(ctx->xml, unode);
238d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_get_attr_value_free(ctx->xml, uri);
239d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
240d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
241d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	fqdn_len = os_strlen(ctx->fqdn);
242d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
243d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	    pos[fqdn_len] != '/') {
244d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi/%s",
245d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			   ctx->fqdn);
246d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_free(ctx->xml, unode);
247d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_get_attr_value_free(ctx->xml, uri);
248d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
249d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
250d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	pos += fqdn_len + 1;
251d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
252d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
253d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi/%s/PerProviderSubscription",
254d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			   ctx->fqdn);
255d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_free(ctx->xml, unode);
256d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_get_attr_value_free(ctx->xml, uri);
257d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
258d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
259d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	pos += 24;
260d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
261d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	wpa_printf(MSG_INFO, "Update command for PPS node %s", pos);
262d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
263d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	node = get_node(ctx->xml, pps, pos);
264d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (node) {
265d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		parent = xml_node_get_parent(ctx->xml, node);
266d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_detach(ctx->xml, node);
267d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "Replace '%s' node", name);
268d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	} else {
269d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		char *pos2;
270d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		pos2 = os_strrchr(pos, '/');
271d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (pos2 == NULL) {
272d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			parent = pps;
273d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		} else {
274d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			*pos2 = '\0';
275d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			parent = get_node(ctx->xml, pps, pos);
276d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		}
277d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (parent == NULL) {
278d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			wpa_printf(MSG_INFO, "Could not find parent %s", pos);
279d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			xml_node_free(ctx->xml, unode);
280d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			xml_node_get_attr_value_free(ctx->xml, uri);
281d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			return -1;
282d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		}
283d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "Add '%s' node", name);
284d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
285d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_add_child(ctx->xml, parent, unode);
286d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
287d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_get_attr_value_free(ctx->xml, uri);
288d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
289d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	return 0;
290d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt}
291d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
292d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
293d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidtstatic int update_pps(struct hs20_osu_client *ctx, xml_node_t *update,
294d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		      const char *pps_fname, xml_node_t *pps)
295d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt{
296d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	wpa_printf(MSG_INFO, "Updating PPS based on updateNode element(s)");
297d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_for_each_sibling(ctx->xml, update) {
298d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_for_each_check(ctx->xml, update);
299d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (process_update_node(ctx, pps, update) < 0)
300d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			return -1;
301d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
302d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
303d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	return update_pps_file(ctx, pps_fname, pps);
304d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt}
305d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
306d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
307d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidtstatic void hs20_sub_rem_complete(struct hs20_osu_client *ctx,
308d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt				  const char *pps_fname)
309d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt{
310d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	/*
311d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	 * Update wpa_supplicant credentials and reconnect using updated
312d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	 * information.
313d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	 */
314d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
315d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	cmd_set_pps(ctx, pps_fname);
316d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
317d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (ctx->no_reconnect)
318d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return;
319d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
320d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
321d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0)
322d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_ERROR, "Failed to request wpa_supplicant to reconnect");
323d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt}
324d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
325d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
326d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidtstatic xml_node_t * hs20_spp_upload_mo(struct hs20_osu_client *ctx,
327d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt				       xml_node_t *cmd,
328d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt				       const char *session_id,
329d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt				       const char *pps_fname)
330d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt{
331d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_namespace_t *ns;
332d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_t *node, *ret_node;
333d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	char *urn;
334d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
335d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	urn = get_spp_attr_value(ctx->xml, cmd, "moURN");
336d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (!urn) {
337d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "No URN included");
338d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return NULL;
339d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
340d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	wpa_printf(MSG_INFO, "Upload MO request - URN=%s", urn);
341d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (strcasecmp(urn, URN_HS20_PPS) != 0) {
342d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "Unsupported moURN");
343d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_get_attr_value_free(ctx->xml, urn);
344d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return NULL;
345d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
346d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_get_attr_value_free(ctx->xml, urn);
347d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
348d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (!pps_fname) {
349d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "PPS file name no known");
350d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return NULL;
351d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
352d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
353d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	node = build_spp_post_dev_data(ctx, &ns, session_id,
354d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt				       "MO upload");
355d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (node == NULL)
356d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return NULL;
357d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	add_mo_container(ctx->xml, ns, node, URN_HS20_PPS, pps_fname);
358d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
359d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	ret_node = soap_send_receive(ctx->http, node);
360d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (ret_node == NULL)
361d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return NULL;
362d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
363d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	debug_dump_node(ctx, "Received response to MO upload", ret_node);
364d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
365d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
366d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "SPP validation failed");
367d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_free(ctx->xml, ret_node);
368d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return NULL;
369d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
370d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
371d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	return ret_node;
372d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt}
373d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
374d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
375d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidtstatic int hs20_add_mo(struct hs20_osu_client *ctx, xml_node_t *add_mo,
376d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		       char *fname, size_t fname_len)
377d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt{
378d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	char *uri, *urn;
379d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	int ret;
380d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
381d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	debug_dump_node(ctx, "Received addMO", add_mo);
382d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
383d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	urn = get_spp_attr_value(ctx->xml, add_mo, "moURN");
384d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (urn == NULL) {
385d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "[hs20] No moURN in addMO");
386d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
387d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
388d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	wpa_printf(MSG_INFO, "addMO - moURN: '%s'", urn);
389d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (strcasecmp(urn, URN_HS20_PPS) != 0) {
390d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "[hs20] Unsupported MO in addMO");
391d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_get_attr_value_free(ctx->xml, urn);
392d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
393d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
394d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_get_attr_value_free(ctx->xml, urn);
395d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
396d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	uri = get_spp_attr_value(ctx->xml, add_mo, "managementTreeURI");
397d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (uri == NULL) {
398d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "[hs20] No managementTreeURI in addMO");
399d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
400d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
401d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	wpa_printf(MSG_INFO, "addMO - managementTreeURI: '%s'", uri);
402d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
403d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	ret = hs20_add_pps_mo(ctx, uri, add_mo, fname, fname_len);
404d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_get_attr_value_free(ctx->xml, uri);
405d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	return ret;
406d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt}
407d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
408d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
409d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidtstatic int process_spp_user_input_response(struct hs20_osu_client *ctx,
410d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt					   const char *session_id,
411d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt					   xml_node_t *add_mo)
412d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt{
413d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	int ret;
414d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	char fname[300];
415d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
416d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	debug_dump_node(ctx, "addMO", add_mo);
417d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
418d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	wpa_printf(MSG_INFO, "Subscription registration completed");
419d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
420d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (hs20_add_mo(ctx, add_mo, fname, sizeof(fname)) < 0) {
421d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "Could not add MO");
422d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		ret = hs20_spp_update_response(
423d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			ctx, session_id,
424d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			"Error occurred",
425d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			"MO addition or update failed");
426d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return 0;
427d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
428d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
429d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	ret = hs20_spp_update_response(ctx, session_id, "OK", NULL);
430d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (ret == 0)
431d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		hs20_sub_rem_complete(ctx, fname);
432d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
433d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	return 0;
434d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt}
435d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
436d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
437d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidtstatic xml_node_t * hs20_spp_user_input_completed(struct hs20_osu_client *ctx,
438d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt						    const char *session_id)
439d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt{
440d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_t *node, *ret_node;
441d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
442d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	node = build_spp_post_dev_data(ctx, NULL, session_id,
443d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt				       "User input completed");
444d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (node == NULL)
445d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return NULL;
446d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
447d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	ret_node = soap_send_receive(ctx->http, node);
448d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (!ret_node) {
449d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (soap_reinit_client(ctx->http) < 0)
450d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			return NULL;
451d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "Try to finish with re-opened connection");
452d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		node = build_spp_post_dev_data(ctx, NULL, session_id,
453d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt					       "User input completed");
454d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (node == NULL)
455d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			return NULL;
456d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		ret_node = soap_send_receive(ctx->http, node);
457d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (ret_node == NULL)
458d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			return NULL;
459d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "Continue with new connection");
460d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
461d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
462d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
463d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "SPP validation failed");
464d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_free(ctx->xml, ret_node);
465d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return NULL;
466d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
467d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
468d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	return ret_node;
469d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt}
470d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
471d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
472d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidtstatic xml_node_t * hs20_spp_get_certificate(struct hs20_osu_client *ctx,
473d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt					     xml_node_t *cmd,
474d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt					     const char *session_id,
475d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt					     const char *pps_fname)
476d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt{
477d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_namespace_t *ns;
478d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_t *node, *ret_node;
479d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	int res;
480d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
481d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	wpa_printf(MSG_INFO, "Client certificate enrollment");
482d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
483d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	res = osu_get_certificate(ctx, cmd);
484d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (res < 0)
485d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "EST simpleEnroll failed");
486d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
487d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	node = build_spp_post_dev_data(ctx, &ns, session_id,
488d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt				       res == 0 ?
489d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt				       "Certificate enrollment completed" :
490d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt				       "Certificate enrollment failed");
491d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (node == NULL)
492d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return NULL;
493d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
494d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	ret_node = soap_send_receive(ctx->http, node);
495d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (ret_node == NULL)
496d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return NULL;
497d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
498d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	debug_dump_node(ctx, "Received response to certificate enrollment "
499d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			"completed", ret_node);
500d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
501d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
502d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "SPP validation failed");
503d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_free(ctx->xml, ret_node);
504d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return NULL;
505d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
506d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
507d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	return ret_node;
508d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt}
509d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
510d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
511d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidtstatic int hs20_spp_exec(struct hs20_osu_client *ctx, xml_node_t *exec,
512d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			 const char *session_id, const char *pps_fname,
513d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			 xml_node_t *pps, xml_node_t **ret_node)
514d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt{
515d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_t *cmd;
516d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	const char *name;
517d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	char *uri;
518d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	char *id = strdup(session_id);
519d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
520d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (id == NULL)
521d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
522d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
523d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	*ret_node = NULL;
524d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
525d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	debug_dump_node(ctx, "exec", exec);
526d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
527d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_for_each_child(ctx->xml, cmd, exec) {
528d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_for_each_check(ctx->xml, cmd);
529d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		break;
530d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
531d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (!cmd) {
532d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "exec command element not found (cmd=%p)",
533d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			   cmd);
534d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		free(id);
535d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
536d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
537d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
538d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	name = xml_node_get_localname(ctx->xml, cmd);
539d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
540d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (strcasecmp(name, "launchBrowserToURI") == 0) {
541d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		int res;
542d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		uri = xml_node_get_text(ctx->xml, cmd);
543d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (!uri) {
544d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			wpa_printf(MSG_INFO, "No URI found");
545d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			free(id);
546d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			return -1;
547d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		}
548d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "Launch browser to URI '%s'", uri);
549d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		write_summary(ctx, "Launch browser to URI '%s'", uri);
550d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		res = hs20_web_browser(uri);
551d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_get_text_free(ctx->xml, uri);
552d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (res > 0) {
553d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			wpa_printf(MSG_INFO, "User response in browser completed successfully - sessionid='%s'",
554d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt				   id);
555d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			write_summary(ctx, "User response in browser completed successfully");
556d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			*ret_node = hs20_spp_user_input_completed(ctx, id);
557d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			free(id);
558d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			return *ret_node ? 0 : -1;
559d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		} else {
560d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			wpa_printf(MSG_INFO, "Failed to receive user response");
561d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			write_summary(ctx, "Failed to receive user response");
562d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			hs20_spp_update_response(
563d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt				ctx, id, "Error occurred", "Other");
564d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			free(id);
565d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			return -1;
566d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		}
567d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return 0;
568d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
569d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
570d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (strcasecmp(name, "uploadMO") == 0) {
571d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (pps_fname == NULL)
572d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			return -1;
573d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		*ret_node = hs20_spp_upload_mo(ctx, cmd, id,
574d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt					       pps_fname);
575d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		free(id);
576d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return *ret_node ? 0 : -1;
577d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
578d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
579d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (strcasecmp(name, "getCertificate") == 0) {
580d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		*ret_node = hs20_spp_get_certificate(ctx, cmd, id,
581d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt						     pps_fname);
582d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		free(id);
583d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return *ret_node ? 0 : -1;
584d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
585d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
586d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	wpa_printf(MSG_INFO, "Unsupported exec command: '%s'", name);
587d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	free(id);
588d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	return -1;
589d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt}
590d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
591d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
592d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidtenum spp_post_dev_data_use {
593d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	SPP_SUBSCRIPTION_REMEDIATION,
594d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	SPP_POLICY_UPDATE,
595d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	SPP_SUBSCRIPTION_REGISTRATION,
596d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt};
597d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
598d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidtstatic void process_spp_post_dev_data_response(
599d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	struct hs20_osu_client *ctx,
600d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	enum spp_post_dev_data_use use, xml_node_t *node,
601d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	const char *pps_fname, xml_node_t *pps)
602d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt{
603d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_t *child;
604d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	char *status = NULL;
605d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_t *update = NULL, *exec = NULL, *add_mo = NULL, *no_mo = NULL;
606d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	char *session_id = NULL;
607d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
608d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	debug_dump_node(ctx, "sppPostDevDataResponse node", node);
609d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
610d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	status = get_spp_attr_value(ctx->xml, node, "sppStatus");
611d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (status == NULL) {
612d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "No sppStatus attribute");
613d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		goto out;
614d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
615d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	write_summary(ctx, "Received sppPostDevDataResponse sppStatus='%s'",
616d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		      status);
617d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
618d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	session_id = get_spp_attr_value(ctx->xml, node, "sessionID");
619d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (session_id == NULL) {
620d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "No sessionID attribute");
621d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		goto out;
622d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
623d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
624d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	wpa_printf(MSG_INFO, "[hs20] sppPostDevDataResponse - sppStatus: '%s'  sessionID: '%s'",
625d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		   status, session_id);
626d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
627d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_for_each_child(ctx->xml, child, node) {
628d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		const char *name;
629d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_for_each_check(ctx->xml, child);
630d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		debug_dump_node(ctx, "child", child);
631d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		name = xml_node_get_localname(ctx->xml, child);
632d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "localname: '%s'", name);
633d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (!update && strcasecmp(name, "updateNode") == 0)
634d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			update = child;
635d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (!exec && strcasecmp(name, "exec") == 0)
636d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			exec = child;
637d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (!add_mo && strcasecmp(name, "addMO") == 0)
638d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			add_mo = child;
639d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (!no_mo && strcasecmp(name, "noMOUpdate") == 0)
640d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			no_mo = child;
641d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
642d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
643d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (use == SPP_SUBSCRIPTION_REMEDIATION &&
644d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	    strcasecmp(status,
645d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		       "Remediation complete, request sppUpdateResponse") == 0)
646d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	{
647d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		int res, ret;
648d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (!update && !no_mo) {
649d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			wpa_printf(MSG_INFO, "No updateNode or noMOUpdate element");
650d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			goto out;
651d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		}
652d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "Subscription remediation completed");
653d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		res = update_pps(ctx, update, pps_fname, pps);
654d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (res < 0)
655d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			wpa_printf(MSG_INFO, "Failed to update PPS MO");
656d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		ret = hs20_spp_update_response(
657d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			ctx, session_id,
658d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			res < 0 ? "Error occurred" : "OK",
659d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			res < 0 ? "MO addition or update failed" : NULL);
660d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (res == 0 && ret == 0)
661d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			hs20_sub_rem_complete(ctx, pps_fname);
662d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		goto out;
663d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
664d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
665d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (use == SPP_SUBSCRIPTION_REMEDIATION &&
666d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	    strcasecmp(status, "Exchange complete, release TLS connection") ==
667d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	    0) {
668d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (!no_mo) {
669d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			wpa_printf(MSG_INFO, "No noMOUpdate element");
670d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			goto out;
671d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		}
672d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "Subscription remediation completed (no MO update)");
673d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		goto out;
674d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
675d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
676d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (use == SPP_POLICY_UPDATE &&
677d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	    strcasecmp(status, "Update complete, request sppUpdateResponse") ==
678d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	    0) {
679d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		int res, ret;
680d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "Policy update received - update PPS");
681d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		res = update_pps(ctx, update, pps_fname, pps);
682d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		ret = hs20_spp_update_response(
683d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			ctx, session_id,
684d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			res < 0 ? "Error occurred" : "OK",
685d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			res < 0 ? "MO addition or update failed" : NULL);
686d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (res == 0 && ret == 0)
687d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			hs20_policy_update_complete(ctx, pps_fname);
688d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		goto out;
689d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
690d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
691d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (use == SPP_SUBSCRIPTION_REGISTRATION &&
692d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	    strcasecmp(status, "Provisioning complete, request "
693d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		       "sppUpdateResponse")  == 0) {
694d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (!add_mo) {
695d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			wpa_printf(MSG_INFO, "No addMO element - not sure what to do next");
696d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			goto out;
697d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		}
698d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		process_spp_user_input_response(ctx, session_id, add_mo);
699d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		node = NULL;
700d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		goto out;
701d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
702d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
703d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (strcasecmp(status, "No update available at this time") == 0) {
704d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "No update available at this time");
705d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		goto out;
706d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
707d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
708d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (strcasecmp(status, "OK") == 0) {
709d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		int res;
710d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_t *ret;
711d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
712d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (!exec) {
713d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			wpa_printf(MSG_INFO, "No exec element - not sure what to do next");
714d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			goto out;
715d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		}
716d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		res = hs20_spp_exec(ctx, exec, session_id,
717d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt				    pps_fname, pps, &ret);
718d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		/* xml_node_free(ctx->xml, node); */
719d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		node = NULL;
720d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (res == 0 && ret)
721d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			process_spp_post_dev_data_response(ctx, use,
722d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt							   ret, pps_fname, pps);
723d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		goto out;
724d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
725d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
726d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (strcasecmp(status, "Error occurred") == 0) {
727d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_t *err;
728d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		char *code = NULL;
729d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		err = get_node(ctx->xml, node, "sppError");
730d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (err)
731d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			code = xml_node_get_attr_value(ctx->xml, err,
732d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt						       "errorCode");
733d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "Error occurred - errorCode=%s",
734d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			   code ? code : "N/A");
735d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_get_attr_value_free(ctx->xml, code);
736d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		goto out;
737d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
738d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
739d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	wpa_printf(MSG_INFO,
740d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		   "[hs20] Unsupported sppPostDevDataResponse sppStatus '%s'",
741d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		   status);
742d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidtout:
743d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_get_attr_value_free(ctx->xml, status);
744d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_get_attr_value_free(ctx->xml, session_id);
745d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_free(ctx->xml, node);
746d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt}
747d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
748d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
749d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidtstatic int spp_post_dev_data(struct hs20_osu_client *ctx,
750d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			     enum spp_post_dev_data_use use,
751d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			     const char *reason,
752d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			     const char *pps_fname, xml_node_t *pps)
753d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt{
754d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_t *payload;
755d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_t *ret_node;
756d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
757d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	payload = build_spp_post_dev_data(ctx, NULL, NULL, reason);
758d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (payload == NULL)
759d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
760d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
761d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	ret_node = soap_send_receive(ctx->http, payload);
762d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (!ret_node) {
763d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		const char *err = http_get_err(ctx->http);
764d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (err) {
765d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			wpa_printf(MSG_INFO, "HTTP error: %s", err);
766d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			write_result(ctx, "HTTP error: %s", err);
767d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		} else {
768d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			write_summary(ctx, "Failed to send SOAP message");
769d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		}
770d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
771d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
772d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
773d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
774d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "SPP validation failed");
775d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_free(ctx->xml, ret_node);
776d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
777d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
778d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
779d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	process_spp_post_dev_data_response(ctx, use, ret_node,
780d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt					   pps_fname, pps);
781d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	return 0;
782d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt}
783d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
784d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
785d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidtvoid spp_sub_rem(struct hs20_osu_client *ctx, const char *address,
7866cb1f6521a84955752c2b99100cf1df87637f86cDmitry Shmidt		 const char *pps_fname,
787d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		 const char *client_cert, const char *client_key,
788d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		 const char *cred_username, const char *cred_password,
789d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		 xml_node_t *pps)
790d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt{
791d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	wpa_printf(MSG_INFO, "SPP subscription remediation");
792d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	write_summary(ctx, "SPP subscription remediation");
793d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
794d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	os_free(ctx->server_url);
795d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	ctx->server_url = os_strdup(address);
796d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
7976cb1f6521a84955752c2b99100cf1df87637f86cDmitry Shmidt	if (soap_init_client(ctx->http, address, ctx->ca_fname,
798d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			     cred_username, cred_password, client_cert,
799d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			     client_key) == 0) {
800d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REMEDIATION,
801d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt				  "Subscription remediation", pps_fname, pps);
802d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
803d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt}
804d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
805d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
806d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidtstatic void hs20_policy_update_complete(struct hs20_osu_client *ctx,
807d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt					const char *pps_fname)
808d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt{
809d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	wpa_printf(MSG_INFO, "Policy update completed");
810d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
811d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	/*
812d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	 * Update wpa_supplicant credentials and reconnect using updated
813d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	 * information.
814d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	 */
815d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
816d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	cmd_set_pps(ctx, pps_fname);
817d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
818d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
819d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0)
820d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_ERROR, "Failed to request wpa_supplicant to reconnect");
821d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt}
822d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
823d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
824d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidtstatic int process_spp_exchange_complete(struct hs20_osu_client *ctx,
825d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt					 xml_node_t *node)
826d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt{
827d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	char *status, *session_id;
828d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
829d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	debug_dump_node(ctx, "sppExchangeComplete", node);
830d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
831d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	status = get_spp_attr_value(ctx->xml, node, "sppStatus");
832d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (status == NULL) {
833d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "No sppStatus attribute");
834d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
835d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
836d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	write_summary(ctx, "Received sppExchangeComplete sppStatus='%s'",
837d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		      status);
838d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
839d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	session_id = get_spp_attr_value(ctx->xml, node, "sessionID");
840d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (session_id == NULL) {
841d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "No sessionID attribute");
842d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_get_attr_value_free(ctx->xml, status);
843d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
844d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
845d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
846d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	wpa_printf(MSG_INFO, "[hs20] sppStatus: '%s'  sessionID: '%s'",
847d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		   status, session_id);
848d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_get_attr_value_free(ctx->xml, session_id);
849d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
850d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (strcasecmp(status, "Exchange complete, release TLS connection") ==
851d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	    0) {
852d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_get_attr_value_free(ctx->xml, status);
853d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return 0;
854d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
855d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
856d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	wpa_printf(MSG_INFO, "Unexpected sppStatus '%s'", status);
857d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	write_summary(ctx, "Unexpected sppStatus '%s'", status);
858d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_get_attr_value_free(ctx->xml, status);
859d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	return -1;
860d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt}
861d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
862d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
863d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidtstatic xml_node_t * build_spp_update_response(struct hs20_osu_client *ctx,
864d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt					      const char *session_id,
865d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt					      const char *spp_status,
866d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt					      const char *error_code)
867d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt{
868d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_namespace_t *ns;
869d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_t *spp_node, *node;
870d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
871d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
872d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt					"sppUpdateResponse");
873d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (spp_node == NULL)
874d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return NULL;
875d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
876d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
877d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
878d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", spp_status);
879d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
880d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (error_code) {
881d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
882d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (node)
883d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
884d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt					  error_code);
885d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
886d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
887d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	return spp_node;
888d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt}
889d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
890d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
891d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidtstatic int hs20_spp_update_response(struct hs20_osu_client *ctx,
892d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt				    const char *session_id,
893d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt				    const char *spp_status,
894d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt				    const char *error_code)
895d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt{
896d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_t *node, *ret_node;
897d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	int ret;
898d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
899d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	write_summary(ctx, "Building sppUpdateResponse sppStatus='%s' error_code='%s'",
900d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		      spp_status, error_code);
901d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	node = build_spp_update_response(ctx, session_id, spp_status,
902d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt					 error_code);
903d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (node == NULL)
904d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
905d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	ret_node = soap_send_receive(ctx->http, node);
906d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (!ret_node) {
907d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (soap_reinit_client(ctx->http) < 0)
908d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			return -1;
909d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "Try to finish with re-opened connection");
910d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		node = build_spp_update_response(ctx, session_id, spp_status,
911d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt						 error_code);
912d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (node == NULL)
913d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			return -1;
914d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		ret_node = soap_send_receive(ctx->http, node);
915d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		if (ret_node == NULL)
916d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			return -1;
917d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "Continue with new connection");
918d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
919d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
920d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (hs20_spp_validate(ctx, ret_node, "sppExchangeComplete") < 0) {
921d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "SPP validation failed");
922d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		xml_node_free(ctx->xml, ret_node);
923d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
924d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
925d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
926d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	ret = process_spp_exchange_complete(ctx, ret_node);
927d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	xml_node_free(ctx->xml, ret_node);
928d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	return ret;
929d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt}
930d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
931d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
932d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidtvoid spp_pol_upd(struct hs20_osu_client *ctx, const char *address,
9336cb1f6521a84955752c2b99100cf1df87637f86cDmitry Shmidt		 const char *pps_fname,
934d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		 const char *client_cert, const char *client_key,
935d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		 const char *cred_username, const char *cred_password,
936d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		 xml_node_t *pps)
937d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt{
938d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	wpa_printf(MSG_INFO, "SPP policy update");
939d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	write_summary(ctx, "SPP policy update");
940d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
941d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	os_free(ctx->server_url);
942d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	ctx->server_url = os_strdup(address);
943d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
9446cb1f6521a84955752c2b99100cf1df87637f86cDmitry Shmidt	if (soap_init_client(ctx->http, address, ctx->ca_fname, cred_username,
945d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			     cred_password, client_cert, client_key) == 0) {
946d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		spp_post_dev_data(ctx, SPP_POLICY_UPDATE, "Policy update",
947d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt				  pps_fname, pps);
948d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
949d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt}
950d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
951d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
9526cb1f6521a84955752c2b99100cf1df87637f86cDmitry Shmidtint cmd_prov(struct hs20_osu_client *ctx, const char *url)
953d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt{
954d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	unlink("Cert/est_cert.der");
955d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	unlink("Cert/est_cert.pem");
956d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
957d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (url == NULL) {
958d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
959d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
960d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
961d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
962af9da3180dc20f57df1fc1e1811f3df9fa9e6ab5Dmitry Shmidt	wpa_printf(MSG_INFO,
963af9da3180dc20f57df1fc1e1811f3df9fa9e6ab5Dmitry Shmidt		   "Credential provisioning requested - URL: %s ca_fname: %s",
964af9da3180dc20f57df1fc1e1811f3df9fa9e6ab5Dmitry Shmidt		   url, ctx->ca_fname ? ctx->ca_fname : "N/A");
965d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
966d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	os_free(ctx->server_url);
967d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	ctx->server_url = os_strdup(url);
968d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
9696cb1f6521a84955752c2b99100cf1df87637f86cDmitry Shmidt	if (soap_init_client(ctx->http, url, ctx->ca_fname, NULL, NULL, NULL,
9706cb1f6521a84955752c2b99100cf1df87637f86cDmitry Shmidt			     NULL) < 0)
971d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
972d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REGISTRATION,
973d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			  "Subscription registration", NULL, NULL);
974d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
975d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	return ctx->pps_cred_set ? 0 : -1;
976d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt}
977d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
978d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
9796cb1f6521a84955752c2b99100cf1df87637f86cDmitry Shmidtint cmd_sim_prov(struct hs20_osu_client *ctx, const char *url)
980d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt{
981d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (url == NULL) {
982d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
983d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
984d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
985d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
986d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	wpa_printf(MSG_INFO, "SIM provisioning requested");
987d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
988d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	os_free(ctx->server_url);
989d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	ctx->server_url = os_strdup(url);
990d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
991d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	wpa_printf(MSG_INFO, "Wait for IP address before starting SIM provisioning");
992d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
993d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	if (wait_ip_addr(ctx->ifname, 15) < 0) {
994d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway");
995d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	}
996d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
9976cb1f6521a84955752c2b99100cf1df87637f86cDmitry Shmidt	if (soap_init_client(ctx->http, url, ctx->ca_fname, NULL, NULL, NULL,
9986cb1f6521a84955752c2b99100cf1df87637f86cDmitry Shmidt			     NULL) < 0)
999d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt		return -1;
1000d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REGISTRATION,
1001d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt			  "Subscription provisioning", NULL, NULL);
1002d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt
1003d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt	return ctx->pps_cred_set ? 0 : -1;
1004d5dc24eb5fbf0e0feff214c0260cae845721d5feDmitry Shmidt}
1005