int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid, const char *pin) { u8 u[UUID_LEN]; int any = 0; if (hapd->wps == NULL) return -1; if (os_strcmp(uuid, "any") == 0) any = 1; else if (uuid_str2bin(uuid, u)) return -1; return wps_registrar_add_pin(hapd->wps->registrar, any ? NULL : u, (const u8 *) pin, os_strlen(pin)); }
static int wpa_config_read_global_uuid(struct wpa_config *config, HKEY hk) { char *str; int ret = 0; str = wpa_config_read_reg_string(hk, TEXT("uuid")); if (str == NULL) return 0; if (uuid_str2bin(str, config->uuid)) ret = -1; os_free(str); return ret; }
int wpas_wps_er_set_config(struct wpa_supplicant *wpa_s, const char *uuid, int id) { u8 u[UUID_LEN]; struct wpa_ssid *ssid; struct wps_credential cred; if (uuid_str2bin(uuid, u)) return -1; ssid = wpa_config_get_network(wpa_s->conf, id); if (ssid == NULL || ssid->ssid == NULL) return -1; os_memset(&cred, 0, sizeof(cred)); if (ssid->ssid_len > 32) return -1; os_memcpy(cred.ssid, ssid->ssid, ssid->ssid_len); cred.ssid_len = ssid->ssid_len; if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) { cred.auth_type = (ssid->proto & WPA_PROTO_RSN) ? WPS_AUTH_WPA2PSK : WPS_AUTH_WPAPSK; if (ssid->pairwise_cipher & WPA_CIPHER_CCMP) cred.encr_type = WPS_ENCR_AES; else cred.encr_type = WPS_ENCR_TKIP; if (ssid->passphrase) { cred.key_len = os_strlen(ssid->passphrase); if (cred.key_len >= 64) return -1; os_memcpy(cred.key, ssid->passphrase, cred.key_len); } else if (ssid->psk_set) { cred.key_len = 32; os_memcpy(cred.key, ssid->psk, 32); } else return -1; } else { cred.auth_type = WPS_AUTH_OPEN; cred.encr_type = WPS_ENCR_NONE; } return wps_er_set_config(wpa_s->wps_er, u, &cred); }
int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr, const char *uuid, const char *pin, int timeout) { u8 u[UUID_LEN]; struct wps_add_pin_data data; data.addr = addr; data.uuid = u; data.pin = (const u8 *) pin; data.pin_len = os_strlen(pin); data.timeout = timeout; data.added = 0; if (os_strcmp(uuid, "any") == 0) data.uuid = NULL; else { if (uuid_str2bin(uuid, u)) return -1; data.uuid = u; } if (hostapd_wps_for_each(hapd, wps_add_pin, &data) < 0) return -1; return data.added ? 0 : -1; }
/* Given that we have received a header w/ SUBSCRIBE, act upon it * * Format of SUBSCRIBE (case-insensitive): * * First line must be: * SUBSCRIBE /wps_event HTTP/1.1 * * Our response (if no error) which includes only required lines is: * HTTP/1.1 200 OK * Server: xx, UPnP/1.0, xx * SID: uuid:xxxxxxxxx * Timeout: Second-<n> * Content-Length: 0 * Date: xxxx * * Header lines must end with \r\n * Per RFC 2616, content-length: is not required but connection:close * would appear to be required (given that we will be closing it!). */ static void web_connection_parse_subscribe(struct upnp_wps_device_sm *sm, struct http_request *req, const char *filename) { struct wpabuf *buf; char *b; char *hdr = http_request_get_hdr(req); char *h; char *match; int match_len; char *end; int len; int got_nt = 0; u8 uuid[UUID_LEN]; int got_uuid = 0; char *callback_urls = NULL; struct subscription *s = NULL; enum http_reply_code ret = HTTP_INTERNAL_SERVER_ERROR; buf = wpabuf_alloc(1000); if (buf == NULL) { http_request_deinit(req); return; } wpa_hexdump_ascii(MSG_DEBUG, "WPS UPnP: HTTP SUBSCRIBE", (u8 *) hdr, os_strlen(hdr)); /* Parse/validate headers */ h = hdr; /* First line: SUBSCRIBE /wps_event HTTP/1.1 * has already been parsed. */ if (os_strcasecmp(filename, UPNP_WPS_DEVICE_EVENT_FILE) != 0) { ret = HTTP_PRECONDITION_FAILED; goto error; } wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP SUBSCRIBE for event"); end = os_strchr(h, '\n'); while (end) { /* Option line by option line */ h = end + 1; end = os_strchr(h, '\n'); if (end == NULL) break; /* no unterminated lines allowed */ /* NT assures that it is our type of subscription; * not used for a renewal. **/ match = "NT:"; match_len = os_strlen(match); if (os_strncasecmp(h, match, match_len) == 0) { h += match_len; while (*h == ' ' || *h == '\t') h++; match = "upnp:event"; match_len = os_strlen(match); if (os_strncasecmp(h, match, match_len) != 0) { ret = HTTP_BAD_REQUEST; goto error; } got_nt = 1; continue; } /* HOST should refer to us */ #if 0 match = "HOST:"; match_len = os_strlen(match); if (os_strncasecmp(h, match, match_len) == 0) { h += match_len; while (*h == ' ' || *h == '\t') h++; ..... } #endif /* CALLBACK gives one or more URLs for NOTIFYs * to be sent as a result of the subscription. * Each URL is enclosed in angle brackets. */ match = "CALLBACK:"; match_len = os_strlen(match); if (os_strncasecmp(h, match, match_len) == 0) { h += match_len; while (*h == ' ' || *h == '\t') h++; len = end - h; os_free(callback_urls); callback_urls = dup_binstr(h, len); if (callback_urls == NULL) { ret = HTTP_INTERNAL_SERVER_ERROR; goto error; } if (len > 0 && callback_urls[len - 1] == '\r') callback_urls[len - 1] = '\0'; continue; } /* SID is only for renewal */ match = "SID:"; match_len = os_strlen(match); if (os_strncasecmp(h, match, match_len) == 0) { h += match_len; while (*h == ' ' || *h == '\t') h++; match = "uuid:"; match_len = os_strlen(match); if (os_strncasecmp(h, match, match_len) != 0) { ret = HTTP_BAD_REQUEST; goto error; } h += match_len; while (*h == ' ' || *h == '\t') h++; if (uuid_str2bin(h, uuid)) { ret = HTTP_BAD_REQUEST; goto error; } got_uuid = 1; continue; } /* TIMEOUT is requested timeout, but apparently we can * just ignore this. */ }
static void wps_er_ssdp_rx(int sd, void *eloop_ctx, void *sock_ctx) { struct wps_er *er = eloop_ctx; struct sockaddr_in addr; /* client address */ socklen_t addr_len; int nread; char buf[MULTICAST_MAX_READ], *pos, *pos2, *start; int wfa = 0, byebye = 0; int max_age = -1; char *location = NULL; u8 uuid[WPS_UUID_LEN]; addr_len = sizeof(addr); nread = recvfrom(sd, buf, sizeof(buf) - 1, 0, (struct sockaddr *) &addr, &addr_len); if (nread <= 0) return; buf[nread] = '\0'; if (er->filter_addr.s_addr && er->filter_addr.s_addr != addr.sin_addr.s_addr) return; wpa_printf(MSG_DEBUG, "WPS ER: Received SSDP from %s", inet_ntoa(addr.sin_addr)); wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Received SSDP contents", (u8 *) buf, nread); if (sd == er->multicast_sd) { /* Reply to M-SEARCH */ if (os_strncmp(buf, "HTTP/1.1 200 OK", 15) != 0) return; /* unexpected response header */ } else { /* Unsolicited message (likely NOTIFY or M-SEARCH) */ if (os_strncmp(buf, "NOTIFY ", 7) != 0) return; /* only process notifications */ } os_memset(uuid, 0, sizeof(uuid)); for (start = buf; start && *start; start = pos) { pos = os_strchr(start, '\n'); if (pos) { if (pos[-1] == '\r') pos[-1] = '\0'; *pos++ = '\0'; } if (os_strstr(start, "schemas-wifialliance-org:device:" "WFADevice:1")) wfa = 1; if (os_strstr(start, "schemas-wifialliance-org:service:" "WFAWLANConfig:1")) wfa = 1; if (os_strncasecmp(start, "LOCATION:", 9) == 0) { start += 9; while (*start == ' ') start++; location = start; } else if (os_strncasecmp(start, "NTS:", 4) == 0) { if (os_strstr(start, "ssdp:byebye")) byebye = 1; } else if (os_strncasecmp(start, "CACHE-CONTROL:", 14) == 0) { start += 9; while (*start == ' ') start++; pos2 = os_strstr(start, "max-age="); if (pos2 == NULL) continue; pos2 += 8; max_age = atoi(pos2); } else if (os_strncasecmp(start, "USN:", 4) == 0) { start += 4; pos2 = os_strstr(start, "uuid:"); if (pos2) { pos2 += 5; while (*pos2 == ' ') pos2++; if (uuid_str2bin(pos2, uuid) < 0) { wpa_printf(MSG_DEBUG, "WPS ER: " "Invalid UUID in USN: %s", pos2); return; } } } } if (!wfa) return; /* Not WPS advertisement/reply */ if (byebye) { wps_er_ap_remove(er, &addr.sin_addr); return; } if (!location) return; /* Unknown location */ if (max_age < 1) return; /* No max-age reported */ wpa_printf(MSG_DEBUG, "WPS ER: AP discovered: %s " "(packet source: %s max-age: %d)", location, inet_ntoa(addr.sin_addr), max_age); wps_er_ap_add(er, uuid, &addr.sin_addr, location, max_age); }
int main(int argc, char **argv) { uint8_t anuuid[16]; uint8_t anuuid2[16]; uuid_str2bin(NOT_NIL_UUID_STR, anuuid); fprintf(stderr, "%s cmp %02x%02x%02x%02x-%02x%02x-%02x%02x-" "%02x%02x-%02x%02x%02x%02x%02x%02x\n", NOT_NIL_UUID_STR, anuuid[0], anuuid[1], anuuid[2], anuuid[3], anuuid[4], anuuid[5], anuuid[6], anuuid[7], anuuid[8], anuuid[9], anuuid[10], anuuid[11], anuuid[12], anuuid[13], anuuid[14], anuuid[15]); uuid_str2bin(NOT_NIL_UUID_STR2, anuuid2); fprintf(stderr, "%s cmp %02x%02x%02x%02x-%02x%02x-%02x%02x-" "%02x%02x-%02x%02x%02x%02x%02x%02x\n", NOT_NIL_UUID_STR2, anuuid2[0], anuuid2[1], anuuid2[2], anuuid2[3], anuuid2[4], anuuid2[5], anuuid2[6], anuuid2[7], anuuid2[8], anuuid2[9], anuuid2[10], anuuid2[11], anuuid2[12], anuuid2[13], anuuid2[14], anuuid2[15]); /* * uuid_is_nil with nil UUID */ uint8_t nilUUID[16] = NIL_UUID; char nilUUIDstr[40]; n_tests++; if (uuid_bin2str(nilUUID, nilUUIDstr, 40) < 0) { fprintf(stderr, "Failure\n"); goto skip1; } char isnil = uuid_is_nil(nilUUID); if (isnil) n_tests_passed++; else n_tests_failed++; printf("%s is nil? %s <%s>\n", nilUUIDstr, isnil ? "YES" : "NO", isnil ? "passed" : "failed" ); skip1: { /* * uuid_is_nil with not nil UUID */ uint8_t notNilUUID[16] = NOT_NIL_UUID; char notNilUUIDstr[40]; n_tests++; if (uuid_bin2str(notNilUUID, notNilUUIDstr, 40) < 0) { fprintf(stderr, "Failure\n"); goto skip2; } char isnil = uuid_is_nil(notNilUUID); if (!isnil) n_tests_passed++; else n_tests_failed++; printf("%s is nil? %s <%s>\n", notNilUUIDstr, isnil ? "YES" : "NO", isnil ? "failed" : "passed" ); } skip2: { /* * uuid_cmp with one nil UUID */ uint8_t nilUUID[16] = NIL_UUID; char nilUUIDstr[40]; uint8_t notNilUUID[16] = NOT_NIL_UUID; char notNilUUIDstr[40]; n_tests++; if (uuid_bin2str(nilUUID, nilUUIDstr, 40) < 0) { fprintf(stderr, "Failure\n"); goto skip3; } n_tests++; if (uuid_bin2str(notNilUUID, notNilUUIDstr, 40) < 0) { fprintf(stderr, "Failure\n"); goto skip3; } int8_t cmpval1 = uuid_cmp(notNilUUID, nilUUID); int8_t cmpval2 = uuid_cmp(nilUUID, notNilUUID); if (cmpval1 + cmpval2 == 0 && cmpval1 != 0) n_tests_passed+=2; else n_tests_failed+=2; printf("%s cmp %s = %d <%s>\n", notNilUUIDstr, nilUUIDstr, cmpval1, cmpval1 ? "passed" : "failed" ); printf("%s cmp %s = %d <%s>\n", nilUUIDstr, notNilUUIDstr, cmpval2, cmpval2 ? "passed" : "failed" ); } skip3: { /* * uuid_cmp with both nil UUID */ uint8_t nilUUID1[16] = NIL_UUID; char nilUUID1str[40]; uint8_t nilUUID2[16] = NIL_UUID; char nilUUID2str[40]; n_tests++; if (uuid_bin2str(nilUUID1, nilUUID1str, 40) < 0) { fprintf(stderr, "Failure\n"); goto skip4; } n_tests++; if (uuid_bin2str(nilUUID2, nilUUID2str, 40) < 0) { fprintf(stderr, "Failure\n"); goto skip4; } int8_t cmpval1 = uuid_cmp(nilUUID1, nilUUID2); int8_t cmpval2 = uuid_cmp(nilUUID2, nilUUID1); if (cmpval1 == cmpval2 && cmpval1 == 0) n_tests_passed+=2; else n_tests_failed+=2; printf("%s cmp %s = %d <%s>\n", nilUUID1str, nilUUID2str, cmpval1, cmpval1 ? "failed" : "passed" ); printf("%s cmp %s = %d <%s>\n", nilUUID2str, nilUUID1str, cmpval2, cmpval2 ? "failed" : "passed" ); } skip4: { /* * uuid_cmp with both not nil UUID */ uint8_t notNilUUID1[16] = NOT_NIL_UUID; char notNilUUID1str[40]; uint8_t notNilUUID2[16] = NOT_NIL_UUID; char notNilUUID2str[40]; n_tests++; if (uuid_bin2str(notNilUUID1, notNilUUID1str, 40) < 0) { fprintf(stderr, "Failure\n"); goto skip5; } n_tests++; if (uuid_bin2str(notNilUUID2, notNilUUID2str, 40) < 0) { fprintf(stderr, "Failure\n"); goto skip5; } int8_t cmpval1 = uuid_cmp(notNilUUID1, notNilUUID2); int8_t cmpval2 = uuid_cmp(notNilUUID2, notNilUUID1); if (cmpval1 == cmpval2 && cmpval1 == 0) n_tests_passed+=2; else n_tests_failed+=2; printf("%s cmp %s = %d <%s>\n", notNilUUID1str, notNilUUID2str, cmpval1, cmpval1 ? "failed" : "passed" ); printf("%s cmp %s = %d <%s>\n", notNilUUID2str, notNilUUID1str, cmpval2, cmpval2 ? "failed" : "passed" ); } skip5: { /* * uuid_cmp with both not nil UUID */ uint8_t notNilUUID1[16] = NOT_NIL_UUID; char notNilUUID1str[40]; uint8_t notNilUUID2[16] = NOT_NIL_UUID2; char notNilUUID2str[40]; n_tests++; if (uuid_bin2str(notNilUUID1, notNilUUID1str, 40) < 0) { fprintf(stderr, "Failure\n"); goto skip6; } n_tests++; if (uuid_bin2str(notNilUUID2, notNilUUID2str, 40) < 0) { fprintf(stderr, "Failure\n"); goto skip6; } int8_t cmpval1 = uuid_cmp(notNilUUID1, notNilUUID2); int8_t cmpval2 = uuid_cmp(notNilUUID2, notNilUUID1); if (cmpval1 + cmpval2 == 0 && cmpval1 != 0) n_tests_passed+=2; else n_tests_failed+=2; printf("%s cmp %s = %d <%s>\n", notNilUUID1str, notNilUUID2str, cmpval1, cmpval1 ? "passed" : "failed" ); printf("%s cmp %s = %d <%s>\n", notNilUUID2str, notNilUUID1str, cmpval2, cmpval2 ? "passed" : "failed" ); } skip6: { /* * uuid_cmp with one nil UUID */ uint8_t nilUUID[16]; char nilUUIDstr[40] = NIL_UUID_STR; uint8_t notNilUUID[16]; char notNilUUIDstr[40] = NOT_NIL_UUID_STR; n_tests++; if (uuid_str2bin(nilUUIDstr, nilUUID) < 0) { fprintf(stderr, "Failure\n"); goto skip7; } n_tests++; if (uuid_str2bin(notNilUUIDstr, notNilUUID) < 0) { fprintf(stderr, "Failure\n"); goto skip7; } int8_t cmpval1 = uuid_cmp(notNilUUID, nilUUID); int8_t cmpval2 = uuid_cmp(nilUUID, notNilUUID); if (cmpval1 + cmpval2 == 0 && cmpval1 != 0) n_tests_passed+=2; else n_tests_failed+=2; printf("%s cmp %s = %d <%s>\n", notNilUUIDstr, nilUUIDstr, cmpval1, cmpval1 ? "passed" : "failed" ); printf("%s cmp %s = %d <%s>\n", nilUUIDstr, notNilUUIDstr, cmpval2, cmpval2 ? "passed" : "failed" ); } skip7: { /* * uuid_cmp with both nil UUID */ uint8_t nilUUID1[16]; char nilUUID1str[40] = NIL_UUID_STR; uint8_t nilUUID2[16]; char nilUUID2str[40] = NIL_UUID_STR; n_tests++; if (uuid_str2bin(nilUUID1str, nilUUID1) < 0) { fprintf(stderr, "Failure\n"); goto skip8; } n_tests++; if (uuid_str2bin(nilUUID2str, nilUUID2) < 0) { fprintf(stderr, "Failure\n"); goto skip8; } int8_t cmpval1 = uuid_cmp(nilUUID1, nilUUID2); int8_t cmpval2 = uuid_cmp(nilUUID2, nilUUID1); if (cmpval1 == cmpval2 && cmpval1 == 0) n_tests_passed+=2; else n_tests_failed+=2; printf("%s cmp %s = %d <%s>\n", nilUUID1str, nilUUID2str, cmpval1, cmpval1 ? "failed" : "passed" ); printf("%s cmp %s = %d <%s>\n", nilUUID2str, nilUUID1str, cmpval2, cmpval2 ? "failed" : "passed" ); } skip8: { /* * uuid_cmp with both not nil UUID */ uint8_t notNilUUID1[16]; char notNilUUID1str[40] = NOT_NIL_UUID_STR; uint8_t notNilUUID2[16]; char notNilUUID2str[40] = NOT_NIL_UUID_STR; n_tests++; if (uuid_str2bin(notNilUUID1str, notNilUUID1) < 0) { fprintf(stderr, "Failure\n"); goto skip9; } n_tests++; if (uuid_str2bin(notNilUUID2str, notNilUUID2) < 0) { fprintf(stderr, "Failure\n"); goto skip9; } int8_t cmpval1 = uuid_cmp(notNilUUID1, notNilUUID2); int8_t cmpval2 = uuid_cmp(notNilUUID2, notNilUUID1); if (cmpval1 == cmpval2 && cmpval1 == 0) n_tests_passed+=2; else n_tests_failed+=2; printf("%s cmp %s = %d <%s>\n", notNilUUID1str, notNilUUID2str, cmpval1, cmpval1 ? "failed" : "passed" ); printf("%s cmp %s = %d <%s>\n", notNilUUID2str, notNilUUID1str, cmpval2, cmpval2 ? "failed" : "passed" ); } skip9: { /* * uuid_cmp with both not nil UUID */ uint8_t notNilUUID1[16]; char notNilUUID1str[40] = NOT_NIL_UUID_STR; uint8_t notNilUUID2[16]; char notNilUUID2str[40] = NOT_NIL_UUID_STR2; n_tests++; if (uuid_str2bin(notNilUUID1str, notNilUUID1) < 0) { fprintf(stderr, "Failure\n"); goto skip10; } n_tests++; if (uuid_str2bin(notNilUUID2str, notNilUUID2) < 0) { fprintf(stderr, "Failure\n"); goto skip10; } int8_t cmpval1 = uuid_cmp(notNilUUID1, notNilUUID2); int8_t cmpval2 = uuid_cmp(notNilUUID2, notNilUUID1); if (cmpval1 + cmpval2 == 0 && cmpval1 != 0) n_tests_passed+=2; else n_tests_failed+=2; printf("%s cmp %s = %d <%s>\n", notNilUUID1str, notNilUUID2str, cmpval1, cmpval1 ? "passed" : "failed" ); printf("%s cmp %s = %d <%s>\n", notNilUUID2str, notNilUUID1str, cmpval2, cmpval2 ? "passed" : "failed" ); } skip10: summary: { fprintf(stderr, "\n\n********************************************************\n" "Number of tests: %d / passed: %d / failed: %d / skipped: %d\n", n_tests, n_tests_passed, n_tests_failed, n_tests - (n_tests_passed+n_tests_failed)); } return 0; }
static void wps_er_parse_device_description(struct wps_er_ap *ap, struct wpabuf *reply) { /* Note: reply includes null termination after the buffer data */ const char *tmp, *data = wpabuf_head(reply); char *pos; wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Device info", wpabuf_head(reply), wpabuf_len(reply)); /* * The root device description may include multiple devices, so first * find the beginning of the WFADevice description to allow the * simplistic parser to pick the correct entries. */ tmp = wps_er_find_wfadevice(data); if (tmp == NULL) { wpa_printf(MSG_DEBUG, "WPS ER: WFADevice:1 device not found - " "trying to parse invalid data"); } else data = tmp; ap->friendly_name = xml_get_first_item(data, "friendlyName"); wpa_printf(MSG_DEBUG, "WPS ER: friendlyName='%s'", ap->friendly_name); ap->manufacturer = xml_get_first_item(data, "manufacturer"); wpa_printf(MSG_DEBUG, "WPS ER: manufacturer='%s'", ap->manufacturer); ap->manufacturer_url = xml_get_first_item(data, "manufacturerURL"); wpa_printf(MSG_DEBUG, "WPS ER: manufacturerURL='%s'", ap->manufacturer_url); ap->model_description = xml_get_first_item(data, "modelDescription"); wpa_printf(MSG_DEBUG, "WPS ER: modelDescription='%s'", ap->model_description); ap->model_name = xml_get_first_item(data, "modelName"); wpa_printf(MSG_DEBUG, "WPS ER: modelName='%s'", ap->model_name); ap->model_number = xml_get_first_item(data, "modelNumber"); wpa_printf(MSG_DEBUG, "WPS ER: modelNumber='%s'", ap->model_number); ap->model_url = xml_get_first_item(data, "modelURL"); wpa_printf(MSG_DEBUG, "WPS ER: modelURL='%s'", ap->model_url); ap->serial_number = xml_get_first_item(data, "serialNumber"); wpa_printf(MSG_DEBUG, "WPS ER: serialNumber='%s'", ap->serial_number); ap->udn = xml_get_first_item(data, "UDN"); wpa_printf(MSG_DEBUG, "WPS ER: UDN='%s'", ap->udn); pos = os_strstr(ap->udn, "uuid:"); if (pos) { pos += 5; if (uuid_str2bin(pos, ap->uuid) < 0) wpa_printf(MSG_DEBUG, "WPS ER: Invalid UUID in UDN"); } ap->upc = xml_get_first_item(data, "UPC"); wpa_printf(MSG_DEBUG, "WPS ER: UPC='%s'", ap->upc); ap->scpd_url = http_link_update( xml_get_first_item(data, "SCPDURL"), ap->location); wpa_printf(MSG_DEBUG, "WPS ER: SCPDURL='%s'", ap->scpd_url); ap->control_url = http_link_update( xml_get_first_item(data, "controlURL"), ap->location); wpa_printf(MSG_DEBUG, "WPS ER: controlURL='%s'", ap->control_url); ap->event_sub_url = http_link_update( xml_get_first_item(data, "eventSubURL"), ap->location); wpa_printf(MSG_DEBUG, "WPS ER: eventSubURL='%s'", ap->event_sub_url); }