2 * Hotspot 2.0 SPP client
3 * Copyright (c) 2012-2014, Qualcomm Atheros, Inc.
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
15 #include "wpa_helpers.h"
16 #include "xml-utils.h"
17 #include "http-utils.h"
18 #include "utils/base64.h"
19 #include "crypto/crypto.h"
20 #include "crypto/sha256.h"
21 #include "osu_client.h"
24 extern const char *spp_xsd_fname;
26 static int hs20_spp_update_response(struct hs20_osu_client *ctx,
27 const char *session_id,
28 const char *spp_status,
29 const char *error_code);
30 static void hs20_policy_update_complete(
31 struct hs20_osu_client *ctx, const char *pps_fname);
34 static char * get_spp_attr_value(struct xml_node_ctx *ctx, xml_node_t *node,
37 return xml_node_get_attr_value_ns(ctx, node, SPP_NS_URI, attr_name);
41 static int hs20_spp_validate(struct hs20_osu_client *ctx, xml_node_t *node,
42 const char *expected_name)
44 struct xml_node_ctx *xctx = ctx->xml;
49 if (!xml_node_is_element(xctx, node))
52 name = xml_node_get_localname(xctx, node);
56 if (strcmp(expected_name, name) != 0) {
57 wpa_printf(MSG_INFO, "Unexpected SOAP method name '%s' (expected '%s')",
59 write_summary(ctx, "Unexpected SOAP method name '%s' (expected '%s')",
64 ret = xml_validate(xctx, node, spp_xsd_fname, &err);
66 wpa_printf(MSG_INFO, "XML schema validation error(s)\n%s", err);
67 write_summary(ctx, "SPP XML schema validation failed");
74 static void add_mo_container(struct xml_node_ctx *ctx, xml_namespace_t *ns,
75 xml_node_t *parent, const char *urn,
79 xml_node_t *fnode, *tnds;
83 fnode = node_from_file(ctx, fname);
86 "Failed to create XML node from file: %s, possible error: %s",
87 fname, strerror(errno));
90 tnds = mo_to_tnds(ctx, fnode, 0, urn, "syncml:dmddf1.2");
91 xml_node_free(ctx, fnode);
95 str = xml_node_to_str(ctx, tnds);
96 xml_node_free(ctx, tnds);
100 node = xml_node_create_text(ctx, parent, ns, "moContainer", str);
102 xml_node_add_attr(ctx, node, ns, "moURN", urn);
107 static xml_node_t * build_spp_post_dev_data(struct hs20_osu_client *ctx,
108 xml_namespace_t **ret_ns,
109 const char *session_id,
113 xml_node_t *spp_node;
115 write_summary(ctx, "Building sppPostDevData requestReason='%s'",
117 spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
119 if (spp_node == NULL)
124 xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
125 xml_node_add_attr(ctx->xml, spp_node, NULL, "requestReason", reason);
127 xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID",
129 xml_node_add_attr(ctx->xml, spp_node, NULL, "redirectURI",
130 "http://localhost:12345/");
132 xml_node_create_text(ctx->xml, spp_node, ns, "supportedSPPVersions",
134 xml_node_create_text(ctx->xml, spp_node, ns, "supportedMOList",
135 URN_HS20_PPS " " URN_OMA_DM_DEVINFO " "
136 URN_OMA_DM_DEVDETAIL " " URN_HS20_DEVDETAIL_EXT);
138 add_mo_container(ctx->xml, ns, spp_node, URN_OMA_DM_DEVINFO,
140 add_mo_container(ctx->xml, ns, spp_node, URN_OMA_DM_DEVDETAIL,
147 static int process_update_node(struct hs20_osu_client *ctx, xml_node_t *pps,
150 xml_node_t *node, *parent, *tnds, *unode;
154 char *cdata, *cdata_end;
157 wpa_printf(MSG_INFO, "Processing updateNode");
158 debug_dump_node(ctx, "updateNode", update);
160 uri = get_spp_attr_value(ctx->xml, update, "managementTreeURI");
162 wpa_printf(MSG_INFO, "No managementTreeURI present");
165 wpa_printf(MSG_INFO, "managementTreeUri: '%s'", uri);
167 name = os_strrchr(uri, '/');
169 wpa_printf(MSG_INFO, "Unexpected URI");
170 xml_node_get_attr_value_free(ctx->xml, uri);
174 wpa_printf(MSG_INFO, "Update interior node: '%s'", name);
176 str = xml_node_get_text(ctx->xml, update);
178 wpa_printf(MSG_INFO, "Could not extract MO text");
179 xml_node_get_attr_value_free(ctx->xml, uri);
182 wpa_printf(MSG_DEBUG, "[hs20] nodeContainer text: '%s'", str);
183 cdata = strstr(str, "<![CDATA[");
184 cdata_end = strstr(str, "]]>");
185 if (cdata && cdata_end && cdata_end > cdata &&
186 cdata < strstr(str, "MgmtTree") &&
187 cdata_end > strstr(str, "/MgmtTree")) {
189 wpa_printf(MSG_DEBUG, "[hs20] Removing extra CDATA container");
190 tmp = strdup(cdata + 9);
192 cdata_end = strstr(tmp, "]]>");
195 wpa_printf(MSG_DEBUG, "[hs20] nodeContainer text with CDATA container removed: '%s'",
197 tnds = xml_node_from_buf(ctx->xml, tmp);
202 tnds = xml_node_from_buf(ctx->xml, str);
203 xml_node_get_text_free(ctx->xml, str);
205 wpa_printf(MSG_INFO, "[hs20] Could not parse nodeContainer text");
206 xml_node_get_attr_value_free(ctx->xml, uri);
210 unode = tnds_to_mo(ctx->xml, tnds);
211 xml_node_free(ctx->xml, tnds);
213 wpa_printf(MSG_INFO, "[hs20] Could not parse nodeContainer TNDS text");
214 xml_node_get_attr_value_free(ctx->xml, uri);
218 debug_dump_node(ctx, "Parsed TNDS", unode);
220 if (get_node_uri(ctx->xml, unode, name) == NULL) {
221 wpa_printf(MSG_INFO, "[hs20] %s node not found", name);
222 xml_node_free(ctx->xml, unode);
223 xml_node_get_attr_value_free(ctx->xml, uri);
227 if (os_strncasecmp(uri, "./Wi-Fi/", 8) != 0) {
228 wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi");
229 xml_node_free(ctx->xml, unode);
230 xml_node_get_attr_value_free(ctx->xml, uri);
235 if (ctx->fqdn == NULL) {
236 wpa_printf(MSG_INFO, "FQDN not known");
237 xml_node_free(ctx->xml, unode);
238 xml_node_get_attr_value_free(ctx->xml, uri);
241 fqdn_len = os_strlen(ctx->fqdn);
242 if (os_strncasecmp(pos, ctx->fqdn, fqdn_len) != 0 ||
243 pos[fqdn_len] != '/') {
244 wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi/%s",
246 xml_node_free(ctx->xml, unode);
247 xml_node_get_attr_value_free(ctx->xml, uri);
252 if (os_strncasecmp(pos, "PerProviderSubscription/", 24) != 0) {
253 wpa_printf(MSG_INFO, "Do not allow update outside ./Wi-Fi/%s/PerProviderSubscription",
255 xml_node_free(ctx->xml, unode);
256 xml_node_get_attr_value_free(ctx->xml, uri);
261 wpa_printf(MSG_INFO, "Update command for PPS node %s", pos);
263 node = get_node(ctx->xml, pps, pos);
265 parent = xml_node_get_parent(ctx->xml, node);
266 xml_node_detach(ctx->xml, node);
267 wpa_printf(MSG_INFO, "Replace '%s' node", name);
270 pos2 = os_strrchr(pos, '/');
275 parent = get_node(ctx->xml, pps, pos);
277 if (parent == NULL) {
278 wpa_printf(MSG_INFO, "Could not find parent %s", pos);
279 xml_node_free(ctx->xml, unode);
280 xml_node_get_attr_value_free(ctx->xml, uri);
283 wpa_printf(MSG_INFO, "Add '%s' node", name);
285 xml_node_add_child(ctx->xml, parent, unode);
287 xml_node_get_attr_value_free(ctx->xml, uri);
293 static int update_pps(struct hs20_osu_client *ctx, xml_node_t *update,
294 const char *pps_fname, xml_node_t *pps)
296 wpa_printf(MSG_INFO, "Updating PPS based on updateNode element(s)");
297 xml_node_for_each_sibling(ctx->xml, update) {
298 xml_node_for_each_check(ctx->xml, update);
299 if (process_update_node(ctx, pps, update) < 0)
303 return update_pps_file(ctx, pps_fname, pps);
307 static void hs20_sub_rem_complete(struct hs20_osu_client *ctx,
308 const char *pps_fname)
311 * Update wpa_supplicant credentials and reconnect using updated
314 wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
315 cmd_set_pps(ctx, pps_fname);
317 if (ctx->no_reconnect)
320 wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
321 if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0)
322 wpa_printf(MSG_ERROR, "Failed to request wpa_supplicant to reconnect");
326 static xml_node_t * hs20_spp_upload_mo(struct hs20_osu_client *ctx,
328 const char *session_id,
329 const char *pps_fname)
332 xml_node_t *node, *ret_node;
335 urn = get_spp_attr_value(ctx->xml, cmd, "moURN");
337 wpa_printf(MSG_INFO, "No URN included");
340 wpa_printf(MSG_INFO, "Upload MO request - URN=%s", urn);
341 if (strcasecmp(urn, URN_HS20_PPS) != 0) {
342 wpa_printf(MSG_INFO, "Unsupported moURN");
343 xml_node_get_attr_value_free(ctx->xml, urn);
346 xml_node_get_attr_value_free(ctx->xml, urn);
349 wpa_printf(MSG_INFO, "PPS file name no known");
353 node = build_spp_post_dev_data(ctx, &ns, session_id,
357 add_mo_container(ctx->xml, ns, node, URN_HS20_PPS, pps_fname);
359 ret_node = soap_send_receive(ctx->http, node);
360 if (ret_node == NULL)
363 debug_dump_node(ctx, "Received response to MO upload", ret_node);
365 if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
366 wpa_printf(MSG_INFO, "SPP validation failed");
367 xml_node_free(ctx->xml, ret_node);
375 static int hs20_add_mo(struct hs20_osu_client *ctx, xml_node_t *add_mo,
376 char *fname, size_t fname_len)
381 debug_dump_node(ctx, "Received addMO", add_mo);
383 urn = get_spp_attr_value(ctx->xml, add_mo, "moURN");
385 wpa_printf(MSG_INFO, "[hs20] No moURN in addMO");
388 wpa_printf(MSG_INFO, "addMO - moURN: '%s'", urn);
389 if (strcasecmp(urn, URN_HS20_PPS) != 0) {
390 wpa_printf(MSG_INFO, "[hs20] Unsupported MO in addMO");
391 xml_node_get_attr_value_free(ctx->xml, urn);
394 xml_node_get_attr_value_free(ctx->xml, urn);
396 uri = get_spp_attr_value(ctx->xml, add_mo, "managementTreeURI");
398 wpa_printf(MSG_INFO, "[hs20] No managementTreeURI in addMO");
401 wpa_printf(MSG_INFO, "addMO - managementTreeURI: '%s'", uri);
403 ret = hs20_add_pps_mo(ctx, uri, add_mo, fname, fname_len);
404 xml_node_get_attr_value_free(ctx->xml, uri);
409 static int process_spp_user_input_response(struct hs20_osu_client *ctx,
410 const char *session_id,
416 debug_dump_node(ctx, "addMO", add_mo);
418 wpa_printf(MSG_INFO, "Subscription registration completed");
420 if (hs20_add_mo(ctx, add_mo, fname, sizeof(fname)) < 0) {
421 wpa_printf(MSG_INFO, "Could not add MO");
422 ret = hs20_spp_update_response(
425 "MO addition or update failed");
429 ret = hs20_spp_update_response(ctx, session_id, "OK", NULL);
431 hs20_sub_rem_complete(ctx, fname);
437 static xml_node_t * hs20_spp_user_input_completed(struct hs20_osu_client *ctx,
438 const char *session_id)
440 xml_node_t *node, *ret_node;
442 node = build_spp_post_dev_data(ctx, NULL, session_id,
443 "User input completed");
447 ret_node = soap_send_receive(ctx->http, node);
449 if (soap_reinit_client(ctx->http) < 0)
451 wpa_printf(MSG_INFO, "Try to finish with re-opened connection");
452 node = build_spp_post_dev_data(ctx, NULL, session_id,
453 "User input completed");
456 ret_node = soap_send_receive(ctx->http, node);
457 if (ret_node == NULL)
459 wpa_printf(MSG_INFO, "Continue with new connection");
462 if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
463 wpa_printf(MSG_INFO, "SPP validation failed");
464 xml_node_free(ctx->xml, ret_node);
472 static xml_node_t * hs20_spp_get_certificate(struct hs20_osu_client *ctx,
474 const char *session_id,
475 const char *pps_fname)
478 xml_node_t *node, *ret_node;
481 wpa_printf(MSG_INFO, "Client certificate enrollment");
483 res = osu_get_certificate(ctx, cmd);
485 wpa_printf(MSG_INFO, "EST simpleEnroll failed");
487 node = build_spp_post_dev_data(ctx, &ns, session_id,
489 "Certificate enrollment completed" :
490 "Certificate enrollment failed");
494 ret_node = soap_send_receive(ctx->http, node);
495 if (ret_node == NULL)
498 debug_dump_node(ctx, "Received response to certificate enrollment "
499 "completed", ret_node);
501 if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
502 wpa_printf(MSG_INFO, "SPP validation failed");
503 xml_node_free(ctx->xml, ret_node);
511 static int hs20_spp_exec(struct hs20_osu_client *ctx, xml_node_t *exec,
512 const char *session_id, const char *pps_fname,
513 xml_node_t *pps, xml_node_t **ret_node)
518 char *id = strdup(session_id);
525 debug_dump_node(ctx, "exec", exec);
527 xml_node_for_each_child(ctx->xml, cmd, exec) {
528 xml_node_for_each_check(ctx->xml, cmd);
532 wpa_printf(MSG_INFO, "exec command element not found (cmd=%p)",
538 name = xml_node_get_localname(ctx->xml, cmd);
540 if (strcasecmp(name, "launchBrowserToURI") == 0) {
542 uri = xml_node_get_text(ctx->xml, cmd);
544 wpa_printf(MSG_INFO, "No URI found");
548 wpa_printf(MSG_INFO, "Launch browser to URI '%s'", uri);
549 write_summary(ctx, "Launch browser to URI '%s'", uri);
550 res = hs20_web_browser(uri);
551 xml_node_get_text_free(ctx->xml, uri);
553 wpa_printf(MSG_INFO, "User response in browser completed successfully - sessionid='%s'",
555 write_summary(ctx, "User response in browser completed successfully");
556 *ret_node = hs20_spp_user_input_completed(ctx, id);
558 return *ret_node ? 0 : -1;
560 wpa_printf(MSG_INFO, "Failed to receive user response");
561 write_summary(ctx, "Failed to receive user response");
562 hs20_spp_update_response(
563 ctx, id, "Error occurred", "Other");
570 if (strcasecmp(name, "uploadMO") == 0) {
571 if (pps_fname == NULL)
573 *ret_node = hs20_spp_upload_mo(ctx, cmd, id,
576 return *ret_node ? 0 : -1;
579 if (strcasecmp(name, "getCertificate") == 0) {
580 *ret_node = hs20_spp_get_certificate(ctx, cmd, id,
583 return *ret_node ? 0 : -1;
586 wpa_printf(MSG_INFO, "Unsupported exec command: '%s'", name);
592 enum spp_post_dev_data_use {
593 SPP_SUBSCRIPTION_REMEDIATION,
595 SPP_SUBSCRIPTION_REGISTRATION,
598 static void process_spp_post_dev_data_response(
599 struct hs20_osu_client *ctx,
600 enum spp_post_dev_data_use use, xml_node_t *node,
601 const char *pps_fname, xml_node_t *pps)
605 xml_node_t *update = NULL, *exec = NULL, *add_mo = NULL, *no_mo = NULL;
606 char *session_id = NULL;
608 debug_dump_node(ctx, "sppPostDevDataResponse node", node);
610 status = get_spp_attr_value(ctx->xml, node, "sppStatus");
611 if (status == NULL) {
612 wpa_printf(MSG_INFO, "No sppStatus attribute");
615 write_summary(ctx, "Received sppPostDevDataResponse sppStatus='%s'",
618 session_id = get_spp_attr_value(ctx->xml, node, "sessionID");
619 if (session_id == NULL) {
620 wpa_printf(MSG_INFO, "No sessionID attribute");
624 wpa_printf(MSG_INFO, "[hs20] sppPostDevDataResponse - sppStatus: '%s' sessionID: '%s'",
627 xml_node_for_each_child(ctx->xml, child, node) {
629 xml_node_for_each_check(ctx->xml, child);
630 debug_dump_node(ctx, "child", child);
631 name = xml_node_get_localname(ctx->xml, child);
632 wpa_printf(MSG_INFO, "localname: '%s'", name);
633 if (!update && strcasecmp(name, "updateNode") == 0)
635 if (!exec && strcasecmp(name, "exec") == 0)
637 if (!add_mo && strcasecmp(name, "addMO") == 0)
639 if (!no_mo && strcasecmp(name, "noMOUpdate") == 0)
643 if (use == SPP_SUBSCRIPTION_REMEDIATION &&
645 "Remediation complete, request sppUpdateResponse") == 0)
648 if (!update && !no_mo) {
649 wpa_printf(MSG_INFO, "No updateNode or noMOUpdate element");
652 wpa_printf(MSG_INFO, "Subscription remediation completed");
653 res = update_pps(ctx, update, pps_fname, pps);
655 wpa_printf(MSG_INFO, "Failed to update PPS MO");
656 ret = hs20_spp_update_response(
658 res < 0 ? "Error occurred" : "OK",
659 res < 0 ? "MO addition or update failed" : NULL);
660 if (res == 0 && ret == 0)
661 hs20_sub_rem_complete(ctx, pps_fname);
665 if (use == SPP_SUBSCRIPTION_REMEDIATION &&
666 strcasecmp(status, "Exchange complete, release TLS connection") ==
669 wpa_printf(MSG_INFO, "No noMOUpdate element");
672 wpa_printf(MSG_INFO, "Subscription remediation completed (no MO update)");
676 if (use == SPP_POLICY_UPDATE &&
677 strcasecmp(status, "Update complete, request sppUpdateResponse") ==
680 wpa_printf(MSG_INFO, "Policy update received - update PPS");
681 res = update_pps(ctx, update, pps_fname, pps);
682 ret = hs20_spp_update_response(
684 res < 0 ? "Error occurred" : "OK",
685 res < 0 ? "MO addition or update failed" : NULL);
686 if (res == 0 && ret == 0)
687 hs20_policy_update_complete(ctx, pps_fname);
691 if (use == SPP_SUBSCRIPTION_REGISTRATION &&
692 strcasecmp(status, "Provisioning complete, request "
693 "sppUpdateResponse") == 0) {
695 wpa_printf(MSG_INFO, "No addMO element - not sure what to do next");
698 process_spp_user_input_response(ctx, session_id, add_mo);
703 if (strcasecmp(status, "No update available at this time") == 0) {
704 wpa_printf(MSG_INFO, "No update available at this time");
708 if (strcasecmp(status, "OK") == 0) {
713 wpa_printf(MSG_INFO, "No exec element - not sure what to do next");
716 res = hs20_spp_exec(ctx, exec, session_id,
717 pps_fname, pps, &ret);
718 /* xml_node_free(ctx->xml, node); */
721 process_spp_post_dev_data_response(ctx, use,
722 ret, pps_fname, pps);
726 if (strcasecmp(status, "Error occurred") == 0) {
729 err = get_node(ctx->xml, node, "sppError");
731 code = xml_node_get_attr_value(ctx->xml, err,
733 wpa_printf(MSG_INFO, "Error occurred - errorCode=%s",
734 code ? code : "N/A");
735 xml_node_get_attr_value_free(ctx->xml, code);
740 "[hs20] Unsupported sppPostDevDataResponse sppStatus '%s'",
743 xml_node_get_attr_value_free(ctx->xml, status);
744 xml_node_get_attr_value_free(ctx->xml, session_id);
745 xml_node_free(ctx->xml, node);
749 static int spp_post_dev_data(struct hs20_osu_client *ctx,
750 enum spp_post_dev_data_use use,
752 const char *pps_fname, xml_node_t *pps)
755 xml_node_t *ret_node;
757 payload = build_spp_post_dev_data(ctx, NULL, NULL, reason);
761 ret_node = soap_send_receive(ctx->http, payload);
763 const char *err = http_get_err(ctx->http);
765 wpa_printf(MSG_INFO, "HTTP error: %s", err);
766 write_result(ctx, "HTTP error: %s", err);
768 write_summary(ctx, "Failed to send SOAP message");
773 if (hs20_spp_validate(ctx, ret_node, "sppPostDevDataResponse") < 0) {
774 wpa_printf(MSG_INFO, "SPP validation failed");
775 xml_node_free(ctx->xml, ret_node);
779 process_spp_post_dev_data_response(ctx, use, ret_node,
785 void spp_sub_rem(struct hs20_osu_client *ctx, const char *address,
786 const char *pps_fname,
787 const char *client_cert, const char *client_key,
788 const char *cred_username, const char *cred_password,
791 wpa_printf(MSG_INFO, "SPP subscription remediation");
792 write_summary(ctx, "SPP subscription remediation");
794 os_free(ctx->server_url);
795 ctx->server_url = os_strdup(address);
797 if (soap_init_client(ctx->http, address, ctx->ca_fname,
798 cred_username, cred_password, client_cert,
800 spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REMEDIATION,
801 "Subscription remediation", pps_fname, pps);
806 static void hs20_policy_update_complete(struct hs20_osu_client *ctx,
807 const char *pps_fname)
809 wpa_printf(MSG_INFO, "Policy update completed");
812 * Update wpa_supplicant credentials and reconnect using updated
815 wpa_printf(MSG_INFO, "Updating wpa_supplicant credentials");
816 cmd_set_pps(ctx, pps_fname);
818 wpa_printf(MSG_INFO, "Requesting reconnection with updated configuration");
819 if (wpa_command(ctx->ifname, "INTERWORKING_SELECT auto") < 0)
820 wpa_printf(MSG_ERROR, "Failed to request wpa_supplicant to reconnect");
824 static int process_spp_exchange_complete(struct hs20_osu_client *ctx,
827 char *status, *session_id;
829 debug_dump_node(ctx, "sppExchangeComplete", node);
831 status = get_spp_attr_value(ctx->xml, node, "sppStatus");
832 if (status == NULL) {
833 wpa_printf(MSG_INFO, "No sppStatus attribute");
836 write_summary(ctx, "Received sppExchangeComplete sppStatus='%s'",
839 session_id = get_spp_attr_value(ctx->xml, node, "sessionID");
840 if (session_id == NULL) {
841 wpa_printf(MSG_INFO, "No sessionID attribute");
842 xml_node_get_attr_value_free(ctx->xml, status);
846 wpa_printf(MSG_INFO, "[hs20] sppStatus: '%s' sessionID: '%s'",
848 xml_node_get_attr_value_free(ctx->xml, session_id);
850 if (strcasecmp(status, "Exchange complete, release TLS connection") ==
852 xml_node_get_attr_value_free(ctx->xml, status);
856 wpa_printf(MSG_INFO, "Unexpected sppStatus '%s'", status);
857 write_summary(ctx, "Unexpected sppStatus '%s'", status);
858 xml_node_get_attr_value_free(ctx->xml, status);
863 static xml_node_t * build_spp_update_response(struct hs20_osu_client *ctx,
864 const char *session_id,
865 const char *spp_status,
866 const char *error_code)
869 xml_node_t *spp_node, *node;
871 spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns,
872 "sppUpdateResponse");
873 if (spp_node == NULL)
876 xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0");
877 xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id);
878 xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", spp_status);
881 node = xml_node_create(ctx->xml, spp_node, ns, "sppError");
883 xml_node_add_attr(ctx->xml, node, NULL, "errorCode",
891 static int hs20_spp_update_response(struct hs20_osu_client *ctx,
892 const char *session_id,
893 const char *spp_status,
894 const char *error_code)
896 xml_node_t *node, *ret_node;
899 write_summary(ctx, "Building sppUpdateResponse sppStatus='%s' error_code='%s'",
900 spp_status, error_code);
901 node = build_spp_update_response(ctx, session_id, spp_status,
905 ret_node = soap_send_receive(ctx->http, node);
907 if (soap_reinit_client(ctx->http) < 0)
909 wpa_printf(MSG_INFO, "Try to finish with re-opened connection");
910 node = build_spp_update_response(ctx, session_id, spp_status,
914 ret_node = soap_send_receive(ctx->http, node);
915 if (ret_node == NULL)
917 wpa_printf(MSG_INFO, "Continue with new connection");
920 if (hs20_spp_validate(ctx, ret_node, "sppExchangeComplete") < 0) {
921 wpa_printf(MSG_INFO, "SPP validation failed");
922 xml_node_free(ctx->xml, ret_node);
926 ret = process_spp_exchange_complete(ctx, ret_node);
927 xml_node_free(ctx->xml, ret_node);
932 void spp_pol_upd(struct hs20_osu_client *ctx, const char *address,
933 const char *pps_fname,
934 const char *client_cert, const char *client_key,
935 const char *cred_username, const char *cred_password,
938 wpa_printf(MSG_INFO, "SPP policy update");
939 write_summary(ctx, "SPP policy update");
941 os_free(ctx->server_url);
942 ctx->server_url = os_strdup(address);
944 if (soap_init_client(ctx->http, address, ctx->ca_fname, cred_username,
945 cred_password, client_cert, client_key) == 0) {
946 spp_post_dev_data(ctx, SPP_POLICY_UPDATE, "Policy update",
952 int cmd_prov(struct hs20_osu_client *ctx, const char *url)
954 unlink("Cert/est_cert.der");
955 unlink("Cert/est_cert.pem");
958 wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
963 "Credential provisioning requested - URL: %s ca_fname: %s",
964 url, ctx->ca_fname ? ctx->ca_fname : "N/A");
966 os_free(ctx->server_url);
967 ctx->server_url = os_strdup(url);
969 if (soap_init_client(ctx->http, url, ctx->ca_fname, NULL, NULL, NULL,
972 spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REGISTRATION,
973 "Subscription registration", NULL, NULL);
975 return ctx->pps_cred_set ? 0 : -1;
979 int cmd_sim_prov(struct hs20_osu_client *ctx, const char *url)
982 wpa_printf(MSG_INFO, "Invalid prov command (missing URL)");
986 wpa_printf(MSG_INFO, "SIM provisioning requested");
988 os_free(ctx->server_url);
989 ctx->server_url = os_strdup(url);
991 wpa_printf(MSG_INFO, "Wait for IP address before starting SIM provisioning");
993 if (wait_ip_addr(ctx->ifname, 15) < 0) {
994 wpa_printf(MSG_INFO, "Could not get IP address for WLAN - try connection anyway");
997 if (soap_init_client(ctx->http, url, ctx->ca_fname, NULL, NULL, NULL,
1000 spp_post_dev_data(ctx, SPP_SUBSCRIPTION_REGISTRATION,
1001 "Subscription provisioning", NULL, NULL);
1003 return ctx->pps_cred_set ? 0 : -1;