+ os_free(ap);
+}
+
+
+static void wps_er_ap_unsubscribed(struct wps_er *er, struct wps_er_ap *ap)
+{
+ wpa_printf(MSG_DEBUG, "WPS ER: Unsubscribed from AP %s (%s)",
+ inet_ntoa(ap->addr), ap->location);
+ dl_list_del(&ap->list);
+ wps_er_ap_free(ap);
+
+ if (er->deinitializing && dl_list_empty(&er->ap_unsubscribing)) {
+ eloop_cancel_timeout(wps_er_deinit_finish, er, NULL);
+ wps_er_deinit_finish(er, NULL);
+ }
+}
+
+
+static void wps_er_http_unsubscribe_cb(void *ctx, struct http_client *c,
+ enum http_client_event event)
+{
+ struct wps_er_ap *ap = ctx;
+
+ switch (event) {
+ case HTTP_CLIENT_OK:
+ wpa_printf(MSG_DEBUG, "WPS ER: Unsubscribed from events");
+ ap->subscribed = 0;
+ break;
+ case HTTP_CLIENT_FAILED:
+ case HTTP_CLIENT_INVALID_REPLY:
+ case HTTP_CLIENT_TIMEOUT:
+ wpa_printf(MSG_DEBUG, "WPS ER: Failed to unsubscribe from "
+ "events");
+ break;
+ }
+ http_client_free(ap->http);
+ ap->http = NULL;
+
+ /*
+ * Need to get rid of the AP entry regardless of whether we managed to
+ * unsubscribe cleanly or not.
+ */
+ wps_er_ap_unsubscribed(ap->er, ap);
+}
+
+
+static void wps_er_ap_unsubscribe(struct wps_er *er, struct wps_er_ap *ap)
+{
+ struct wpabuf *req;
+ struct sockaddr_in dst;
+ char *url, *path;
+ char sid[100];
+
+ if (ap->event_sub_url == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS ER: No eventSubURL - cannot "
+ "subscribe");
+ goto fail;
+ }
+ if (ap->http) {
+ wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request - cannot "
+ "send subscribe request");
+ goto fail;
+ }
+
+ url = http_client_url_parse(ap->event_sub_url, &dst, &path);
+ if (url == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse eventSubURL");
+ goto fail;
+ }
+
+ req = wpabuf_alloc(os_strlen(ap->event_sub_url) + 1000);
+ if (req == NULL) {
+ os_free(url);
+ goto fail;
+ }
+ uuid_bin2str(ap->sid, sid, sizeof(sid));
+ wpabuf_printf(req,
+ "UNSUBSCRIBE %s HTTP/1.1\r\n"
+ "HOST: %s:%d\r\n"
+ "SID: uuid:%s\r\n"
+ "\r\n",
+ path, inet_ntoa(dst.sin_addr), ntohs(dst.sin_port), sid);
+ os_free(url);
+ wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Unsubscription request",
+ wpabuf_head(req), wpabuf_len(req));
+
+ ap->http = http_client_addr(&dst, req, 1000,
+ wps_er_http_unsubscribe_cb, ap);
+ if (ap->http == NULL) {
+ wpabuf_free(req);
+ goto fail;
+ }
+ return;
+
+fail:
+ /*
+ * Need to get rid of the AP entry even when we fail to unsubscribe
+ * cleanly.
+ */
+ wps_er_ap_unsubscribed(ap->er, ap);
+}
+
+static void wps_er_ap_remove_entry(struct wps_er *er, struct wps_er_ap *ap)
+{
+ wpa_printf(MSG_DEBUG, "WPS ER: Removing AP entry for %s (%s)",
+ inet_ntoa(ap->addr), ap->location);
+ eloop_cancel_timeout(wps_er_ap_timeout, er, ap);