xref: /freebsd/contrib/wpa/hs20/client/oma_dm_client.c (revision 5b9c547c072b84410b50897cc53710c75b2f6b74)
1*5b9c547cSRui Paulo /*
2*5b9c547cSRui Paulo  * Hotspot 2.0 - OMA DM client
3*5b9c547cSRui Paulo  * Copyright (c) 2013-2014, Qualcomm Atheros, Inc.
4*5b9c547cSRui Paulo  *
5*5b9c547cSRui Paulo  * This software may be distributed under the terms of the BSD license.
6*5b9c547cSRui Paulo  * See README for more details.
7*5b9c547cSRui Paulo  */
8*5b9c547cSRui Paulo 
9*5b9c547cSRui Paulo #include "includes.h"
10*5b9c547cSRui Paulo 
11*5b9c547cSRui Paulo #include "common.h"
12*5b9c547cSRui Paulo #include "wpa_helpers.h"
13*5b9c547cSRui Paulo #include "xml-utils.h"
14*5b9c547cSRui Paulo #include "http-utils.h"
15*5b9c547cSRui Paulo #include "utils/browser.h"
16*5b9c547cSRui Paulo #include "osu_client.h"
17*5b9c547cSRui Paulo 
18*5b9c547cSRui Paulo 
19*5b9c547cSRui Paulo #define DM_SERVER_INITIATED_MGMT 1200
20*5b9c547cSRui Paulo #define DM_CLIENT_INITIATED_MGMT 1201
21*5b9c547cSRui Paulo #define DM_GENERIC_ALERT 1226
22*5b9c547cSRui Paulo 
23*5b9c547cSRui Paulo /* OMA-TS-SyncML-RepPro-V1_2_2 - 10. Response Status Codes */
24*5b9c547cSRui Paulo #define DM_RESP_OK 200
25*5b9c547cSRui Paulo #define DM_RESP_AUTH_ACCEPTED 212
26*5b9c547cSRui Paulo #define DM_RESP_CHUNKED_ITEM_ACCEPTED 213
27*5b9c547cSRui Paulo #define DM_RESP_NOT_EXECUTED 215
28*5b9c547cSRui Paulo #define DM_RESP_ATOMIC_ROLL_BACK_OK 216
29*5b9c547cSRui Paulo #define DM_RESP_NOT_MODIFIED 304
30*5b9c547cSRui Paulo #define DM_RESP_BAD_REQUEST 400
31*5b9c547cSRui Paulo #define DM_RESP_UNAUTHORIZED 401
32*5b9c547cSRui Paulo #define DM_RESP_FORBIDDEN 403
33*5b9c547cSRui Paulo #define DM_RESP_NOT_FOUND 404
34*5b9c547cSRui Paulo #define DM_RESP_COMMAND_NOT_ALLOWED 405
35*5b9c547cSRui Paulo #define DM_RESP_OPTIONAL_FEATURE_NOT_SUPPORTED 406
36*5b9c547cSRui Paulo #define DM_RESP_MISSING_CREDENTIALS 407
37*5b9c547cSRui Paulo #define DM_RESP_CONFLICT 409
38*5b9c547cSRui Paulo #define DM_RESP_GONE 410
39*5b9c547cSRui Paulo #define DM_RESP_INCOMPLETE_COMMAND 412
40*5b9c547cSRui Paulo #define DM_RESP_REQ_ENTITY_TOO_LARGE 413
41*5b9c547cSRui Paulo #define DM_RESP_URI_TOO_LONG 414
42*5b9c547cSRui Paulo #define DM_RESP_UNSUPPORTED_MEDIA_TYPE_OR_FORMAT 415
43*5b9c547cSRui Paulo #define DM_RESP_REQ_TOO_BIG 416
44*5b9c547cSRui Paulo #define DM_RESP_ALREADY_EXISTS 418
45*5b9c547cSRui Paulo #define DM_RESP_DEVICE_FULL 420
46*5b9c547cSRui Paulo #define DM_RESP_SIZE_MISMATCH 424
47*5b9c547cSRui Paulo #define DM_RESP_PERMISSION_DENIED 425
48*5b9c547cSRui Paulo #define DM_RESP_COMMAND_FAILED 500
49*5b9c547cSRui Paulo #define DM_RESP_COMMAND_NOT_IMPLEMENTED 501
50*5b9c547cSRui Paulo #define DM_RESP_ATOMIC_ROLL_BACK_FAILED 516
51*5b9c547cSRui Paulo 
52*5b9c547cSRui Paulo #define DM_HS20_SUBSCRIPTION_CREATION \
53*5b9c547cSRui Paulo 	"org.wi-fi.hotspot2dot0.SubscriptionCreation"
54*5b9c547cSRui Paulo #define DM_HS20_SUBSCRIPTION_PROVISIONING \
55*5b9c547cSRui Paulo 	"org.wi-fi.hotspot2dot0.SubscriptionProvisioning"
56*5b9c547cSRui Paulo #define DM_HS20_SUBSCRIPTION_REMEDIATION \
57*5b9c547cSRui Paulo 	"org.wi-fi.hotspot2dot0.SubscriptionRemediation"
58*5b9c547cSRui Paulo #define DM_HS20_POLICY_UPDATE \
59*5b9c547cSRui Paulo 	"org.wi-fi.hotspot2dot0.PolicyUpdate"
60*5b9c547cSRui Paulo 
61*5b9c547cSRui Paulo #define DM_URI_PPS "./Wi-Fi/org.wi-fi/PerProviderSubscription"
62*5b9c547cSRui Paulo #define DM_URI_LAUNCH_BROWSER \
63*5b9c547cSRui Paulo 	"./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/launchBrowserToURI"
64*5b9c547cSRui Paulo 
65*5b9c547cSRui Paulo 
66*5b9c547cSRui Paulo static void add_item(struct hs20_osu_client *ctx, xml_node_t *parent,
67*5b9c547cSRui Paulo 		     const char *locuri, const char *data);
68*5b9c547cSRui Paulo 
69*5b9c547cSRui Paulo 
70*5b9c547cSRui Paulo static const char * int2str(int val)
71*5b9c547cSRui Paulo {
72*5b9c547cSRui Paulo 	static char buf[20];
73*5b9c547cSRui Paulo 	snprintf(buf, sizeof(buf), "%d", val);
74*5b9c547cSRui Paulo 	return buf;
75*5b9c547cSRui Paulo }
76*5b9c547cSRui Paulo 
77*5b9c547cSRui Paulo 
78*5b9c547cSRui Paulo static char * oma_dm_get_target_locuri(struct hs20_osu_client *ctx,
79*5b9c547cSRui Paulo 				       xml_node_t *node)
80*5b9c547cSRui Paulo {
81*5b9c547cSRui Paulo 	xml_node_t *locuri;
82*5b9c547cSRui Paulo 	char *uri, *ret = NULL;
83*5b9c547cSRui Paulo 
84*5b9c547cSRui Paulo 	locuri = get_node(ctx->xml, node, "Item/Target/LocURI");
85*5b9c547cSRui Paulo 	if (locuri == NULL)
86*5b9c547cSRui Paulo 		return NULL;
87*5b9c547cSRui Paulo 
88*5b9c547cSRui Paulo 	uri = xml_node_get_text(ctx->xml, locuri);
89*5b9c547cSRui Paulo 	if (uri)
90*5b9c547cSRui Paulo 		ret = os_strdup(uri);
91*5b9c547cSRui Paulo 	xml_node_get_text_free(ctx->xml, uri);
92*5b9c547cSRui Paulo 	return ret;
93*5b9c547cSRui Paulo }
94*5b9c547cSRui Paulo 
95*5b9c547cSRui Paulo 
96*5b9c547cSRui Paulo static void oma_dm_add_locuri(struct hs20_osu_client *ctx, xml_node_t *parent,
97*5b9c547cSRui Paulo 			      const char *element, const char *uri)
98*5b9c547cSRui Paulo {
99*5b9c547cSRui Paulo 	xml_node_t *node;
100*5b9c547cSRui Paulo 
101*5b9c547cSRui Paulo 	node = xml_node_create(ctx->xml, parent, NULL, element);
102*5b9c547cSRui Paulo 	if (node == NULL)
103*5b9c547cSRui Paulo 		return;
104*5b9c547cSRui Paulo 	xml_node_create_text(ctx->xml, node, NULL, "LocURI", uri);
105*5b9c547cSRui Paulo }
106*5b9c547cSRui Paulo 
107*5b9c547cSRui Paulo 
108*5b9c547cSRui Paulo static xml_node_t * oma_dm_build_hdr(struct hs20_osu_client *ctx,
109*5b9c547cSRui Paulo 				     const char *url, int msgid)
110*5b9c547cSRui Paulo {
111*5b9c547cSRui Paulo 	xml_node_t *syncml, *synchdr;
112*5b9c547cSRui Paulo 	xml_namespace_t *ns;
113*5b9c547cSRui Paulo 
114*5b9c547cSRui Paulo 	syncml = xml_node_create_root(ctx->xml, "SYNCML:SYNCML1.2", NULL, &ns,
115*5b9c547cSRui Paulo 				      "SyncML");
116*5b9c547cSRui Paulo 
117*5b9c547cSRui Paulo 	synchdr = xml_node_create(ctx->xml, syncml, NULL, "SyncHdr");
118*5b9c547cSRui Paulo 	xml_node_create_text(ctx->xml, synchdr, NULL, "VerDTD", "1.2");
119*5b9c547cSRui Paulo 	xml_node_create_text(ctx->xml, synchdr, NULL, "VerProto", "DM/1.2");
120*5b9c547cSRui Paulo 	xml_node_create_text(ctx->xml, synchdr, NULL, "SessionID", "1");
121*5b9c547cSRui Paulo 	xml_node_create_text(ctx->xml, synchdr, NULL, "MsgID", int2str(msgid));
122*5b9c547cSRui Paulo 
123*5b9c547cSRui Paulo 	oma_dm_add_locuri(ctx, synchdr, "Target", url);
124*5b9c547cSRui Paulo 	oma_dm_add_locuri(ctx, synchdr, "Source", ctx->devid);
125*5b9c547cSRui Paulo 
126*5b9c547cSRui Paulo 	return syncml;
127*5b9c547cSRui Paulo }
128*5b9c547cSRui Paulo 
129*5b9c547cSRui Paulo 
130*5b9c547cSRui Paulo static void oma_dm_add_cmdid(struct hs20_osu_client *ctx, xml_node_t *parent,
131*5b9c547cSRui Paulo 			     int cmdid)
132*5b9c547cSRui Paulo {
133*5b9c547cSRui Paulo 	xml_node_create_text(ctx->xml, parent, NULL, "CmdID", int2str(cmdid));
134*5b9c547cSRui Paulo }
135*5b9c547cSRui Paulo 
136*5b9c547cSRui Paulo 
137*5b9c547cSRui Paulo static xml_node_t * add_alert(struct hs20_osu_client *ctx, xml_node_t *parent,
138*5b9c547cSRui Paulo 			      int cmdid, int data)
139*5b9c547cSRui Paulo {
140*5b9c547cSRui Paulo 	xml_node_t *node;
141*5b9c547cSRui Paulo 
142*5b9c547cSRui Paulo 	node = xml_node_create(ctx->xml, parent, NULL, "Alert");
143*5b9c547cSRui Paulo 	if (node == NULL)
144*5b9c547cSRui Paulo 		return NULL;
145*5b9c547cSRui Paulo 	oma_dm_add_cmdid(ctx, node, cmdid);
146*5b9c547cSRui Paulo 	xml_node_create_text(ctx->xml, node, NULL, "Data", int2str(data));
147*5b9c547cSRui Paulo 
148*5b9c547cSRui Paulo 	return node;
149*5b9c547cSRui Paulo }
150*5b9c547cSRui Paulo 
151*5b9c547cSRui Paulo 
152*5b9c547cSRui Paulo static xml_node_t * add_status(struct hs20_osu_client *ctx, xml_node_t *parent,
153*5b9c547cSRui Paulo 			       int msgref, int cmdref, int cmdid,
154*5b9c547cSRui Paulo 			       const char *cmd, int data, const char *targetref)
155*5b9c547cSRui Paulo {
156*5b9c547cSRui Paulo 	xml_node_t *node;
157*5b9c547cSRui Paulo 
158*5b9c547cSRui Paulo 	node = xml_node_create(ctx->xml, parent, NULL, "Status");
159*5b9c547cSRui Paulo 	if (node == NULL)
160*5b9c547cSRui Paulo 		return NULL;
161*5b9c547cSRui Paulo 	oma_dm_add_cmdid(ctx, node, cmdid);
162*5b9c547cSRui Paulo 	xml_node_create_text(ctx->xml, node, NULL, "MsgRef", int2str(msgref));
163*5b9c547cSRui Paulo 	if (cmdref)
164*5b9c547cSRui Paulo 		xml_node_create_text(ctx->xml, node, NULL, "CmdRef",
165*5b9c547cSRui Paulo 				     int2str(cmdref));
166*5b9c547cSRui Paulo 	xml_node_create_text(ctx->xml, node, NULL, "Cmd", cmd);
167*5b9c547cSRui Paulo 	xml_node_create_text(ctx->xml, node, NULL, "Data", int2str(data));
168*5b9c547cSRui Paulo 	if (targetref) {
169*5b9c547cSRui Paulo 		xml_node_create_text(ctx->xml, node, NULL, "TargetRef",
170*5b9c547cSRui Paulo 				     targetref);
171*5b9c547cSRui Paulo 	}
172*5b9c547cSRui Paulo 
173*5b9c547cSRui Paulo 	return node;
174*5b9c547cSRui Paulo }
175*5b9c547cSRui Paulo 
176*5b9c547cSRui Paulo 
177*5b9c547cSRui Paulo static xml_node_t * add_results(struct hs20_osu_client *ctx, xml_node_t *parent,
178*5b9c547cSRui Paulo 				int msgref, int cmdref, int cmdid,
179*5b9c547cSRui Paulo 				const char *locuri, const char *data)
180*5b9c547cSRui Paulo {
181*5b9c547cSRui Paulo 	xml_node_t *node;
182*5b9c547cSRui Paulo 
183*5b9c547cSRui Paulo 	node = xml_node_create(ctx->xml, parent, NULL, "Results");
184*5b9c547cSRui Paulo 	if (node == NULL)
185*5b9c547cSRui Paulo 		return NULL;
186*5b9c547cSRui Paulo 
187*5b9c547cSRui Paulo 	oma_dm_add_cmdid(ctx, node, cmdid);
188*5b9c547cSRui Paulo 	xml_node_create_text(ctx->xml, node, NULL, "MsgRef", int2str(msgref));
189*5b9c547cSRui Paulo 	xml_node_create_text(ctx->xml, node, NULL, "CmdRef", int2str(cmdref));
190*5b9c547cSRui Paulo 	add_item(ctx, node, locuri, data);
191*5b9c547cSRui Paulo 
192*5b9c547cSRui Paulo 	return node;
193*5b9c547cSRui Paulo }
194*5b9c547cSRui Paulo 
195*5b9c547cSRui Paulo 
196*5b9c547cSRui Paulo static char * mo_str(struct hs20_osu_client *ctx, const char *urn,
197*5b9c547cSRui Paulo 		     const char *fname)
198*5b9c547cSRui Paulo {
199*5b9c547cSRui Paulo 	xml_node_t *fnode, *tnds;
200*5b9c547cSRui Paulo 	char *str;
201*5b9c547cSRui Paulo 
202*5b9c547cSRui Paulo 	fnode = node_from_file(ctx->xml, fname);
203*5b9c547cSRui Paulo 	if (!fnode)
204*5b9c547cSRui Paulo 		return NULL;
205*5b9c547cSRui Paulo 	tnds = mo_to_tnds(ctx->xml, fnode, 0, urn, "syncml:dmddf1.2");
206*5b9c547cSRui Paulo 	xml_node_free(ctx->xml, fnode);
207*5b9c547cSRui Paulo 	if (!tnds)
208*5b9c547cSRui Paulo 		return NULL;
209*5b9c547cSRui Paulo 
210*5b9c547cSRui Paulo 	str = xml_node_to_str(ctx->xml, tnds);
211*5b9c547cSRui Paulo 	xml_node_free(ctx->xml, tnds);
212*5b9c547cSRui Paulo 	if (str == NULL)
213*5b9c547cSRui Paulo 		return NULL;
214*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "MgmtTree: %s", str);
215*5b9c547cSRui Paulo 
216*5b9c547cSRui Paulo 	return str;
217*5b9c547cSRui Paulo }
218*5b9c547cSRui Paulo 
219*5b9c547cSRui Paulo 
220*5b9c547cSRui Paulo static void add_item(struct hs20_osu_client *ctx, xml_node_t *parent,
221*5b9c547cSRui Paulo 		     const char *locuri, const char *data)
222*5b9c547cSRui Paulo {
223*5b9c547cSRui Paulo 	xml_node_t *item, *node;
224*5b9c547cSRui Paulo 
225*5b9c547cSRui Paulo 	item = xml_node_create(ctx->xml, parent, NULL, "Item");
226*5b9c547cSRui Paulo 	oma_dm_add_locuri(ctx, item, "Source", locuri);
227*5b9c547cSRui Paulo 	node = xml_node_create(ctx->xml, item, NULL, "Meta");
228*5b9c547cSRui Paulo 	xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Format",
229*5b9c547cSRui Paulo 				"Chr");
230*5b9c547cSRui Paulo 	xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Type",
231*5b9c547cSRui Paulo 				"text/plain");
232*5b9c547cSRui Paulo 	xml_node_create_text(ctx->xml, item, NULL, "Data", data);
233*5b9c547cSRui Paulo }
234*5b9c547cSRui Paulo 
235*5b9c547cSRui Paulo 
236*5b9c547cSRui Paulo static void add_replace_devinfo(struct hs20_osu_client *ctx, xml_node_t *parent,
237*5b9c547cSRui Paulo 				int cmdid)
238*5b9c547cSRui Paulo {
239*5b9c547cSRui Paulo 	xml_node_t *info, *child, *replace;
240*5b9c547cSRui Paulo 	const char *name;
241*5b9c547cSRui Paulo 	char locuri[200], *txt;
242*5b9c547cSRui Paulo 
243*5b9c547cSRui Paulo 	info = node_from_file(ctx->xml, "devinfo.xml");
244*5b9c547cSRui Paulo 	if (info == NULL) {
245*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Could not read devinfo.xml");
246*5b9c547cSRui Paulo 		return;
247*5b9c547cSRui Paulo 	}
248*5b9c547cSRui Paulo 
249*5b9c547cSRui Paulo 	replace = xml_node_create(ctx->xml, parent, NULL, "Replace");
250*5b9c547cSRui Paulo 	if (replace == NULL) {
251*5b9c547cSRui Paulo 		xml_node_free(ctx->xml, info);
252*5b9c547cSRui Paulo 		return;
253*5b9c547cSRui Paulo 	}
254*5b9c547cSRui Paulo 	oma_dm_add_cmdid(ctx, replace, cmdid);
255*5b9c547cSRui Paulo 
256*5b9c547cSRui Paulo 	xml_node_for_each_child(ctx->xml, child, info) {
257*5b9c547cSRui Paulo 		xml_node_for_each_check(ctx->xml, child);
258*5b9c547cSRui Paulo 		name = xml_node_get_localname(ctx->xml, child);
259*5b9c547cSRui Paulo 		os_snprintf(locuri, sizeof(locuri), "./DevInfo/%s", name);
260*5b9c547cSRui Paulo 		txt = xml_node_get_text(ctx->xml, child);
261*5b9c547cSRui Paulo 		if (txt) {
262*5b9c547cSRui Paulo 			add_item(ctx, replace, locuri, txt);
263*5b9c547cSRui Paulo 			xml_node_get_text_free(ctx->xml, txt);
264*5b9c547cSRui Paulo 		}
265*5b9c547cSRui Paulo 	}
266*5b9c547cSRui Paulo 
267*5b9c547cSRui Paulo 	xml_node_free(ctx->xml, info);
268*5b9c547cSRui Paulo }
269*5b9c547cSRui Paulo 
270*5b9c547cSRui Paulo 
271*5b9c547cSRui Paulo static void oma_dm_add_hs20_generic_alert(struct hs20_osu_client *ctx,
272*5b9c547cSRui Paulo 					  xml_node_t *syncbody,
273*5b9c547cSRui Paulo 					  int cmdid, const char *oper,
274*5b9c547cSRui Paulo 					  const char *data)
275*5b9c547cSRui Paulo {
276*5b9c547cSRui Paulo 	xml_node_t *node, *item;
277*5b9c547cSRui Paulo 	char buf[200];
278*5b9c547cSRui Paulo 
279*5b9c547cSRui Paulo 	node = add_alert(ctx, syncbody, cmdid, DM_GENERIC_ALERT);
280*5b9c547cSRui Paulo 
281*5b9c547cSRui Paulo 	item = xml_node_create(ctx->xml, node, NULL, "Item");
282*5b9c547cSRui Paulo 	oma_dm_add_locuri(ctx, item, "Source", DM_URI_PPS);
283*5b9c547cSRui Paulo 	node = xml_node_create(ctx->xml, item, NULL, "Meta");
284*5b9c547cSRui Paulo 	snprintf(buf, sizeof(buf), "Reversed-Domain-Name: %s", oper);
285*5b9c547cSRui Paulo 	xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Type", buf);
286*5b9c547cSRui Paulo 	xml_node_create_text_ns(ctx->xml, node, "syncml:metinf", "Format",
287*5b9c547cSRui Paulo 				"xml");
288*5b9c547cSRui Paulo 	xml_node_create_text(ctx->xml, item, NULL, "Data", data);
289*5b9c547cSRui Paulo }
290*5b9c547cSRui Paulo 
291*5b9c547cSRui Paulo 
292*5b9c547cSRui Paulo static xml_node_t * build_oma_dm_1(struct hs20_osu_client *ctx,
293*5b9c547cSRui Paulo 				   const char *url, int msgid, const char *oper)
294*5b9c547cSRui Paulo {
295*5b9c547cSRui Paulo 	xml_node_t *syncml, *syncbody;
296*5b9c547cSRui Paulo 	char *str;
297*5b9c547cSRui Paulo 	int cmdid = 0;
298*5b9c547cSRui Paulo 
299*5b9c547cSRui Paulo 	syncml = oma_dm_build_hdr(ctx, url, msgid);
300*5b9c547cSRui Paulo 	if (syncml == NULL)
301*5b9c547cSRui Paulo 		return NULL;
302*5b9c547cSRui Paulo 
303*5b9c547cSRui Paulo 	syncbody = xml_node_create(ctx->xml, syncml, NULL, "SyncBody");
304*5b9c547cSRui Paulo 	if (syncbody == NULL) {
305*5b9c547cSRui Paulo 		xml_node_free(ctx->xml, syncml);
306*5b9c547cSRui Paulo 		return NULL;
307*5b9c547cSRui Paulo 	}
308*5b9c547cSRui Paulo 
309*5b9c547cSRui Paulo 	cmdid++;
310*5b9c547cSRui Paulo 	add_alert(ctx, syncbody, cmdid, DM_CLIENT_INITIATED_MGMT);
311*5b9c547cSRui Paulo 
312*5b9c547cSRui Paulo 	str = mo_str(ctx, NULL, "devdetail.xml");
313*5b9c547cSRui Paulo 	if (str == NULL) {
314*5b9c547cSRui Paulo 		xml_node_free(ctx->xml, syncml);
315*5b9c547cSRui Paulo 		return NULL;
316*5b9c547cSRui Paulo 	}
317*5b9c547cSRui Paulo 	cmdid++;
318*5b9c547cSRui Paulo 	oma_dm_add_hs20_generic_alert(ctx, syncbody, cmdid, oper, str);
319*5b9c547cSRui Paulo 	os_free(str);
320*5b9c547cSRui Paulo 
321*5b9c547cSRui Paulo 	cmdid++;
322*5b9c547cSRui Paulo 	add_replace_devinfo(ctx, syncbody, cmdid);
323*5b9c547cSRui Paulo 
324*5b9c547cSRui Paulo 	xml_node_create(ctx->xml, syncbody, NULL, "Final");
325*5b9c547cSRui Paulo 
326*5b9c547cSRui Paulo 	return syncml;
327*5b9c547cSRui Paulo }
328*5b9c547cSRui Paulo 
329*5b9c547cSRui Paulo 
330*5b9c547cSRui Paulo static xml_node_t * build_oma_dm_1_sub_reg(struct hs20_osu_client *ctx,
331*5b9c547cSRui Paulo 					   const char *url, int msgid)
332*5b9c547cSRui Paulo {
333*5b9c547cSRui Paulo 	xml_node_t *syncml;
334*5b9c547cSRui Paulo 
335*5b9c547cSRui Paulo 	syncml = build_oma_dm_1(ctx, url, msgid, DM_HS20_SUBSCRIPTION_CREATION);
336*5b9c547cSRui Paulo 	if (syncml)
337*5b9c547cSRui Paulo 		debug_dump_node(ctx, "OMA-DM Package 1 (sub reg)", syncml);
338*5b9c547cSRui Paulo 
339*5b9c547cSRui Paulo 	return syncml;
340*5b9c547cSRui Paulo }
341*5b9c547cSRui Paulo 
342*5b9c547cSRui Paulo 
343*5b9c547cSRui Paulo static xml_node_t * build_oma_dm_1_sub_prov(struct hs20_osu_client *ctx,
344*5b9c547cSRui Paulo 					    const char *url, int msgid)
345*5b9c547cSRui Paulo {
346*5b9c547cSRui Paulo 	xml_node_t *syncml;
347*5b9c547cSRui Paulo 
348*5b9c547cSRui Paulo 	syncml = build_oma_dm_1(ctx, url, msgid,
349*5b9c547cSRui Paulo 				DM_HS20_SUBSCRIPTION_PROVISIONING);
350*5b9c547cSRui Paulo 	if (syncml)
351*5b9c547cSRui Paulo 		debug_dump_node(ctx, "OMA-DM Package 1 (sub prov)", syncml);
352*5b9c547cSRui Paulo 
353*5b9c547cSRui Paulo 	return syncml;
354*5b9c547cSRui Paulo }
355*5b9c547cSRui Paulo 
356*5b9c547cSRui Paulo 
357*5b9c547cSRui Paulo static xml_node_t * build_oma_dm_1_pol_upd(struct hs20_osu_client *ctx,
358*5b9c547cSRui Paulo 					   const char *url, int msgid)
359*5b9c547cSRui Paulo {
360*5b9c547cSRui Paulo 	xml_node_t *syncml;
361*5b9c547cSRui Paulo 
362*5b9c547cSRui Paulo 	syncml = build_oma_dm_1(ctx, url, msgid, DM_HS20_POLICY_UPDATE);
363*5b9c547cSRui Paulo 	if (syncml)
364*5b9c547cSRui Paulo 		debug_dump_node(ctx, "OMA-DM Package 1 (pol upd)", syncml);
365*5b9c547cSRui Paulo 
366*5b9c547cSRui Paulo 	return syncml;
367*5b9c547cSRui Paulo }
368*5b9c547cSRui Paulo 
369*5b9c547cSRui Paulo 
370*5b9c547cSRui Paulo static xml_node_t * build_oma_dm_1_sub_rem(struct hs20_osu_client *ctx,
371*5b9c547cSRui Paulo 					   const char *url, int msgid)
372*5b9c547cSRui Paulo {
373*5b9c547cSRui Paulo 	xml_node_t *syncml;
374*5b9c547cSRui Paulo 
375*5b9c547cSRui Paulo 	syncml = build_oma_dm_1(ctx, url, msgid,
376*5b9c547cSRui Paulo 				DM_HS20_SUBSCRIPTION_REMEDIATION);
377*5b9c547cSRui Paulo 	if (syncml)
378*5b9c547cSRui Paulo 		debug_dump_node(ctx, "OMA-DM Package 1 (sub rem)", syncml);
379*5b9c547cSRui Paulo 
380*5b9c547cSRui Paulo 	return syncml;
381*5b9c547cSRui Paulo }
382*5b9c547cSRui Paulo 
383*5b9c547cSRui Paulo 
384*5b9c547cSRui Paulo static int oma_dm_exec_browser(struct hs20_osu_client *ctx, xml_node_t *exec)
385*5b9c547cSRui Paulo {
386*5b9c547cSRui Paulo 	xml_node_t *node;
387*5b9c547cSRui Paulo 	char *data;
388*5b9c547cSRui Paulo 	int res;
389*5b9c547cSRui Paulo 
390*5b9c547cSRui Paulo 	node = get_node(ctx->xml, exec, "Item/Data");
391*5b9c547cSRui Paulo 	if (node == NULL) {
392*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "No Data node found");
393*5b9c547cSRui Paulo 		return DM_RESP_BAD_REQUEST;
394*5b9c547cSRui Paulo 	}
395*5b9c547cSRui Paulo 
396*5b9c547cSRui Paulo 	data = xml_node_get_text(ctx->xml, node);
397*5b9c547cSRui Paulo 	if (data == NULL) {
398*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Invalid data");
399*5b9c547cSRui Paulo 		return DM_RESP_BAD_REQUEST;
400*5b9c547cSRui Paulo 	}
401*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "Data: %s", data);
402*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "Launch browser to URI '%s'", data);
403*5b9c547cSRui Paulo 	write_summary(ctx, "Launch browser to URI '%s'", data);
404*5b9c547cSRui Paulo 	res = hs20_web_browser(data);
405*5b9c547cSRui Paulo 	xml_node_get_text_free(ctx->xml, data);
406*5b9c547cSRui Paulo 	if (res > 0) {
407*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "User response in browser completed successfully");
408*5b9c547cSRui Paulo 		write_summary(ctx, "User response in browser completed successfully");
409*5b9c547cSRui Paulo 		return DM_RESP_OK;
410*5b9c547cSRui Paulo 	} else {
411*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Failed to receive user response");
412*5b9c547cSRui Paulo 		write_summary(ctx, "Failed to receive user response");
413*5b9c547cSRui Paulo 		return DM_RESP_COMMAND_FAILED;
414*5b9c547cSRui Paulo 	}
415*5b9c547cSRui Paulo }
416*5b9c547cSRui Paulo 
417*5b9c547cSRui Paulo 
418*5b9c547cSRui Paulo static int oma_dm_exec_get_cert(struct hs20_osu_client *ctx, xml_node_t *exec)
419*5b9c547cSRui Paulo {
420*5b9c547cSRui Paulo 	xml_node_t *node, *getcert;
421*5b9c547cSRui Paulo 	char *data;
422*5b9c547cSRui Paulo 	const char *name;
423*5b9c547cSRui Paulo 	int res;
424*5b9c547cSRui Paulo 
425*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "Client certificate enrollment");
426*5b9c547cSRui Paulo 	write_summary(ctx, "Client certificate enrollment");
427*5b9c547cSRui Paulo 
428*5b9c547cSRui Paulo 	node = get_node(ctx->xml, exec, "Item/Data");
429*5b9c547cSRui Paulo 	if (node == NULL) {
430*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "No Data node found");
431*5b9c547cSRui Paulo 		return DM_RESP_BAD_REQUEST;
432*5b9c547cSRui Paulo 	}
433*5b9c547cSRui Paulo 
434*5b9c547cSRui Paulo 	data = xml_node_get_text(ctx->xml, node);
435*5b9c547cSRui Paulo 	if (data == NULL) {
436*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Invalid data");
437*5b9c547cSRui Paulo 		return DM_RESP_BAD_REQUEST;
438*5b9c547cSRui Paulo 	}
439*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "Data: %s", data);
440*5b9c547cSRui Paulo 	getcert = xml_node_from_buf(ctx->xml, data);
441*5b9c547cSRui Paulo 	xml_node_get_text_free(ctx->xml, data);
442*5b9c547cSRui Paulo 
443*5b9c547cSRui Paulo 	if (getcert == NULL) {
444*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Could not parse Item/Data node contents");
445*5b9c547cSRui Paulo 		return DM_RESP_BAD_REQUEST;
446*5b9c547cSRui Paulo 	}
447*5b9c547cSRui Paulo 
448*5b9c547cSRui Paulo 	debug_dump_node(ctx, "OMA-DM getCertificate", getcert);
449*5b9c547cSRui Paulo 
450*5b9c547cSRui Paulo 	name = xml_node_get_localname(ctx->xml, getcert);
451*5b9c547cSRui Paulo 	if (name == NULL || os_strcasecmp(name, "getCertificate") != 0) {
452*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Unexpected getCertificate node name '%s'",
453*5b9c547cSRui Paulo 			   name);
454*5b9c547cSRui Paulo 		return DM_RESP_BAD_REQUEST;
455*5b9c547cSRui Paulo 	}
456*5b9c547cSRui Paulo 
457*5b9c547cSRui Paulo 	res = osu_get_certificate(ctx, getcert);
458*5b9c547cSRui Paulo 
459*5b9c547cSRui Paulo 	xml_node_free(ctx->xml, getcert);
460*5b9c547cSRui Paulo 
461*5b9c547cSRui Paulo 	return res == 0 ? DM_RESP_OK : DM_RESP_COMMAND_FAILED;
462*5b9c547cSRui Paulo }
463*5b9c547cSRui Paulo 
464*5b9c547cSRui Paulo 
465*5b9c547cSRui Paulo static int oma_dm_exec(struct hs20_osu_client *ctx, xml_node_t *exec)
466*5b9c547cSRui Paulo {
467*5b9c547cSRui Paulo 	char *locuri;
468*5b9c547cSRui Paulo 	int ret;
469*5b9c547cSRui Paulo 
470*5b9c547cSRui Paulo 	locuri = oma_dm_get_target_locuri(ctx, exec);
471*5b9c547cSRui Paulo 	if (locuri == NULL) {
472*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "No Target LocURI node found");
473*5b9c547cSRui Paulo 		return DM_RESP_BAD_REQUEST;
474*5b9c547cSRui Paulo 	}
475*5b9c547cSRui Paulo 
476*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "Target LocURI: %s", locuri);
477*5b9c547cSRui Paulo 
478*5b9c547cSRui Paulo 	if (os_strcasecmp(locuri, "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/"
479*5b9c547cSRui Paulo 			  "launchBrowserToURI") == 0) {
480*5b9c547cSRui Paulo 		ret = oma_dm_exec_browser(ctx, exec);
481*5b9c547cSRui Paulo 	} else if (os_strcasecmp(locuri, "./DevDetail/Ext/org.wi-fi/Wi-Fi/Ops/"
482*5b9c547cSRui Paulo 			  "getCertificate") == 0) {
483*5b9c547cSRui Paulo 		ret = oma_dm_exec_get_cert(ctx, exec);
484*5b9c547cSRui Paulo 	} else {
485*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Unsupported exec Target LocURI");
486*5b9c547cSRui Paulo 		ret = DM_RESP_NOT_FOUND;
487*5b9c547cSRui Paulo 	}
488*5b9c547cSRui Paulo 	os_free(locuri);
489*5b9c547cSRui Paulo 
490*5b9c547cSRui Paulo 	return ret;
491*5b9c547cSRui Paulo }
492*5b9c547cSRui Paulo 
493*5b9c547cSRui Paulo 
494*5b9c547cSRui Paulo static int oma_dm_run_add(struct hs20_osu_client *ctx, const char *locuri,
495*5b9c547cSRui Paulo 			  xml_node_t *add, xml_node_t *pps,
496*5b9c547cSRui Paulo 			  const char *pps_fname)
497*5b9c547cSRui Paulo {
498*5b9c547cSRui Paulo 	const char *pos;
499*5b9c547cSRui Paulo 	size_t fqdn_len;
500*5b9c547cSRui Paulo 	xml_node_t *node, *tnds, *unode, *pps_node;
501*5b9c547cSRui Paulo 	char *data, *uri, *upos, *end;
502*5b9c547cSRui Paulo 	int use_tnds = 0;
503*5b9c547cSRui Paulo 	size_t uri_len;
504*5b9c547cSRui Paulo 
505*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "Add command target LocURI: %s", locuri);
506*5b9c547cSRui Paulo 
507*5b9c547cSRui Paulo 	if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
508*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Do not allow Add outside ./Wi-Fi");
509*5b9c547cSRui Paulo 		return DM_RESP_PERMISSION_DENIED;
510*5b9c547cSRui Paulo 	}
511*5b9c547cSRui Paulo 	pos = locuri + 8;
512*5b9c547cSRui Paulo 
513*5b9c547cSRui Paulo 	if (ctx->fqdn == NULL)
514*5b9c547cSRui Paulo 		return DM_RESP_COMMAND_FAILED;
515*5b9c547cSRui Paulo 	fqdn_len = os_strlen(ctx->fqdn);
516*5b9c547cSRui Paulo 	if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
517*5b9c547cSRui Paulo 	    pos[fqdn_len] != '/') {
518*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Do not allow Add outside ./Wi-Fi/%s",
519*5b9c547cSRui Paulo 			   ctx->fqdn);
520*5b9c547cSRui Paulo 		return DM_RESP_PERMISSION_DENIED;
521*5b9c547cSRui Paulo 	}
522*5b9c547cSRui Paulo 	pos += fqdn_len + 1;
523*5b9c547cSRui Paulo 
524*5b9c547cSRui Paulo 	if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
525*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO,
526*5b9c547cSRui Paulo 			   "Do not allow Add outside ./Wi-Fi/%s/PerProviderSubscription",
527*5b9c547cSRui Paulo 			   ctx->fqdn);
528*5b9c547cSRui Paulo 		return DM_RESP_PERMISSION_DENIED;
529*5b9c547cSRui Paulo 	}
530*5b9c547cSRui Paulo 	pos += 24;
531*5b9c547cSRui Paulo 
532*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "Add command for PPS node %s", pos);
533*5b9c547cSRui Paulo 
534*5b9c547cSRui Paulo 	pps_node = get_node(ctx->xml, pps, pos);
535*5b9c547cSRui Paulo 	if (pps_node) {
536*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Specified PPS node exists already");
537*5b9c547cSRui Paulo 		return DM_RESP_ALREADY_EXISTS;
538*5b9c547cSRui Paulo 	}
539*5b9c547cSRui Paulo 
540*5b9c547cSRui Paulo 	uri = os_strdup(pos);
541*5b9c547cSRui Paulo 	if (uri == NULL)
542*5b9c547cSRui Paulo 		return DM_RESP_COMMAND_FAILED;
543*5b9c547cSRui Paulo 	while (!pps_node) {
544*5b9c547cSRui Paulo 		upos = os_strrchr(uri, '/');
545*5b9c547cSRui Paulo 		if (!upos)
546*5b9c547cSRui Paulo 			break;
547*5b9c547cSRui Paulo 		upos[0] = '\0';
548*5b9c547cSRui Paulo 		pps_node = get_node(ctx->xml, pps, uri);
549*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Node %s %s", uri,
550*5b9c547cSRui Paulo 			   pps_node ? "exists" : "does not exist");
551*5b9c547cSRui Paulo 	}
552*5b9c547cSRui Paulo 
553*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "Parent URI: %s", uri);
554*5b9c547cSRui Paulo 
555*5b9c547cSRui Paulo 	if (!pps_node) {
556*5b9c547cSRui Paulo 		/* Add at root of PPS MO */
557*5b9c547cSRui Paulo 		pps_node = pps;
558*5b9c547cSRui Paulo 	}
559*5b9c547cSRui Paulo 
560*5b9c547cSRui Paulo 	uri_len = os_strlen(uri);
561*5b9c547cSRui Paulo 	os_strlcpy(uri, pos + uri_len, os_strlen(pos));
562*5b9c547cSRui Paulo 	upos = uri;
563*5b9c547cSRui Paulo 	while (*upos == '/')
564*5b9c547cSRui Paulo 		upos++;
565*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "Nodes to add: %s", upos);
566*5b9c547cSRui Paulo 
567*5b9c547cSRui Paulo 	for (;;) {
568*5b9c547cSRui Paulo 		end = os_strchr(upos, '/');
569*5b9c547cSRui Paulo 		if (!end)
570*5b9c547cSRui Paulo 			break;
571*5b9c547cSRui Paulo 		*end = '\0';
572*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Adding interim node %s", upos);
573*5b9c547cSRui Paulo 		pps_node = xml_node_create(ctx->xml, pps_node, NULL, upos);
574*5b9c547cSRui Paulo 		if (pps_node == NULL) {
575*5b9c547cSRui Paulo 			os_free(uri);
576*5b9c547cSRui Paulo 			return DM_RESP_COMMAND_FAILED;
577*5b9c547cSRui Paulo 		}
578*5b9c547cSRui Paulo 		upos = end + 1;
579*5b9c547cSRui Paulo 	}
580*5b9c547cSRui Paulo 
581*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "Adding node %s", upos);
582*5b9c547cSRui Paulo 
583*5b9c547cSRui Paulo 	node = get_node(ctx->xml, add, "Item/Meta/Type");
584*5b9c547cSRui Paulo 	if (node) {
585*5b9c547cSRui Paulo 		char *type;
586*5b9c547cSRui Paulo 		type = xml_node_get_text(ctx->xml, node);
587*5b9c547cSRui Paulo 		if (type == NULL) {
588*5b9c547cSRui Paulo 			wpa_printf(MSG_ERROR, "Could not find type text");
589*5b9c547cSRui Paulo 			os_free(uri);
590*5b9c547cSRui Paulo 			return DM_RESP_BAD_REQUEST;
591*5b9c547cSRui Paulo 		}
592*5b9c547cSRui Paulo 		use_tnds = node &&
593*5b9c547cSRui Paulo 			os_strstr(type, "application/vnd.syncml.dmtnds+xml");
594*5b9c547cSRui Paulo 	}
595*5b9c547cSRui Paulo 
596*5b9c547cSRui Paulo 	node = get_node(ctx->xml, add, "Item/Data");
597*5b9c547cSRui Paulo 	if (node == NULL) {
598*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "No Add/Item/Data found");
599*5b9c547cSRui Paulo 		os_free(uri);
600*5b9c547cSRui Paulo 		return DM_RESP_BAD_REQUEST;
601*5b9c547cSRui Paulo 	}
602*5b9c547cSRui Paulo 
603*5b9c547cSRui Paulo 	data = xml_node_get_text(ctx->xml, node);
604*5b9c547cSRui Paulo 	if (data == NULL) {
605*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Could not get Add/Item/Data text");
606*5b9c547cSRui Paulo 		os_free(uri);
607*5b9c547cSRui Paulo 		return DM_RESP_BAD_REQUEST;
608*5b9c547cSRui Paulo 	}
609*5b9c547cSRui Paulo 
610*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "Add/Item/Data: %s", data);
611*5b9c547cSRui Paulo 
612*5b9c547cSRui Paulo 	if (use_tnds) {
613*5b9c547cSRui Paulo 		tnds = xml_node_from_buf(ctx->xml, data);
614*5b9c547cSRui Paulo 		xml_node_get_text_free(ctx->xml, data);
615*5b9c547cSRui Paulo 		if (tnds == NULL) {
616*5b9c547cSRui Paulo 			wpa_printf(MSG_INFO,
617*5b9c547cSRui Paulo 				   "Could not parse Add/Item/Data text");
618*5b9c547cSRui Paulo 			os_free(uri);
619*5b9c547cSRui Paulo 			return DM_RESP_BAD_REQUEST;
620*5b9c547cSRui Paulo 		}
621*5b9c547cSRui Paulo 
622*5b9c547cSRui Paulo 		unode = tnds_to_mo(ctx->xml, tnds);
623*5b9c547cSRui Paulo 		xml_node_free(ctx->xml, tnds);
624*5b9c547cSRui Paulo 		if (unode == NULL) {
625*5b9c547cSRui Paulo 			wpa_printf(MSG_INFO, "Could not parse TNDS text");
626*5b9c547cSRui Paulo 			os_free(uri);
627*5b9c547cSRui Paulo 			return DM_RESP_BAD_REQUEST;
628*5b9c547cSRui Paulo 		}
629*5b9c547cSRui Paulo 
630*5b9c547cSRui Paulo 		debug_dump_node(ctx, "Parsed TNDS", unode);
631*5b9c547cSRui Paulo 
632*5b9c547cSRui Paulo 		xml_node_add_child(ctx->xml, pps_node, unode);
633*5b9c547cSRui Paulo 	} else {
634*5b9c547cSRui Paulo 		/* TODO: What to do here? */
635*5b9c547cSRui Paulo 		os_free(uri);
636*5b9c547cSRui Paulo 		return DM_RESP_BAD_REQUEST;
637*5b9c547cSRui Paulo 	}
638*5b9c547cSRui Paulo 
639*5b9c547cSRui Paulo 	os_free(uri);
640*5b9c547cSRui Paulo 
641*5b9c547cSRui Paulo 	if (update_pps_file(ctx, pps_fname, pps) < 0)
642*5b9c547cSRui Paulo 		return DM_RESP_COMMAND_FAILED;
643*5b9c547cSRui Paulo 
644*5b9c547cSRui Paulo 	ctx->pps_updated = 1;
645*5b9c547cSRui Paulo 
646*5b9c547cSRui Paulo 	return DM_RESP_OK;
647*5b9c547cSRui Paulo }
648*5b9c547cSRui Paulo 
649*5b9c547cSRui Paulo 
650*5b9c547cSRui Paulo static int oma_dm_add(struct hs20_osu_client *ctx, xml_node_t *add,
651*5b9c547cSRui Paulo 		      xml_node_t *pps, const char *pps_fname)
652*5b9c547cSRui Paulo {
653*5b9c547cSRui Paulo 	xml_node_t *node;
654*5b9c547cSRui Paulo 	char *locuri;
655*5b9c547cSRui Paulo 	char fname[300];
656*5b9c547cSRui Paulo 	int ret;
657*5b9c547cSRui Paulo 
658*5b9c547cSRui Paulo 	node = get_node(ctx->xml, add, "Item/Target/LocURI");
659*5b9c547cSRui Paulo 	if (node == NULL) {
660*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "No Target LocURI node found");
661*5b9c547cSRui Paulo 		return DM_RESP_BAD_REQUEST;
662*5b9c547cSRui Paulo 	}
663*5b9c547cSRui Paulo 	locuri = xml_node_get_text(ctx->xml, node);
664*5b9c547cSRui Paulo 	if (locuri == NULL) {
665*5b9c547cSRui Paulo 		wpa_printf(MSG_ERROR, "No LocURI node text found");
666*5b9c547cSRui Paulo 		return DM_RESP_BAD_REQUEST;
667*5b9c547cSRui Paulo 	}
668*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "Target LocURI: %s", locuri);
669*5b9c547cSRui Paulo 	if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
670*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Unsupported Add Target LocURI");
671*5b9c547cSRui Paulo 		xml_node_get_text_free(ctx->xml, locuri);
672*5b9c547cSRui Paulo 		return DM_RESP_PERMISSION_DENIED;
673*5b9c547cSRui Paulo 	}
674*5b9c547cSRui Paulo 
675*5b9c547cSRui Paulo 	node = get_node(ctx->xml, add, "Item/Data");
676*5b9c547cSRui Paulo 	if (node == NULL) {
677*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "No Data node found");
678*5b9c547cSRui Paulo 		xml_node_get_text_free(ctx->xml, locuri);
679*5b9c547cSRui Paulo 		return DM_RESP_BAD_REQUEST;
680*5b9c547cSRui Paulo 	}
681*5b9c547cSRui Paulo 
682*5b9c547cSRui Paulo 	if (pps_fname && os_file_exists(pps_fname)) {
683*5b9c547cSRui Paulo 		ret = oma_dm_run_add(ctx, locuri, add, pps, pps_fname);
684*5b9c547cSRui Paulo 		if (ret != DM_RESP_OK) {
685*5b9c547cSRui Paulo 			xml_node_get_text_free(ctx->xml, locuri);
686*5b9c547cSRui Paulo 			return ret;
687*5b9c547cSRui Paulo 		}
688*5b9c547cSRui Paulo 		ret = 0;
689*5b9c547cSRui Paulo 		os_strlcpy(fname, pps_fname, sizeof(fname));
690*5b9c547cSRui Paulo 	} else
691*5b9c547cSRui Paulo 		ret = hs20_add_pps_mo(ctx, locuri, node, fname, sizeof(fname));
692*5b9c547cSRui Paulo 	xml_node_get_text_free(ctx->xml, locuri);
693*5b9c547cSRui Paulo 	if (ret < 0)
694*5b9c547cSRui Paulo 		return ret == -2 ? DM_RESP_ALREADY_EXISTS :
695*5b9c547cSRui Paulo 			DM_RESP_COMMAND_FAILED;
696*5b9c547cSRui Paulo 
697*5b9c547cSRui Paulo 	if (ctx->no_reconnect == 2) {
698*5b9c547cSRui Paulo 		os_snprintf(ctx->pps_fname, sizeof(ctx->pps_fname), "%s",
699*5b9c547cSRui Paulo 			    fname);
700*5b9c547cSRui Paulo 		ctx->pps_cred_set = 1;
701*5b9c547cSRui Paulo 		return DM_RESP_OK;
702*5b9c547cSRui Paulo 	}
703*5b9c547cSRui Paulo 
704*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
705*5b9c547cSRui Paulo 	cmd_set_pps(ctx, fname);
706*5b9c547cSRui Paulo 
707*5b9c547cSRui Paulo 	if (ctx->no_reconnect)
708*5b9c547cSRui Paulo 		return DM_RESP_OK;
709*5b9c547cSRui Paulo 
710*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
711*5b9c547cSRui Paulo 	if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0)
712*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect");
713*5b9c547cSRui Paulo 
714*5b9c547cSRui Paulo 	return DM_RESP_OK;
715*5b9c547cSRui Paulo }
716*5b9c547cSRui Paulo 
717*5b9c547cSRui Paulo 
718*5b9c547cSRui Paulo static int oma_dm_replace(struct hs20_osu_client *ctx, xml_node_t *replace,
719*5b9c547cSRui Paulo 			  xml_node_t *pps, const char *pps_fname)
720*5b9c547cSRui Paulo {
721*5b9c547cSRui Paulo 	char *locuri, *pos;
722*5b9c547cSRui Paulo 	size_t fqdn_len;
723*5b9c547cSRui Paulo 	xml_node_t *node, *tnds, *unode, *pps_node, *parent;
724*5b9c547cSRui Paulo 	char *data;
725*5b9c547cSRui Paulo 	int use_tnds = 0;
726*5b9c547cSRui Paulo 
727*5b9c547cSRui Paulo 	locuri = oma_dm_get_target_locuri(ctx, replace);
728*5b9c547cSRui Paulo 	if (locuri == NULL)
729*5b9c547cSRui Paulo 		return DM_RESP_BAD_REQUEST;
730*5b9c547cSRui Paulo 
731*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "Replace command target LocURI: %s", locuri);
732*5b9c547cSRui Paulo 	if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
733*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Do not allow Replace outside ./Wi-Fi");
734*5b9c547cSRui Paulo 		os_free(locuri);
735*5b9c547cSRui Paulo 		return DM_RESP_PERMISSION_DENIED;
736*5b9c547cSRui Paulo 	}
737*5b9c547cSRui Paulo 	pos = locuri + 8;
738*5b9c547cSRui Paulo 
739*5b9c547cSRui Paulo 	if (ctx->fqdn == NULL) {
740*5b9c547cSRui Paulo 		os_free(locuri);
741*5b9c547cSRui Paulo 		return DM_RESP_COMMAND_FAILED;
742*5b9c547cSRui Paulo 	}
743*5b9c547cSRui Paulo 	fqdn_len = os_strlen(ctx->fqdn);
744*5b9c547cSRui Paulo 	if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
745*5b9c547cSRui Paulo 	    pos[fqdn_len] != '/') {
746*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Do not allow Replace outside ./Wi-Fi/%s",
747*5b9c547cSRui Paulo 			   ctx->fqdn);
748*5b9c547cSRui Paulo 		os_free(locuri);
749*5b9c547cSRui Paulo 		return DM_RESP_PERMISSION_DENIED;
750*5b9c547cSRui Paulo 	}
751*5b9c547cSRui Paulo 	pos += fqdn_len + 1;
752*5b9c547cSRui Paulo 
753*5b9c547cSRui Paulo 	if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
754*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO,
755*5b9c547cSRui Paulo 			   "Do not allow Replace outside ./Wi-Fi/%s/PerProviderSubscription",
756*5b9c547cSRui Paulo 			   ctx->fqdn);
757*5b9c547cSRui Paulo 		os_free(locuri);
758*5b9c547cSRui Paulo 		return DM_RESP_PERMISSION_DENIED;
759*5b9c547cSRui Paulo 	}
760*5b9c547cSRui Paulo 	pos += 24;
761*5b9c547cSRui Paulo 
762*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "Replace command for PPS node %s", pos);
763*5b9c547cSRui Paulo 
764*5b9c547cSRui Paulo 	pps_node = get_node(ctx->xml, pps, pos);
765*5b9c547cSRui Paulo 	if (pps_node == NULL) {
766*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Specified PPS node not found");
767*5b9c547cSRui Paulo 		os_free(locuri);
768*5b9c547cSRui Paulo 		return DM_RESP_NOT_FOUND;
769*5b9c547cSRui Paulo 	}
770*5b9c547cSRui Paulo 
771*5b9c547cSRui Paulo 	node = get_node(ctx->xml, replace, "Item/Meta/Type");
772*5b9c547cSRui Paulo 	if (node) {
773*5b9c547cSRui Paulo 		char *type;
774*5b9c547cSRui Paulo 		type = xml_node_get_text(ctx->xml, node);
775*5b9c547cSRui Paulo 		if (type == NULL) {
776*5b9c547cSRui Paulo 			wpa_printf(MSG_INFO, "Could not find type text");
777*5b9c547cSRui Paulo 			os_free(locuri);
778*5b9c547cSRui Paulo 			return DM_RESP_BAD_REQUEST;
779*5b9c547cSRui Paulo 		}
780*5b9c547cSRui Paulo 		use_tnds = node &&
781*5b9c547cSRui Paulo 			os_strstr(type, "application/vnd.syncml.dmtnds+xml");
782*5b9c547cSRui Paulo 	}
783*5b9c547cSRui Paulo 
784*5b9c547cSRui Paulo 	node = get_node(ctx->xml, replace, "Item/Data");
785*5b9c547cSRui Paulo 	if (node == NULL) {
786*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "No Replace/Item/Data found");
787*5b9c547cSRui Paulo 		os_free(locuri);
788*5b9c547cSRui Paulo 		return DM_RESP_BAD_REQUEST;
789*5b9c547cSRui Paulo 	}
790*5b9c547cSRui Paulo 
791*5b9c547cSRui Paulo 	data = xml_node_get_text(ctx->xml, node);
792*5b9c547cSRui Paulo 	if (data == NULL) {
793*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Could not get Replace/Item/Data text");
794*5b9c547cSRui Paulo 		os_free(locuri);
795*5b9c547cSRui Paulo 		return DM_RESP_BAD_REQUEST;
796*5b9c547cSRui Paulo 	}
797*5b9c547cSRui Paulo 
798*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "Replace/Item/Data: %s", data);
799*5b9c547cSRui Paulo 
800*5b9c547cSRui Paulo 	if (use_tnds) {
801*5b9c547cSRui Paulo 		tnds = xml_node_from_buf(ctx->xml, data);
802*5b9c547cSRui Paulo 		xml_node_get_text_free(ctx->xml, data);
803*5b9c547cSRui Paulo 		if (tnds == NULL) {
804*5b9c547cSRui Paulo 			wpa_printf(MSG_INFO,
805*5b9c547cSRui Paulo 				   "Could not parse Replace/Item/Data text");
806*5b9c547cSRui Paulo 			os_free(locuri);
807*5b9c547cSRui Paulo 			return DM_RESP_BAD_REQUEST;
808*5b9c547cSRui Paulo 		}
809*5b9c547cSRui Paulo 
810*5b9c547cSRui Paulo 		unode = tnds_to_mo(ctx->xml, tnds);
811*5b9c547cSRui Paulo 		xml_node_free(ctx->xml, tnds);
812*5b9c547cSRui Paulo 		if (unode == NULL) {
813*5b9c547cSRui Paulo 			wpa_printf(MSG_INFO, "Could not parse TNDS text");
814*5b9c547cSRui Paulo 			os_free(locuri);
815*5b9c547cSRui Paulo 			return DM_RESP_BAD_REQUEST;
816*5b9c547cSRui Paulo 		}
817*5b9c547cSRui Paulo 
818*5b9c547cSRui Paulo 		debug_dump_node(ctx, "Parsed TNDS", unode);
819*5b9c547cSRui Paulo 
820*5b9c547cSRui Paulo 		parent = xml_node_get_parent(ctx->xml, pps_node);
821*5b9c547cSRui Paulo 		xml_node_detach(ctx->xml, pps_node);
822*5b9c547cSRui Paulo 		xml_node_add_child(ctx->xml, parent, unode);
823*5b9c547cSRui Paulo 	} else {
824*5b9c547cSRui Paulo 		xml_node_set_text(ctx->xml, pps_node, data);
825*5b9c547cSRui Paulo 		xml_node_get_text_free(ctx->xml, data);
826*5b9c547cSRui Paulo 	}
827*5b9c547cSRui Paulo 
828*5b9c547cSRui Paulo 	os_free(locuri);
829*5b9c547cSRui Paulo 
830*5b9c547cSRui Paulo 	if (update_pps_file(ctx, pps_fname, pps) < 0)
831*5b9c547cSRui Paulo 		return DM_RESP_COMMAND_FAILED;
832*5b9c547cSRui Paulo 
833*5b9c547cSRui Paulo 	ctx->pps_updated = 1;
834*5b9c547cSRui Paulo 
835*5b9c547cSRui Paulo 	return DM_RESP_OK;
836*5b9c547cSRui Paulo }
837*5b9c547cSRui Paulo 
838*5b9c547cSRui Paulo 
839*5b9c547cSRui Paulo static int oma_dm_get(struct hs20_osu_client *ctx, xml_node_t *get,
840*5b9c547cSRui Paulo 		      xml_node_t *pps, const char *pps_fname, char **value)
841*5b9c547cSRui Paulo {
842*5b9c547cSRui Paulo 	char *locuri, *pos;
843*5b9c547cSRui Paulo 	size_t fqdn_len;
844*5b9c547cSRui Paulo 	xml_node_t *pps_node;
845*5b9c547cSRui Paulo 	const char *name;
846*5b9c547cSRui Paulo 
847*5b9c547cSRui Paulo 	*value = NULL;
848*5b9c547cSRui Paulo 
849*5b9c547cSRui Paulo 	locuri = oma_dm_get_target_locuri(ctx, get);
850*5b9c547cSRui Paulo 	if (locuri == NULL)
851*5b9c547cSRui Paulo 		return DM_RESP_BAD_REQUEST;
852*5b9c547cSRui Paulo 
853*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "Get command target LocURI: %s", locuri);
854*5b9c547cSRui Paulo 	if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
855*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Do not allow Get outside ./Wi-Fi");
856*5b9c547cSRui Paulo 		os_free(locuri);
857*5b9c547cSRui Paulo 		return DM_RESP_PERMISSION_DENIED;
858*5b9c547cSRui Paulo 	}
859*5b9c547cSRui Paulo 	pos = locuri + 8;
860*5b9c547cSRui Paulo 
861*5b9c547cSRui Paulo 	if (ctx->fqdn == NULL)
862*5b9c547cSRui Paulo 		return DM_RESP_COMMAND_FAILED;
863*5b9c547cSRui Paulo 	fqdn_len = os_strlen(ctx->fqdn);
864*5b9c547cSRui Paulo 	if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
865*5b9c547cSRui Paulo 	    pos[fqdn_len] != '/') {
866*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Do not allow Get outside ./Wi-Fi/%s",
867*5b9c547cSRui Paulo 			   ctx->fqdn);
868*5b9c547cSRui Paulo 		os_free(locuri);
869*5b9c547cSRui Paulo 		return DM_RESP_PERMISSION_DENIED;
870*5b9c547cSRui Paulo 	}
871*5b9c547cSRui Paulo 	pos += fqdn_len + 1;
872*5b9c547cSRui Paulo 
873*5b9c547cSRui Paulo 	if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
874*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO,
875*5b9c547cSRui Paulo 			   "Do not allow Get outside ./Wi-Fi/%s/PerProviderSubscription",
876*5b9c547cSRui Paulo 			   ctx->fqdn);
877*5b9c547cSRui Paulo 		os_free(locuri);
878*5b9c547cSRui Paulo 		return DM_RESP_PERMISSION_DENIED;
879*5b9c547cSRui Paulo 	}
880*5b9c547cSRui Paulo 	pos += 24;
881*5b9c547cSRui Paulo 
882*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "Get command for PPS node %s", pos);
883*5b9c547cSRui Paulo 
884*5b9c547cSRui Paulo 	pps_node = get_node(ctx->xml, pps, pos);
885*5b9c547cSRui Paulo 	if (pps_node == NULL) {
886*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Specified PPS node not found");
887*5b9c547cSRui Paulo 		os_free(locuri);
888*5b9c547cSRui Paulo 		return DM_RESP_NOT_FOUND;
889*5b9c547cSRui Paulo 	}
890*5b9c547cSRui Paulo 
891*5b9c547cSRui Paulo 	name = xml_node_get_localname(ctx->xml, pps_node);
892*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "Get command returned node with name '%s'", name);
893*5b9c547cSRui Paulo 	if (os_strcasecmp(name, "Password") == 0) {
894*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Do not allow Get for Password node");
895*5b9c547cSRui Paulo 		os_free(locuri);
896*5b9c547cSRui Paulo 		return DM_RESP_PERMISSION_DENIED;
897*5b9c547cSRui Paulo 	}
898*5b9c547cSRui Paulo 
899*5b9c547cSRui Paulo 	/*
900*5b9c547cSRui Paulo 	 * TODO: No support for DMTNDS, so if interior node, reply with a
901*5b9c547cSRui Paulo 	 * list of children node names in Results element. The child list type is
902*5b9c547cSRui Paulo 	 * defined in [DMTND].
903*5b9c547cSRui Paulo 	 */
904*5b9c547cSRui Paulo 
905*5b9c547cSRui Paulo 	*value = xml_node_get_text(ctx->xml, pps_node);
906*5b9c547cSRui Paulo 	if (*value == NULL)
907*5b9c547cSRui Paulo 		return DM_RESP_COMMAND_FAILED;
908*5b9c547cSRui Paulo 
909*5b9c547cSRui Paulo 	return DM_RESP_OK;
910*5b9c547cSRui Paulo }
911*5b9c547cSRui Paulo 
912*5b9c547cSRui Paulo 
913*5b9c547cSRui Paulo static int oma_dm_get_cmdid(struct hs20_osu_client *ctx, xml_node_t *node)
914*5b9c547cSRui Paulo {
915*5b9c547cSRui Paulo 	xml_node_t *cnode;
916*5b9c547cSRui Paulo 	char *str;
917*5b9c547cSRui Paulo 	int ret;
918*5b9c547cSRui Paulo 
919*5b9c547cSRui Paulo 	cnode = get_node(ctx->xml, node, "CmdID");
920*5b9c547cSRui Paulo 	if (cnode == NULL)
921*5b9c547cSRui Paulo 		return 0;
922*5b9c547cSRui Paulo 
923*5b9c547cSRui Paulo 	str = xml_node_get_text(ctx->xml, cnode);
924*5b9c547cSRui Paulo 	if (str == NULL)
925*5b9c547cSRui Paulo 		return 0;
926*5b9c547cSRui Paulo 	ret = atoi(str);
927*5b9c547cSRui Paulo 	xml_node_get_text_free(ctx->xml, str);
928*5b9c547cSRui Paulo 	return ret;
929*5b9c547cSRui Paulo }
930*5b9c547cSRui Paulo 
931*5b9c547cSRui Paulo 
932*5b9c547cSRui Paulo static xml_node_t * oma_dm_send_recv(struct hs20_osu_client *ctx,
933*5b9c547cSRui Paulo 				     const char *url, xml_node_t *syncml,
934*5b9c547cSRui Paulo 				     const char *ext_hdr,
935*5b9c547cSRui Paulo 				     const char *username, const char *password,
936*5b9c547cSRui Paulo 				     const char *client_cert,
937*5b9c547cSRui Paulo 				     const char *client_key)
938*5b9c547cSRui Paulo {
939*5b9c547cSRui Paulo 	xml_node_t *resp;
940*5b9c547cSRui Paulo 	char *str, *res;
941*5b9c547cSRui Paulo 	char *resp_uri = NULL;
942*5b9c547cSRui Paulo 
943*5b9c547cSRui Paulo 	str = xml_node_to_str(ctx->xml, syncml);
944*5b9c547cSRui Paulo 	xml_node_free(ctx->xml, syncml);
945*5b9c547cSRui Paulo 	if (str == NULL)
946*5b9c547cSRui Paulo 		return NULL;
947*5b9c547cSRui Paulo 
948*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "Send OMA DM Package");
949*5b9c547cSRui Paulo 	write_summary(ctx, "Send OMA DM Package");
950*5b9c547cSRui Paulo 	os_free(ctx->server_url);
951*5b9c547cSRui Paulo 	ctx->server_url = os_strdup(url);
952*5b9c547cSRui Paulo 	res = http_post(ctx->http, url, str, "application/vnd.syncml.dm+xml",
953*5b9c547cSRui Paulo 			ext_hdr, ctx->ca_fname, username, password,
954*5b9c547cSRui Paulo 			client_cert, client_key, NULL);
955*5b9c547cSRui Paulo 	os_free(str);
956*5b9c547cSRui Paulo 	os_free(resp_uri);
957*5b9c547cSRui Paulo 	resp_uri = NULL;
958*5b9c547cSRui Paulo 
959*5b9c547cSRui Paulo 	if (res == NULL) {
960*5b9c547cSRui Paulo 		const char *err = http_get_err(ctx->http);
961*5b9c547cSRui Paulo 		if (err) {
962*5b9c547cSRui Paulo 			wpa_printf(MSG_INFO, "HTTP error: %s", err);
963*5b9c547cSRui Paulo 			write_result(ctx, "HTTP error: %s", err);
964*5b9c547cSRui Paulo 		} else {
965*5b9c547cSRui Paulo 			write_summary(ctx, "Failed to send OMA DM Package");
966*5b9c547cSRui Paulo 		}
967*5b9c547cSRui Paulo 		return NULL;
968*5b9c547cSRui Paulo 	}
969*5b9c547cSRui Paulo 	wpa_printf(MSG_DEBUG, "Server response: %s", res);
970*5b9c547cSRui Paulo 
971*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "Process OMA DM Package");
972*5b9c547cSRui Paulo 	write_summary(ctx, "Process received OMA DM Package");
973*5b9c547cSRui Paulo 	resp = xml_node_from_buf(ctx->xml, res);
974*5b9c547cSRui Paulo 	os_free(res);
975*5b9c547cSRui Paulo 	if (resp == NULL) {
976*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Failed to parse OMA DM response");
977*5b9c547cSRui Paulo 		return NULL;
978*5b9c547cSRui Paulo 	}
979*5b9c547cSRui Paulo 
980*5b9c547cSRui Paulo 	debug_dump_node(ctx, "OMA DM Package", resp);
981*5b9c547cSRui Paulo 
982*5b9c547cSRui Paulo 	return resp;
983*5b9c547cSRui Paulo }
984*5b9c547cSRui Paulo 
985*5b9c547cSRui Paulo 
986*5b9c547cSRui Paulo static xml_node_t * oma_dm_process(struct hs20_osu_client *ctx, const char *url,
987*5b9c547cSRui Paulo 				   xml_node_t *resp, int msgid,
988*5b9c547cSRui Paulo 				   char **ret_resp_uri,
989*5b9c547cSRui Paulo 				   xml_node_t *pps, const char *pps_fname)
990*5b9c547cSRui Paulo {
991*5b9c547cSRui Paulo 	xml_node_t *syncml, *syncbody, *hdr, *body, *child;
992*5b9c547cSRui Paulo 	const char *name;
993*5b9c547cSRui Paulo 	char *resp_uri = NULL;
994*5b9c547cSRui Paulo 	int server_msgid = 0;
995*5b9c547cSRui Paulo 	int cmdid = 0;
996*5b9c547cSRui Paulo 	int server_cmdid;
997*5b9c547cSRui Paulo 	int resp_needed = 0;
998*5b9c547cSRui Paulo 	char *tmp;
999*5b9c547cSRui Paulo 	int final = 0;
1000*5b9c547cSRui Paulo 	char *locuri;
1001*5b9c547cSRui Paulo 
1002*5b9c547cSRui Paulo 	*ret_resp_uri = NULL;
1003*5b9c547cSRui Paulo 
1004*5b9c547cSRui Paulo 	name = xml_node_get_localname(ctx->xml, resp);
1005*5b9c547cSRui Paulo 	if (name == NULL || os_strcasecmp(name, "SyncML") != 0) {
1006*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "SyncML node not found");
1007*5b9c547cSRui Paulo 		return NULL;
1008*5b9c547cSRui Paulo 	}
1009*5b9c547cSRui Paulo 
1010*5b9c547cSRui Paulo 	hdr = get_node(ctx->xml, resp, "SyncHdr");
1011*5b9c547cSRui Paulo 	body = get_node(ctx->xml, resp, "SyncBody");
1012*5b9c547cSRui Paulo 	if (hdr == NULL || body == NULL) {
1013*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Could not find SyncHdr or SyncBody");
1014*5b9c547cSRui Paulo 		return NULL;
1015*5b9c547cSRui Paulo 	}
1016*5b9c547cSRui Paulo 
1017*5b9c547cSRui Paulo 	xml_node_for_each_child(ctx->xml, child, hdr) {
1018*5b9c547cSRui Paulo 		xml_node_for_each_check(ctx->xml, child);
1019*5b9c547cSRui Paulo 		name = xml_node_get_localname(ctx->xml, child);
1020*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "SyncHdr %s", name);
1021*5b9c547cSRui Paulo 		if (os_strcasecmp(name, "RespURI") == 0) {
1022*5b9c547cSRui Paulo 			tmp = xml_node_get_text(ctx->xml, child);
1023*5b9c547cSRui Paulo 			if (tmp)
1024*5b9c547cSRui Paulo 				resp_uri = os_strdup(tmp);
1025*5b9c547cSRui Paulo 			xml_node_get_text_free(ctx->xml, tmp);
1026*5b9c547cSRui Paulo 		} else if (os_strcasecmp(name, "MsgID") == 0) {
1027*5b9c547cSRui Paulo 			tmp = xml_node_get_text(ctx->xml, child);
1028*5b9c547cSRui Paulo 			if (tmp)
1029*5b9c547cSRui Paulo 				server_msgid = atoi(tmp);
1030*5b9c547cSRui Paulo 			xml_node_get_text_free(ctx->xml, tmp);
1031*5b9c547cSRui Paulo 		}
1032*5b9c547cSRui Paulo 	}
1033*5b9c547cSRui Paulo 
1034*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "Server MsgID: %d", server_msgid);
1035*5b9c547cSRui Paulo 	if (resp_uri)
1036*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "RespURI: %s", resp_uri);
1037*5b9c547cSRui Paulo 
1038*5b9c547cSRui Paulo 	syncml = oma_dm_build_hdr(ctx, resp_uri ? resp_uri : url, msgid);
1039*5b9c547cSRui Paulo 	if (syncml == NULL) {
1040*5b9c547cSRui Paulo 		os_free(resp_uri);
1041*5b9c547cSRui Paulo 		return NULL;
1042*5b9c547cSRui Paulo 	}
1043*5b9c547cSRui Paulo 
1044*5b9c547cSRui Paulo 	syncbody = xml_node_create(ctx->xml, syncml, NULL, "SyncBody");
1045*5b9c547cSRui Paulo 	cmdid++;
1046*5b9c547cSRui Paulo 	add_status(ctx, syncbody, server_msgid, 0, cmdid, "SyncHdr",
1047*5b9c547cSRui Paulo 		   DM_RESP_AUTH_ACCEPTED, NULL);
1048*5b9c547cSRui Paulo 
1049*5b9c547cSRui Paulo 	xml_node_for_each_child(ctx->xml, child, body) {
1050*5b9c547cSRui Paulo 		xml_node_for_each_check(ctx->xml, child);
1051*5b9c547cSRui Paulo 		server_cmdid = oma_dm_get_cmdid(ctx, child);
1052*5b9c547cSRui Paulo 		name = xml_node_get_localname(ctx->xml, child);
1053*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "SyncBody CmdID=%d - %s",
1054*5b9c547cSRui Paulo 			   server_cmdid, name);
1055*5b9c547cSRui Paulo 		if (os_strcasecmp(name, "Exec") == 0) {
1056*5b9c547cSRui Paulo 			int res = oma_dm_exec(ctx, child);
1057*5b9c547cSRui Paulo 			cmdid++;
1058*5b9c547cSRui Paulo 			locuri = oma_dm_get_target_locuri(ctx, child);
1059*5b9c547cSRui Paulo 			if (locuri == NULL)
1060*5b9c547cSRui Paulo 				res = DM_RESP_BAD_REQUEST;
1061*5b9c547cSRui Paulo 			add_status(ctx, syncbody, server_msgid, server_cmdid,
1062*5b9c547cSRui Paulo 				   cmdid, name, res, locuri);
1063*5b9c547cSRui Paulo 			os_free(locuri);
1064*5b9c547cSRui Paulo 			resp_needed = 1;
1065*5b9c547cSRui Paulo 		} else if (os_strcasecmp(name, "Add") == 0) {
1066*5b9c547cSRui Paulo 			int res = oma_dm_add(ctx, child, pps, pps_fname);
1067*5b9c547cSRui Paulo 			cmdid++;
1068*5b9c547cSRui Paulo 			locuri = oma_dm_get_target_locuri(ctx, child);
1069*5b9c547cSRui Paulo 			if (locuri == NULL)
1070*5b9c547cSRui Paulo 				res = DM_RESP_BAD_REQUEST;
1071*5b9c547cSRui Paulo 			add_status(ctx, syncbody, server_msgid, server_cmdid,
1072*5b9c547cSRui Paulo 				   cmdid, name, res, locuri);
1073*5b9c547cSRui Paulo 			os_free(locuri);
1074*5b9c547cSRui Paulo 			resp_needed = 1;
1075*5b9c547cSRui Paulo 		} else if (os_strcasecmp(name, "Replace") == 0) {
1076*5b9c547cSRui Paulo 			int res;
1077*5b9c547cSRui Paulo 			res = oma_dm_replace(ctx, child, pps, pps_fname);
1078*5b9c547cSRui Paulo 			cmdid++;
1079*5b9c547cSRui Paulo 			locuri = oma_dm_get_target_locuri(ctx, child);
1080*5b9c547cSRui Paulo 			if (locuri == NULL)
1081*5b9c547cSRui Paulo 				res = DM_RESP_BAD_REQUEST;
1082*5b9c547cSRui Paulo 			add_status(ctx, syncbody, server_msgid, server_cmdid,
1083*5b9c547cSRui Paulo 				   cmdid, name, res, locuri);
1084*5b9c547cSRui Paulo 			os_free(locuri);
1085*5b9c547cSRui Paulo 			resp_needed = 1;
1086*5b9c547cSRui Paulo 		} else if (os_strcasecmp(name, "Status") == 0) {
1087*5b9c547cSRui Paulo 			/* TODO: Verify success */
1088*5b9c547cSRui Paulo 		} else if (os_strcasecmp(name, "Get") == 0) {
1089*5b9c547cSRui Paulo 			int res;
1090*5b9c547cSRui Paulo 			char *value;
1091*5b9c547cSRui Paulo 			res = oma_dm_get(ctx, child, pps, pps_fname, &value);
1092*5b9c547cSRui Paulo 			cmdid++;
1093*5b9c547cSRui Paulo 			locuri = oma_dm_get_target_locuri(ctx, child);
1094*5b9c547cSRui Paulo 			if (locuri == NULL)
1095*5b9c547cSRui Paulo 				res = DM_RESP_BAD_REQUEST;
1096*5b9c547cSRui Paulo 			add_status(ctx, syncbody, server_msgid, server_cmdid,
1097*5b9c547cSRui Paulo 				   cmdid, name, res, locuri);
1098*5b9c547cSRui Paulo 			if (res == DM_RESP_OK && value) {
1099*5b9c547cSRui Paulo 				cmdid++;
1100*5b9c547cSRui Paulo 				add_results(ctx, syncbody, server_msgid,
1101*5b9c547cSRui Paulo 					    server_cmdid, cmdid, locuri, value);
1102*5b9c547cSRui Paulo 			}
1103*5b9c547cSRui Paulo 			os_free(locuri);
1104*5b9c547cSRui Paulo 			xml_node_get_text_free(ctx->xml, value);
1105*5b9c547cSRui Paulo 			resp_needed = 1;
1106*5b9c547cSRui Paulo #if 0 /* TODO: MUST support */
1107*5b9c547cSRui Paulo 		} else if (os_strcasecmp(name, "Delete") == 0) {
1108*5b9c547cSRui Paulo #endif
1109*5b9c547cSRui Paulo #if 0 /* TODO: MUST support */
1110*5b9c547cSRui Paulo 		} else if (os_strcasecmp(name, "Sequence") == 0) {
1111*5b9c547cSRui Paulo #endif
1112*5b9c547cSRui Paulo 		} else if (os_strcasecmp(name, "Final") == 0) {
1113*5b9c547cSRui Paulo 			final = 1;
1114*5b9c547cSRui Paulo 			break;
1115*5b9c547cSRui Paulo 		} else {
1116*5b9c547cSRui Paulo 			locuri = oma_dm_get_target_locuri(ctx, child);
1117*5b9c547cSRui Paulo 			add_status(ctx, syncbody, server_msgid, server_cmdid,
1118*5b9c547cSRui Paulo 				   cmdid, name, DM_RESP_COMMAND_NOT_IMPLEMENTED,
1119*5b9c547cSRui Paulo 				   locuri);
1120*5b9c547cSRui Paulo 			os_free(locuri);
1121*5b9c547cSRui Paulo 			resp_needed = 1;
1122*5b9c547cSRui Paulo 		}
1123*5b9c547cSRui Paulo 	}
1124*5b9c547cSRui Paulo 
1125*5b9c547cSRui Paulo 	if (!final) {
1126*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Final node not found");
1127*5b9c547cSRui Paulo 		xml_node_free(ctx->xml, syncml);
1128*5b9c547cSRui Paulo 		os_free(resp_uri);
1129*5b9c547cSRui Paulo 		return NULL;
1130*5b9c547cSRui Paulo 	}
1131*5b9c547cSRui Paulo 
1132*5b9c547cSRui Paulo 	if (!resp_needed) {
1133*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Exchange completed - no response needed");
1134*5b9c547cSRui Paulo 		xml_node_free(ctx->xml, syncml);
1135*5b9c547cSRui Paulo 		os_free(resp_uri);
1136*5b9c547cSRui Paulo 		return NULL;
1137*5b9c547cSRui Paulo 	}
1138*5b9c547cSRui Paulo 
1139*5b9c547cSRui Paulo 	xml_node_create(ctx->xml, syncbody, NULL, "Final");
1140*5b9c547cSRui Paulo 
1141*5b9c547cSRui Paulo 	debug_dump_node(ctx, "OMA-DM Package 3", syncml);
1142*5b9c547cSRui Paulo 
1143*5b9c547cSRui Paulo 	*ret_resp_uri = resp_uri;
1144*5b9c547cSRui Paulo 	return syncml;
1145*5b9c547cSRui Paulo }
1146*5b9c547cSRui Paulo 
1147*5b9c547cSRui Paulo 
1148*5b9c547cSRui Paulo int cmd_oma_dm_prov(struct hs20_osu_client *ctx, const char *url)
1149*5b9c547cSRui Paulo {
1150*5b9c547cSRui Paulo 	xml_node_t *syncml, *resp;
1151*5b9c547cSRui Paulo 	char *resp_uri = NULL;
1152*5b9c547cSRui Paulo 	int msgid = 0;
1153*5b9c547cSRui Paulo 
1154*5b9c547cSRui Paulo 	if (url == NULL) {
1155*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
1156*5b9c547cSRui Paulo 		return -1;
1157*5b9c547cSRui Paulo 	}
1158*5b9c547cSRui Paulo 
1159*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "OMA-DM credential provisioning requested");
1160*5b9c547cSRui Paulo 	write_summary(ctx, "OMA-DM credential provisioning");
1161*5b9c547cSRui Paulo 
1162*5b9c547cSRui Paulo 	msgid++;
1163*5b9c547cSRui Paulo 	syncml = build_oma_dm_1_sub_reg(ctx, url, msgid);
1164*5b9c547cSRui Paulo 	if (syncml == NULL)
1165*5b9c547cSRui Paulo 		return -1;
1166*5b9c547cSRui Paulo 
1167*5b9c547cSRui Paulo 	while (syncml) {
1168*5b9c547cSRui Paulo 		resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : url,
1169*5b9c547cSRui Paulo 					syncml, NULL, NULL, NULL, NULL, NULL);
1170*5b9c547cSRui Paulo 		if (resp == NULL)
1171*5b9c547cSRui Paulo 			return -1;
1172*5b9c547cSRui Paulo 
1173*5b9c547cSRui Paulo 		msgid++;
1174*5b9c547cSRui Paulo 		syncml = oma_dm_process(ctx, url, resp, msgid, &resp_uri,
1175*5b9c547cSRui Paulo 					NULL, NULL);
1176*5b9c547cSRui Paulo 		xml_node_free(ctx->xml, resp);
1177*5b9c547cSRui Paulo 	}
1178*5b9c547cSRui Paulo 
1179*5b9c547cSRui Paulo 	os_free(resp_uri);
1180*5b9c547cSRui Paulo 
1181*5b9c547cSRui Paulo 	return ctx->pps_cred_set ? 0 : -1;
1182*5b9c547cSRui Paulo }
1183*5b9c547cSRui Paulo 
1184*5b9c547cSRui Paulo 
1185*5b9c547cSRui Paulo int cmd_oma_dm_sim_prov(struct hs20_osu_client *ctx, const char *url)
1186*5b9c547cSRui Paulo {
1187*5b9c547cSRui Paulo 	xml_node_t *syncml, *resp;
1188*5b9c547cSRui Paulo 	char *resp_uri = NULL;
1189*5b9c547cSRui Paulo 	int msgid = 0;
1190*5b9c547cSRui Paulo 
1191*5b9c547cSRui Paulo 	if (url == NULL) {
1192*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
1193*5b9c547cSRui Paulo 		return -1;
1194*5b9c547cSRui Paulo 	}
1195*5b9c547cSRui Paulo 
1196*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "OMA-DM SIM provisioning requested");
1197*5b9c547cSRui Paulo 	ctx->no_reconnect = 2;
1198*5b9c547cSRui Paulo 
1199*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "Wait for IP address before starting SIM provisioning");
1200*5b9c547cSRui Paulo 	write_summary(ctx, "Wait for IP address before starting SIM provisioning");
1201*5b9c547cSRui Paulo 
1202*5b9c547cSRui Paulo 	if (wait_ip_addr(ctx->ifname, 15) < 0) {
1203*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway");
1204*5b9c547cSRui Paulo 	}
1205*5b9c547cSRui Paulo 	write_summary(ctx, "OMA-DM SIM provisioning");
1206*5b9c547cSRui Paulo 
1207*5b9c547cSRui Paulo 	msgid++;
1208*5b9c547cSRui Paulo 	syncml = build_oma_dm_1_sub_prov(ctx, url, msgid);
1209*5b9c547cSRui Paulo 	if (syncml == NULL)
1210*5b9c547cSRui Paulo 		return -1;
1211*5b9c547cSRui Paulo 
1212*5b9c547cSRui Paulo 	while (syncml) {
1213*5b9c547cSRui Paulo 		resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : url,
1214*5b9c547cSRui Paulo 					syncml, NULL, NULL, NULL, NULL, NULL);
1215*5b9c547cSRui Paulo 		if (resp == NULL)
1216*5b9c547cSRui Paulo 			return -1;
1217*5b9c547cSRui Paulo 
1218*5b9c547cSRui Paulo 		msgid++;
1219*5b9c547cSRui Paulo 		syncml = oma_dm_process(ctx, url, resp, msgid, &resp_uri,
1220*5b9c547cSRui Paulo 					NULL, NULL);
1221*5b9c547cSRui Paulo 		xml_node_free(ctx->xml, resp);
1222*5b9c547cSRui Paulo 	}
1223*5b9c547cSRui Paulo 
1224*5b9c547cSRui Paulo 	os_free(resp_uri);
1225*5b9c547cSRui Paulo 
1226*5b9c547cSRui Paulo 	if (ctx->pps_cred_set) {
1227*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
1228*5b9c547cSRui Paulo 		cmd_set_pps(ctx, ctx->pps_fname);
1229*5b9c547cSRui Paulo 
1230*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
1231*5b9c547cSRui Paulo 		write_summary(ctx, "Requesting reconnection with updated configuration");
1232*5b9c547cSRui Paulo 		if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) {
1233*5b9c547cSRui Paulo 			wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect");
1234*5b9c547cSRui Paulo 			write_summary(ctx, "Failed to request wpa_supplicant to reconnect");
1235*5b9c547cSRui Paulo 			return -1;
1236*5b9c547cSRui Paulo 		}
1237*5b9c547cSRui Paulo 	}
1238*5b9c547cSRui Paulo 
1239*5b9c547cSRui Paulo 	return ctx->pps_cred_set ? 0 : -1;
1240*5b9c547cSRui Paulo }
1241*5b9c547cSRui Paulo 
1242*5b9c547cSRui Paulo 
1243*5b9c547cSRui Paulo void oma_dm_pol_upd(struct hs20_osu_client *ctx, const char *address,
1244*5b9c547cSRui Paulo 		    const char *pps_fname,
1245*5b9c547cSRui Paulo 		    const char *client_cert, const char *client_key,
1246*5b9c547cSRui Paulo 		    const char *cred_username, const char *cred_password,
1247*5b9c547cSRui Paulo 		    xml_node_t *pps)
1248*5b9c547cSRui Paulo {
1249*5b9c547cSRui Paulo 	xml_node_t *syncml, *resp;
1250*5b9c547cSRui Paulo 	char *resp_uri = NULL;
1251*5b9c547cSRui Paulo 	int msgid = 0;
1252*5b9c547cSRui Paulo 
1253*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "OMA-DM policy update");
1254*5b9c547cSRui Paulo 	write_summary(ctx, "OMA-DM policy update");
1255*5b9c547cSRui Paulo 
1256*5b9c547cSRui Paulo 	msgid++;
1257*5b9c547cSRui Paulo 	syncml = build_oma_dm_1_pol_upd(ctx, address, msgid);
1258*5b9c547cSRui Paulo 	if (syncml == NULL)
1259*5b9c547cSRui Paulo 		return;
1260*5b9c547cSRui Paulo 
1261*5b9c547cSRui Paulo 	while (syncml) {
1262*5b9c547cSRui Paulo 		resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : address,
1263*5b9c547cSRui Paulo 					syncml, NULL, cred_username,
1264*5b9c547cSRui Paulo 					cred_password, client_cert, client_key);
1265*5b9c547cSRui Paulo 		if (resp == NULL)
1266*5b9c547cSRui Paulo 			return;
1267*5b9c547cSRui Paulo 
1268*5b9c547cSRui Paulo 		msgid++;
1269*5b9c547cSRui Paulo 		syncml = oma_dm_process(ctx, address, resp, msgid, &resp_uri,
1270*5b9c547cSRui Paulo 					pps, pps_fname);
1271*5b9c547cSRui Paulo 		xml_node_free(ctx->xml, resp);
1272*5b9c547cSRui Paulo 	}
1273*5b9c547cSRui Paulo 
1274*5b9c547cSRui Paulo 	os_free(resp_uri);
1275*5b9c547cSRui Paulo 
1276*5b9c547cSRui Paulo 	if (ctx->pps_updated) {
1277*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Update wpa_supplicant credential based on updated PPS MO");
1278*5b9c547cSRui Paulo 		write_summary(ctx, "Update wpa_supplicant credential based on updated PPS MO and request connection");
1279*5b9c547cSRui Paulo 		cmd_set_pps(ctx, pps_fname);
1280*5b9c547cSRui Paulo 		if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) {
1281*5b9c547cSRui Paulo 			wpa_printf(MSG_INFO,
1282*5b9c547cSRui Paulo 				   "Failed to request wpa_supplicant to reconnect");
1283*5b9c547cSRui Paulo 			write_summary(ctx,
1284*5b9c547cSRui Paulo 				      "Failed to request wpa_supplicant to reconnect");
1285*5b9c547cSRui Paulo 		}
1286*5b9c547cSRui Paulo 	}
1287*5b9c547cSRui Paulo }
1288*5b9c547cSRui Paulo 
1289*5b9c547cSRui Paulo 
1290*5b9c547cSRui Paulo void oma_dm_sub_rem(struct hs20_osu_client *ctx, const char *address,
1291*5b9c547cSRui Paulo 		    const char *pps_fname,
1292*5b9c547cSRui Paulo 		    const char *client_cert, const char *client_key,
1293*5b9c547cSRui Paulo 		    const char *cred_username, const char *cred_password,
1294*5b9c547cSRui Paulo 		    xml_node_t *pps)
1295*5b9c547cSRui Paulo {
1296*5b9c547cSRui Paulo 	xml_node_t *syncml, *resp;
1297*5b9c547cSRui Paulo 	char *resp_uri = NULL;
1298*5b9c547cSRui Paulo 	int msgid = 0;
1299*5b9c547cSRui Paulo 
1300*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "OMA-DM subscription remediation");
1301*5b9c547cSRui Paulo 	write_summary(ctx, "OMA-DM subscription remediation");
1302*5b9c547cSRui Paulo 
1303*5b9c547cSRui Paulo 	msgid++;
1304*5b9c547cSRui Paulo 	syncml = build_oma_dm_1_sub_rem(ctx, address, msgid);
1305*5b9c547cSRui Paulo 	if (syncml == NULL)
1306*5b9c547cSRui Paulo 		return;
1307*5b9c547cSRui Paulo 
1308*5b9c547cSRui Paulo 	while (syncml) {
1309*5b9c547cSRui Paulo 		resp = oma_dm_send_recv(ctx, resp_uri ? resp_uri : address,
1310*5b9c547cSRui Paulo 					syncml, NULL, cred_username,
1311*5b9c547cSRui Paulo 					cred_password, client_cert, client_key);
1312*5b9c547cSRui Paulo 		if (resp == NULL)
1313*5b9c547cSRui Paulo 			return;
1314*5b9c547cSRui Paulo 
1315*5b9c547cSRui Paulo 		msgid++;
1316*5b9c547cSRui Paulo 		syncml = oma_dm_process(ctx, address, resp, msgid, &resp_uri,
1317*5b9c547cSRui Paulo 					pps, pps_fname);
1318*5b9c547cSRui Paulo 		xml_node_free(ctx->xml, resp);
1319*5b9c547cSRui Paulo 	}
1320*5b9c547cSRui Paulo 
1321*5b9c547cSRui Paulo 	os_free(resp_uri);
1322*5b9c547cSRui Paulo 
1323*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "Update wpa_supplicant credential based on updated PPS MO and request reconnection");
1324*5b9c547cSRui Paulo 	write_summary(ctx, "Update wpa_supplicant credential based on updated PPS MO and request reconnection");
1325*5b9c547cSRui Paulo 	cmd_set_pps(ctx, pps_fname);
1326*5b9c547cSRui Paulo 	if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0) {
1327*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Failed to request wpa_supplicant to reconnect");
1328*5b9c547cSRui Paulo 		write_summary(ctx, "Failed to request wpa_supplicant to reconnect");
1329*5b9c547cSRui Paulo 	}
1330*5b9c547cSRui Paulo }
1331*5b9c547cSRui Paulo 
1332*5b9c547cSRui Paulo 
1333*5b9c547cSRui Paulo void cmd_oma_dm_add(struct hs20_osu_client *ctx, const char *pps_fname,
1334*5b9c547cSRui Paulo 		    const char *add_fname)
1335*5b9c547cSRui Paulo {
1336*5b9c547cSRui Paulo 	xml_node_t *pps, *add;
1337*5b9c547cSRui Paulo 	int res;
1338*5b9c547cSRui Paulo 
1339*5b9c547cSRui Paulo 	ctx->fqdn = os_strdup("wi-fi.org");
1340*5b9c547cSRui Paulo 
1341*5b9c547cSRui Paulo 	pps = node_from_file(ctx->xml, pps_fname);
1342*5b9c547cSRui Paulo 	if (pps == NULL) {
1343*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "PPS file %s could not be parsed",
1344*5b9c547cSRui Paulo 			   pps_fname);
1345*5b9c547cSRui Paulo 		return;
1346*5b9c547cSRui Paulo 	}
1347*5b9c547cSRui Paulo 
1348*5b9c547cSRui Paulo 	add = node_from_file(ctx->xml, add_fname);
1349*5b9c547cSRui Paulo 	if (add == NULL) {
1350*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Add file %s could not be parsed",
1351*5b9c547cSRui Paulo 			   add_fname);
1352*5b9c547cSRui Paulo 		xml_node_free(ctx->xml, pps);
1353*5b9c547cSRui Paulo 		return;
1354*5b9c547cSRui Paulo 	}
1355*5b9c547cSRui Paulo 
1356*5b9c547cSRui Paulo 	res = oma_dm_add(ctx, add, pps, pps_fname);
1357*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "oma_dm_add --> %d", res);
1358*5b9c547cSRui Paulo 
1359*5b9c547cSRui Paulo 	xml_node_free(ctx->xml, pps);
1360*5b9c547cSRui Paulo 	xml_node_free(ctx->xml, add);
1361*5b9c547cSRui Paulo }
1362*5b9c547cSRui Paulo 
1363*5b9c547cSRui Paulo 
1364*5b9c547cSRui Paulo void cmd_oma_dm_replace(struct hs20_osu_client *ctx, const char *pps_fname,
1365*5b9c547cSRui Paulo 			const char *replace_fname)
1366*5b9c547cSRui Paulo {
1367*5b9c547cSRui Paulo 	xml_node_t *pps, *replace;
1368*5b9c547cSRui Paulo 	int res;
1369*5b9c547cSRui Paulo 
1370*5b9c547cSRui Paulo 	ctx->fqdn = os_strdup("wi-fi.org");
1371*5b9c547cSRui Paulo 
1372*5b9c547cSRui Paulo 	pps = node_from_file(ctx->xml, pps_fname);
1373*5b9c547cSRui Paulo 	if (pps == NULL) {
1374*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "PPS file %s could not be parsed",
1375*5b9c547cSRui Paulo 			   pps_fname);
1376*5b9c547cSRui Paulo 		return;
1377*5b9c547cSRui Paulo 	}
1378*5b9c547cSRui Paulo 
1379*5b9c547cSRui Paulo 	replace = node_from_file(ctx->xml, replace_fname);
1380*5b9c547cSRui Paulo 	if (replace == NULL) {
1381*5b9c547cSRui Paulo 		wpa_printf(MSG_INFO, "Replace file %s could not be parsed",
1382*5b9c547cSRui Paulo 			   replace_fname);
1383*5b9c547cSRui Paulo 		xml_node_free(ctx->xml, pps);
1384*5b9c547cSRui Paulo 		return;
1385*5b9c547cSRui Paulo 	}
1386*5b9c547cSRui Paulo 
1387*5b9c547cSRui Paulo 	res = oma_dm_replace(ctx, replace, pps, pps_fname);
1388*5b9c547cSRui Paulo 	wpa_printf(MSG_INFO, "oma_dm_replace --> %d", res);
1389*5b9c547cSRui Paulo 
1390*5b9c547cSRui Paulo 	xml_node_free(ctx->xml, pps);
1391*5b9c547cSRui Paulo 	xml_node_free(ctx->xml, replace);
1392*5b9c547cSRui Paulo }
1393