1214501Srpaulo/* 2214501Srpaulo * Wi-Fi Protected Setup - External Registrar 3252726Srpaulo * Copyright (c) 2009-2012, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7214501Srpaulo */ 8214501Srpaulo 9214501Srpaulo#include "includes.h" 10214501Srpaulo 11214501Srpaulo#include "common.h" 12214501Srpaulo#include "base64.h" 13214501Srpaulo#include "uuid.h" 14214501Srpaulo#include "eloop.h" 15214501Srpaulo#include "httpread.h" 16214501Srpaulo#include "http_client.h" 17214501Srpaulo#include "http_server.h" 18214501Srpaulo#include "upnp_xml.h" 19214501Srpaulo#include "wps_i.h" 20214501Srpaulo#include "wps_upnp.h" 21214501Srpaulo#include "wps_upnp_i.h" 22214501Srpaulo#include "wps_er.h" 23214501Srpaulo 24214501Srpaulo 25214501Srpaulostatic void wps_er_deinit_finish(void *eloop_data, void *user_ctx); 26214501Srpaulostatic void wps_er_ap_timeout(void *eloop_data, void *user_ctx); 27214501Srpaulostatic void wps_er_sta_timeout(void *eloop_data, void *user_ctx); 28214501Srpaulostatic void wps_er_ap_process(struct wps_er_ap *ap, struct wpabuf *msg); 29214501Srpaulostatic int wps_er_send_get_device_info(struct wps_er_ap *ap, 30214501Srpaulo void (*m1_handler)(struct wps_er_ap *ap, 31214501Srpaulo struct wpabuf *m1)); 32214501Srpaulo 33214501Srpaulo 34214501Srpaulostatic void wps_er_sta_event(struct wps_context *wps, struct wps_er_sta *sta, 35214501Srpaulo enum wps_event event) 36214501Srpaulo{ 37214501Srpaulo union wps_event_data data; 38214501Srpaulo struct wps_event_er_enrollee *ev = &data.enrollee; 39214501Srpaulo 40214501Srpaulo if (wps->event_cb == NULL) 41214501Srpaulo return; 42214501Srpaulo 43214501Srpaulo os_memset(&data, 0, sizeof(data)); 44214501Srpaulo ev->uuid = sta->uuid; 45214501Srpaulo ev->mac_addr = sta->addr; 46214501Srpaulo ev->m1_received = sta->m1_received; 47214501Srpaulo ev->config_methods = sta->config_methods; 48214501Srpaulo ev->dev_passwd_id = sta->dev_passwd_id; 49214501Srpaulo ev->pri_dev_type = sta->pri_dev_type; 50214501Srpaulo ev->dev_name = sta->dev_name; 51214501Srpaulo ev->manufacturer = sta->manufacturer; 52214501Srpaulo ev->model_name = sta->model_name; 53214501Srpaulo ev->model_number = sta->model_number; 54214501Srpaulo ev->serial_number = sta->serial_number; 55214501Srpaulo wps->event_cb(wps->cb_ctx, event, &data); 56214501Srpaulo} 57214501Srpaulo 58214501Srpaulo 59252726Srpaulostatic struct wps_er_sta * wps_er_sta_get(struct wps_er_ap *ap, const u8 *addr, 60252726Srpaulo const u8 *uuid) 61214501Srpaulo{ 62214501Srpaulo struct wps_er_sta *sta; 63214501Srpaulo dl_list_for_each(sta, &ap->sta, struct wps_er_sta, list) { 64252726Srpaulo if ((addr == NULL || 65252726Srpaulo os_memcmp(sta->addr, addr, ETH_ALEN) == 0) && 66252726Srpaulo (uuid == NULL || 67252726Srpaulo os_memcmp(uuid, sta->uuid, WPS_UUID_LEN) == 0)) 68214501Srpaulo return sta; 69214501Srpaulo } 70214501Srpaulo return NULL; 71214501Srpaulo} 72214501Srpaulo 73214501Srpaulo 74214501Srpaulostatic void wps_er_sta_free(struct wps_er_sta *sta) 75214501Srpaulo{ 76214501Srpaulo wps_er_sta_event(sta->ap->er->wps, sta, WPS_EV_ER_ENROLLEE_REMOVE); 77214501Srpaulo if (sta->wps) 78214501Srpaulo wps_deinit(sta->wps); 79214501Srpaulo os_free(sta->manufacturer); 80214501Srpaulo os_free(sta->model_name); 81214501Srpaulo os_free(sta->model_number); 82214501Srpaulo os_free(sta->serial_number); 83214501Srpaulo os_free(sta->dev_name); 84214501Srpaulo http_client_free(sta->http); 85214501Srpaulo eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL); 86214501Srpaulo os_free(sta->cred); 87214501Srpaulo os_free(sta); 88214501Srpaulo} 89214501Srpaulo 90214501Srpaulo 91214501Srpaulostatic void wps_er_sta_remove_all(struct wps_er_ap *ap) 92214501Srpaulo{ 93214501Srpaulo struct wps_er_sta *prev, *sta; 94214501Srpaulo dl_list_for_each_safe(sta, prev, &ap->sta, struct wps_er_sta, list) 95214501Srpaulo wps_er_sta_free(sta); 96214501Srpaulo} 97214501Srpaulo 98214501Srpaulo 99214501Srpaulostatic struct wps_er_ap * wps_er_ap_get(struct wps_er *er, 100214501Srpaulo struct in_addr *addr, const u8 *uuid) 101214501Srpaulo{ 102214501Srpaulo struct wps_er_ap *ap; 103214501Srpaulo dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) { 104214501Srpaulo if ((addr == NULL || ap->addr.s_addr == addr->s_addr) && 105214501Srpaulo (uuid == NULL || 106214501Srpaulo os_memcmp(uuid, ap->uuid, WPS_UUID_LEN) == 0)) 107214501Srpaulo return ap; 108214501Srpaulo } 109214501Srpaulo return NULL; 110214501Srpaulo} 111214501Srpaulo 112214501Srpaulo 113214501Srpaulostatic struct wps_er_ap * wps_er_ap_get_id(struct wps_er *er, unsigned int id) 114214501Srpaulo{ 115214501Srpaulo struct wps_er_ap *ap; 116214501Srpaulo dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) { 117214501Srpaulo if (ap->id == id) 118214501Srpaulo return ap; 119214501Srpaulo } 120214501Srpaulo return NULL; 121214501Srpaulo} 122214501Srpaulo 123214501Srpaulo 124214501Srpaulostatic void wps_er_ap_event(struct wps_context *wps, struct wps_er_ap *ap, 125214501Srpaulo enum wps_event event) 126214501Srpaulo{ 127214501Srpaulo union wps_event_data data; 128214501Srpaulo struct wps_event_er_ap *evap = &data.ap; 129214501Srpaulo 130214501Srpaulo if (wps->event_cb == NULL) 131214501Srpaulo return; 132214501Srpaulo 133214501Srpaulo os_memset(&data, 0, sizeof(data)); 134214501Srpaulo evap->uuid = ap->uuid; 135214501Srpaulo evap->friendly_name = ap->friendly_name; 136214501Srpaulo evap->manufacturer = ap->manufacturer; 137214501Srpaulo evap->manufacturer_url = ap->manufacturer_url; 138214501Srpaulo evap->model_description = ap->model_description; 139214501Srpaulo evap->model_name = ap->model_name; 140214501Srpaulo evap->model_number = ap->model_number; 141214501Srpaulo evap->model_url = ap->model_url; 142214501Srpaulo evap->serial_number = ap->serial_number; 143214501Srpaulo evap->upc = ap->upc; 144214501Srpaulo evap->pri_dev_type = ap->pri_dev_type; 145214501Srpaulo evap->wps_state = ap->wps_state; 146214501Srpaulo evap->mac_addr = ap->mac_addr; 147214501Srpaulo wps->event_cb(wps->cb_ctx, event, &data); 148214501Srpaulo} 149214501Srpaulo 150214501Srpaulo 151214501Srpaulostatic void wps_er_ap_free(struct wps_er_ap *ap) 152214501Srpaulo{ 153214501Srpaulo http_client_free(ap->http); 154214501Srpaulo ap->http = NULL; 155214501Srpaulo 156214501Srpaulo os_free(ap->location); 157214501Srpaulo os_free(ap->friendly_name); 158214501Srpaulo os_free(ap->manufacturer); 159214501Srpaulo os_free(ap->manufacturer_url); 160214501Srpaulo os_free(ap->model_description); 161214501Srpaulo os_free(ap->model_name); 162214501Srpaulo os_free(ap->model_number); 163214501Srpaulo os_free(ap->model_url); 164214501Srpaulo os_free(ap->serial_number); 165214501Srpaulo os_free(ap->udn); 166214501Srpaulo os_free(ap->upc); 167214501Srpaulo 168214501Srpaulo os_free(ap->scpd_url); 169214501Srpaulo os_free(ap->control_url); 170214501Srpaulo os_free(ap->event_sub_url); 171214501Srpaulo 172214501Srpaulo os_free(ap->ap_settings); 173214501Srpaulo 174214501Srpaulo os_free(ap); 175214501Srpaulo} 176214501Srpaulo 177214501Srpaulo 178214501Srpaulostatic void wps_er_ap_unsubscribed(struct wps_er *er, struct wps_er_ap *ap) 179214501Srpaulo{ 180214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Unsubscribed from AP %s (%s)", 181214501Srpaulo inet_ntoa(ap->addr), ap->location); 182214501Srpaulo dl_list_del(&ap->list); 183214501Srpaulo wps_er_ap_free(ap); 184214501Srpaulo 185214501Srpaulo if (er->deinitializing && dl_list_empty(&er->ap_unsubscribing)) { 186214501Srpaulo eloop_cancel_timeout(wps_er_deinit_finish, er, NULL); 187214501Srpaulo wps_er_deinit_finish(er, NULL); 188214501Srpaulo } 189214501Srpaulo} 190214501Srpaulo 191214501Srpaulo 192214501Srpaulostatic void wps_er_http_unsubscribe_cb(void *ctx, struct http_client *c, 193214501Srpaulo enum http_client_event event) 194214501Srpaulo{ 195214501Srpaulo struct wps_er_ap *ap = ctx; 196214501Srpaulo 197214501Srpaulo switch (event) { 198214501Srpaulo case HTTP_CLIENT_OK: 199214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Unsubscribed from events"); 200214501Srpaulo ap->subscribed = 0; 201214501Srpaulo break; 202214501Srpaulo case HTTP_CLIENT_FAILED: 203214501Srpaulo case HTTP_CLIENT_INVALID_REPLY: 204214501Srpaulo case HTTP_CLIENT_TIMEOUT: 205214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Failed to unsubscribe from " 206214501Srpaulo "events"); 207214501Srpaulo break; 208214501Srpaulo } 209214501Srpaulo http_client_free(ap->http); 210214501Srpaulo ap->http = NULL; 211214501Srpaulo 212214501Srpaulo /* 213214501Srpaulo * Need to get rid of the AP entry regardless of whether we managed to 214214501Srpaulo * unsubscribe cleanly or not. 215214501Srpaulo */ 216214501Srpaulo wps_er_ap_unsubscribed(ap->er, ap); 217214501Srpaulo} 218214501Srpaulo 219214501Srpaulo 220214501Srpaulostatic void wps_er_ap_unsubscribe(struct wps_er *er, struct wps_er_ap *ap) 221214501Srpaulo{ 222214501Srpaulo struct wpabuf *req; 223214501Srpaulo struct sockaddr_in dst; 224214501Srpaulo char *url, *path; 225214501Srpaulo char sid[100]; 226214501Srpaulo 227214501Srpaulo if (ap->event_sub_url == NULL) { 228214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: No eventSubURL - cannot " 229214501Srpaulo "subscribe"); 230214501Srpaulo goto fail; 231214501Srpaulo } 232214501Srpaulo if (ap->http) { 233214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request - cannot " 234214501Srpaulo "send subscribe request"); 235214501Srpaulo goto fail; 236214501Srpaulo } 237214501Srpaulo 238214501Srpaulo url = http_client_url_parse(ap->event_sub_url, &dst, &path); 239214501Srpaulo if (url == NULL) { 240214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse eventSubURL"); 241214501Srpaulo goto fail; 242214501Srpaulo } 243214501Srpaulo 244214501Srpaulo req = wpabuf_alloc(os_strlen(ap->event_sub_url) + 1000); 245214501Srpaulo if (req == NULL) { 246214501Srpaulo os_free(url); 247214501Srpaulo goto fail; 248214501Srpaulo } 249214501Srpaulo uuid_bin2str(ap->sid, sid, sizeof(sid)); 250214501Srpaulo wpabuf_printf(req, 251214501Srpaulo "UNSUBSCRIBE %s HTTP/1.1\r\n" 252214501Srpaulo "HOST: %s:%d\r\n" 253214501Srpaulo "SID: uuid:%s\r\n" 254214501Srpaulo "\r\n", 255214501Srpaulo path, inet_ntoa(dst.sin_addr), ntohs(dst.sin_port), sid); 256214501Srpaulo os_free(url); 257214501Srpaulo wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Unsubscription request", 258214501Srpaulo wpabuf_head(req), wpabuf_len(req)); 259214501Srpaulo 260214501Srpaulo ap->http = http_client_addr(&dst, req, 1000, 261214501Srpaulo wps_er_http_unsubscribe_cb, ap); 262214501Srpaulo if (ap->http == NULL) { 263214501Srpaulo wpabuf_free(req); 264214501Srpaulo goto fail; 265214501Srpaulo } 266214501Srpaulo return; 267214501Srpaulo 268214501Srpaulofail: 269214501Srpaulo /* 270214501Srpaulo * Need to get rid of the AP entry even when we fail to unsubscribe 271214501Srpaulo * cleanly. 272214501Srpaulo */ 273214501Srpaulo wps_er_ap_unsubscribed(ap->er, ap); 274214501Srpaulo} 275214501Srpaulo 276252726Srpaulo 277252726Srpaulostatic struct wps_er_ap_settings * wps_er_ap_get_settings(struct wps_er *er, 278252726Srpaulo const u8 *uuid) 279252726Srpaulo{ 280252726Srpaulo struct wps_er_ap_settings *s; 281252726Srpaulo dl_list_for_each(s, &er->ap_settings, struct wps_er_ap_settings, list) 282252726Srpaulo if (os_memcmp(uuid, s->uuid, WPS_UUID_LEN) == 0) 283252726Srpaulo return s; 284252726Srpaulo return NULL; 285252726Srpaulo} 286252726Srpaulo 287252726Srpaulo 288252726Srpauloint wps_er_ap_cache_settings(struct wps_er *er, struct in_addr *addr) 289252726Srpaulo{ 290252726Srpaulo struct wps_er_ap *ap; 291252726Srpaulo struct wps_er_ap_settings *settings; 292252726Srpaulo 293252726Srpaulo ap = wps_er_ap_get(er, addr, NULL); 294252726Srpaulo if (ap == NULL || ap->ap_settings == NULL) 295252726Srpaulo return -1; 296252726Srpaulo 297252726Srpaulo settings = wps_er_ap_get_settings(er, ap->uuid); 298252726Srpaulo if (!settings) { 299252726Srpaulo settings = os_zalloc(sizeof(*settings)); 300252726Srpaulo if (settings == NULL) 301252726Srpaulo return -1; 302252726Srpaulo os_memcpy(settings->uuid, ap->uuid, WPS_UUID_LEN); 303252726Srpaulo dl_list_add(&er->ap_settings, &settings->list); 304252726Srpaulo } 305252726Srpaulo os_memcpy(&settings->ap_settings, ap->ap_settings, 306252726Srpaulo sizeof(struct wps_credential)); 307252726Srpaulo 308252726Srpaulo return 0; 309252726Srpaulo} 310252726Srpaulo 311252726Srpaulo 312252726Srpaulostatic int wps_er_ap_use_cached_settings(struct wps_er *er, 313252726Srpaulo struct wps_er_ap *ap) 314252726Srpaulo{ 315252726Srpaulo struct wps_er_ap_settings *s; 316252726Srpaulo 317252726Srpaulo if (ap->ap_settings) 318252726Srpaulo return 0; 319252726Srpaulo 320252726Srpaulo s = wps_er_ap_get_settings(ap->er, ap->uuid); 321252726Srpaulo if (!s) 322252726Srpaulo return -1; 323252726Srpaulo 324252726Srpaulo ap->ap_settings = os_malloc(sizeof(*ap->ap_settings)); 325252726Srpaulo if (ap->ap_settings == NULL) 326252726Srpaulo return -1; 327252726Srpaulo 328252726Srpaulo os_memcpy(ap->ap_settings, &s->ap_settings, sizeof(*ap->ap_settings)); 329252726Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Use cached AP settings"); 330252726Srpaulo return 0; 331252726Srpaulo} 332252726Srpaulo 333252726Srpaulo 334214501Srpaulostatic void wps_er_ap_remove_entry(struct wps_er *er, struct wps_er_ap *ap) 335214501Srpaulo{ 336214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Removing AP entry for %s (%s)", 337214501Srpaulo inet_ntoa(ap->addr), ap->location); 338214501Srpaulo eloop_cancel_timeout(wps_er_ap_timeout, er, ap); 339214501Srpaulo wps_er_sta_remove_all(ap); 340214501Srpaulo wps_er_ap_event(er->wps, ap, WPS_EV_ER_AP_REMOVE); 341214501Srpaulo http_client_free(ap->http); 342214501Srpaulo ap->http = NULL; 343214501Srpaulo if (ap->wps) { 344214501Srpaulo wps_deinit(ap->wps); 345214501Srpaulo ap->wps = NULL; 346214501Srpaulo } 347214501Srpaulo 348214501Srpaulo dl_list_del(&ap->list); 349214501Srpaulo if (ap->subscribed) { 350214501Srpaulo dl_list_add(&er->ap_unsubscribing, &ap->list); 351214501Srpaulo wps_er_ap_unsubscribe(er, ap); 352214501Srpaulo } else 353214501Srpaulo wps_er_ap_free(ap); 354214501Srpaulo} 355214501Srpaulo 356214501Srpaulo 357214501Srpaulostatic void wps_er_ap_timeout(void *eloop_data, void *user_ctx) 358214501Srpaulo{ 359214501Srpaulo struct wps_er *er = eloop_data; 360214501Srpaulo struct wps_er_ap *ap = user_ctx; 361214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: AP advertisement timed out"); 362214501Srpaulo wps_er_ap_remove_entry(er, ap); 363214501Srpaulo} 364214501Srpaulo 365214501Srpaulo 366214501Srpaulostatic int wps_er_get_sid(struct wps_er_ap *ap, char *sid) 367214501Srpaulo{ 368214501Srpaulo char *pos; 369214501Srpaulo char txt[100]; 370214501Srpaulo 371214501Srpaulo if (!sid) { 372214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: No SID received from %s (%s)", 373214501Srpaulo inet_ntoa(ap->addr), ap->location); 374214501Srpaulo return -1; 375214501Srpaulo } 376214501Srpaulo 377214501Srpaulo pos = os_strstr(sid, "uuid:"); 378214501Srpaulo if (!pos) { 379214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Invalid SID received from " 380214501Srpaulo "%s (%s): '%s'", inet_ntoa(ap->addr), ap->location, 381214501Srpaulo sid); 382214501Srpaulo return -1; 383214501Srpaulo } 384214501Srpaulo 385214501Srpaulo pos += 5; 386214501Srpaulo if (uuid_str2bin(pos, ap->sid) < 0) { 387214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Invalid SID received from " 388214501Srpaulo "%s (%s): '%s'", inet_ntoa(ap->addr), ap->location, 389214501Srpaulo sid); 390214501Srpaulo return -1; 391214501Srpaulo } 392214501Srpaulo 393214501Srpaulo uuid_bin2str(ap->sid, txt, sizeof(txt)); 394214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: SID for subscription with %s (%s): %s", 395214501Srpaulo inet_ntoa(ap->addr), ap->location, txt); 396214501Srpaulo 397214501Srpaulo return 0; 398214501Srpaulo} 399214501Srpaulo 400214501Srpaulo 401214501Srpaulostatic void wps_er_http_subscribe_cb(void *ctx, struct http_client *c, 402214501Srpaulo enum http_client_event event) 403214501Srpaulo{ 404214501Srpaulo struct wps_er_ap *ap = ctx; 405214501Srpaulo 406214501Srpaulo switch (event) { 407214501Srpaulo case HTTP_CLIENT_OK: 408214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Subscribed to events"); 409214501Srpaulo ap->subscribed = 1; 410214501Srpaulo wps_er_get_sid(ap, http_client_get_hdr_line(c, "SID")); 411252726Srpaulo wps_er_ap_use_cached_settings(ap->er, ap); 412214501Srpaulo wps_er_ap_event(ap->er->wps, ap, WPS_EV_ER_AP_ADD); 413214501Srpaulo break; 414214501Srpaulo case HTTP_CLIENT_FAILED: 415214501Srpaulo case HTTP_CLIENT_INVALID_REPLY: 416214501Srpaulo case HTTP_CLIENT_TIMEOUT: 417214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Failed to subscribe to events"); 418214501Srpaulo break; 419214501Srpaulo } 420214501Srpaulo http_client_free(ap->http); 421214501Srpaulo ap->http = NULL; 422214501Srpaulo} 423214501Srpaulo 424214501Srpaulo 425214501Srpaulostatic void wps_er_subscribe(struct wps_er_ap *ap) 426214501Srpaulo{ 427214501Srpaulo struct wpabuf *req; 428214501Srpaulo struct sockaddr_in dst; 429214501Srpaulo char *url, *path; 430214501Srpaulo 431214501Srpaulo if (ap->event_sub_url == NULL) { 432214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: No eventSubURL - cannot " 433214501Srpaulo "subscribe"); 434214501Srpaulo return; 435214501Srpaulo } 436214501Srpaulo if (ap->http) { 437214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request - cannot " 438214501Srpaulo "send subscribe request"); 439214501Srpaulo return; 440214501Srpaulo } 441214501Srpaulo 442214501Srpaulo url = http_client_url_parse(ap->event_sub_url, &dst, &path); 443214501Srpaulo if (url == NULL) { 444214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse eventSubURL"); 445214501Srpaulo return; 446214501Srpaulo } 447214501Srpaulo 448214501Srpaulo req = wpabuf_alloc(os_strlen(ap->event_sub_url) + 1000); 449214501Srpaulo if (req == NULL) { 450214501Srpaulo os_free(url); 451214501Srpaulo return; 452214501Srpaulo } 453214501Srpaulo wpabuf_printf(req, 454214501Srpaulo "SUBSCRIBE %s HTTP/1.1\r\n" 455214501Srpaulo "HOST: %s:%d\r\n" 456214501Srpaulo "CALLBACK: <http://%s:%d/event/%u/%u>\r\n" 457214501Srpaulo "NT: upnp:event\r\n" 458214501Srpaulo "TIMEOUT: Second-%d\r\n" 459214501Srpaulo "\r\n", 460214501Srpaulo path, inet_ntoa(dst.sin_addr), ntohs(dst.sin_port), 461214501Srpaulo ap->er->ip_addr_text, ap->er->http_port, 462214501Srpaulo ap->er->event_id, ap->id, 1800); 463214501Srpaulo os_free(url); 464214501Srpaulo wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Subscription request", 465214501Srpaulo wpabuf_head(req), wpabuf_len(req)); 466214501Srpaulo 467214501Srpaulo ap->http = http_client_addr(&dst, req, 1000, wps_er_http_subscribe_cb, 468214501Srpaulo ap); 469214501Srpaulo if (ap->http == NULL) 470214501Srpaulo wpabuf_free(req); 471214501Srpaulo} 472214501Srpaulo 473214501Srpaulo 474214501Srpaulostatic void wps_er_ap_get_m1(struct wps_er_ap *ap, struct wpabuf *m1) 475214501Srpaulo{ 476214501Srpaulo struct wps_parse_attr attr; 477214501Srpaulo 478214501Srpaulo if (wps_parse_msg(m1, &attr) < 0) { 479214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse M1"); 480214501Srpaulo return; 481214501Srpaulo } 482214501Srpaulo if (attr.primary_dev_type) 483214501Srpaulo os_memcpy(ap->pri_dev_type, attr.primary_dev_type, 8); 484214501Srpaulo if (attr.wps_state) 485214501Srpaulo ap->wps_state = *attr.wps_state; 486214501Srpaulo if (attr.mac_addr) 487214501Srpaulo os_memcpy(ap->mac_addr, attr.mac_addr, ETH_ALEN); 488214501Srpaulo 489214501Srpaulo wps_er_subscribe(ap); 490214501Srpaulo} 491214501Srpaulo 492214501Srpaulo 493214501Srpaulostatic void wps_er_get_device_info(struct wps_er_ap *ap) 494214501Srpaulo{ 495214501Srpaulo wps_er_send_get_device_info(ap, wps_er_ap_get_m1); 496214501Srpaulo} 497214501Srpaulo 498214501Srpaulo 499252726Srpaulostatic const char * wps_er_find_wfadevice(const char *data) 500252726Srpaulo{ 501252726Srpaulo const char *tag, *tagname, *end; 502252726Srpaulo char *val; 503252726Srpaulo int found = 0; 504252726Srpaulo 505252726Srpaulo while (!found) { 506252726Srpaulo /* Find next <device> */ 507252726Srpaulo for (;;) { 508252726Srpaulo if (xml_next_tag(data, &tag, &tagname, &end)) 509252726Srpaulo return NULL; 510252726Srpaulo data = end; 511252726Srpaulo if (!os_strncasecmp(tagname, "device", 6) && 512252726Srpaulo *tag != '/' && 513252726Srpaulo (tagname[6] == '>' || !isgraph(tagname[6]))) { 514252726Srpaulo break; 515252726Srpaulo } 516252726Srpaulo } 517252726Srpaulo 518252726Srpaulo /* Check whether deviceType is WFADevice */ 519252726Srpaulo val = xml_get_first_item(data, "deviceType"); 520252726Srpaulo if (val == NULL) 521252726Srpaulo return NULL; 522252726Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Found deviceType '%s'", val); 523252726Srpaulo found = os_strcasecmp(val, "urn:schemas-wifialliance-org:" 524252726Srpaulo "device:WFADevice:1") == 0; 525252726Srpaulo os_free(val); 526252726Srpaulo } 527252726Srpaulo 528252726Srpaulo return data; 529252726Srpaulo} 530252726Srpaulo 531252726Srpaulo 532214501Srpaulostatic void wps_er_parse_device_description(struct wps_er_ap *ap, 533214501Srpaulo struct wpabuf *reply) 534214501Srpaulo{ 535214501Srpaulo /* Note: reply includes null termination after the buffer data */ 536252726Srpaulo const char *tmp, *data = wpabuf_head(reply); 537214501Srpaulo char *pos; 538214501Srpaulo 539214501Srpaulo wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Device info", 540214501Srpaulo wpabuf_head(reply), wpabuf_len(reply)); 541214501Srpaulo 542252726Srpaulo /* 543252726Srpaulo * The root device description may include multiple devices, so first 544252726Srpaulo * find the beginning of the WFADevice description to allow the 545252726Srpaulo * simplistic parser to pick the correct entries. 546252726Srpaulo */ 547252726Srpaulo tmp = wps_er_find_wfadevice(data); 548252726Srpaulo if (tmp == NULL) { 549252726Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: WFADevice:1 device not found - " 550252726Srpaulo "trying to parse invalid data"); 551252726Srpaulo } else 552252726Srpaulo data = tmp; 553252726Srpaulo 554214501Srpaulo ap->friendly_name = xml_get_first_item(data, "friendlyName"); 555214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: friendlyName='%s'", ap->friendly_name); 556214501Srpaulo 557214501Srpaulo ap->manufacturer = xml_get_first_item(data, "manufacturer"); 558214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: manufacturer='%s'", ap->manufacturer); 559214501Srpaulo 560214501Srpaulo ap->manufacturer_url = xml_get_first_item(data, "manufacturerURL"); 561214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: manufacturerURL='%s'", 562214501Srpaulo ap->manufacturer_url); 563214501Srpaulo 564214501Srpaulo ap->model_description = xml_get_first_item(data, "modelDescription"); 565214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: modelDescription='%s'", 566214501Srpaulo ap->model_description); 567214501Srpaulo 568214501Srpaulo ap->model_name = xml_get_first_item(data, "modelName"); 569214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: modelName='%s'", ap->model_name); 570214501Srpaulo 571214501Srpaulo ap->model_number = xml_get_first_item(data, "modelNumber"); 572214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: modelNumber='%s'", ap->model_number); 573214501Srpaulo 574214501Srpaulo ap->model_url = xml_get_first_item(data, "modelURL"); 575214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: modelURL='%s'", ap->model_url); 576214501Srpaulo 577214501Srpaulo ap->serial_number = xml_get_first_item(data, "serialNumber"); 578214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: serialNumber='%s'", ap->serial_number); 579214501Srpaulo 580214501Srpaulo ap->udn = xml_get_first_item(data, "UDN"); 581214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: UDN='%s'", ap->udn); 582214501Srpaulo pos = os_strstr(ap->udn, "uuid:"); 583214501Srpaulo if (pos) { 584214501Srpaulo pos += 5; 585214501Srpaulo if (uuid_str2bin(pos, ap->uuid) < 0) 586214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Invalid UUID in UDN"); 587214501Srpaulo } 588214501Srpaulo 589214501Srpaulo ap->upc = xml_get_first_item(data, "UPC"); 590214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: UPC='%s'", ap->upc); 591214501Srpaulo 592214501Srpaulo ap->scpd_url = http_link_update( 593214501Srpaulo xml_get_first_item(data, "SCPDURL"), ap->location); 594214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: SCPDURL='%s'", ap->scpd_url); 595214501Srpaulo 596214501Srpaulo ap->control_url = http_link_update( 597214501Srpaulo xml_get_first_item(data, "controlURL"), ap->location); 598214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: controlURL='%s'", ap->control_url); 599214501Srpaulo 600214501Srpaulo ap->event_sub_url = http_link_update( 601214501Srpaulo xml_get_first_item(data, "eventSubURL"), ap->location); 602214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: eventSubURL='%s'", ap->event_sub_url); 603214501Srpaulo} 604214501Srpaulo 605214501Srpaulo 606214501Srpaulostatic void wps_er_http_dev_desc_cb(void *ctx, struct http_client *c, 607214501Srpaulo enum http_client_event event) 608214501Srpaulo{ 609214501Srpaulo struct wps_er_ap *ap = ctx; 610214501Srpaulo struct wpabuf *reply; 611214501Srpaulo int ok = 0; 612214501Srpaulo 613214501Srpaulo switch (event) { 614214501Srpaulo case HTTP_CLIENT_OK: 615214501Srpaulo reply = http_client_get_body(c); 616214501Srpaulo if (reply == NULL) 617214501Srpaulo break; 618214501Srpaulo wps_er_parse_device_description(ap, reply); 619214501Srpaulo ok = 1; 620214501Srpaulo break; 621214501Srpaulo case HTTP_CLIENT_FAILED: 622214501Srpaulo case HTTP_CLIENT_INVALID_REPLY: 623214501Srpaulo case HTTP_CLIENT_TIMEOUT: 624214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Failed to fetch device info"); 625214501Srpaulo break; 626214501Srpaulo } 627214501Srpaulo http_client_free(ap->http); 628214501Srpaulo ap->http = NULL; 629214501Srpaulo if (ok) 630214501Srpaulo wps_er_get_device_info(ap); 631214501Srpaulo} 632214501Srpaulo 633214501Srpaulo 634214501Srpaulovoid wps_er_ap_add(struct wps_er *er, const u8 *uuid, struct in_addr *addr, 635214501Srpaulo const char *location, int max_age) 636214501Srpaulo{ 637214501Srpaulo struct wps_er_ap *ap; 638214501Srpaulo 639214501Srpaulo ap = wps_er_ap_get(er, addr, uuid); 640214501Srpaulo if (ap) { 641214501Srpaulo /* Update advertisement timeout */ 642214501Srpaulo eloop_cancel_timeout(wps_er_ap_timeout, er, ap); 643214501Srpaulo eloop_register_timeout(max_age, 0, wps_er_ap_timeout, er, ap); 644214501Srpaulo return; 645214501Srpaulo } 646214501Srpaulo 647214501Srpaulo ap = os_zalloc(sizeof(*ap)); 648214501Srpaulo if (ap == NULL) 649214501Srpaulo return; 650214501Srpaulo dl_list_init(&ap->sta); 651214501Srpaulo ap->er = er; 652214501Srpaulo ap->id = ++er->next_ap_id; 653214501Srpaulo ap->location = os_strdup(location); 654214501Srpaulo if (ap->location == NULL) { 655214501Srpaulo os_free(ap); 656214501Srpaulo return; 657214501Srpaulo } 658214501Srpaulo dl_list_add(&er->ap, &ap->list); 659214501Srpaulo 660214501Srpaulo ap->addr.s_addr = addr->s_addr; 661214501Srpaulo os_memcpy(ap->uuid, uuid, WPS_UUID_LEN); 662214501Srpaulo eloop_register_timeout(max_age, 0, wps_er_ap_timeout, er, ap); 663214501Srpaulo 664214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Added AP entry for %s (%s)", 665214501Srpaulo inet_ntoa(ap->addr), ap->location); 666214501Srpaulo 667214501Srpaulo /* Fetch device description */ 668214501Srpaulo ap->http = http_client_url(ap->location, NULL, 10000, 669214501Srpaulo wps_er_http_dev_desc_cb, ap); 670214501Srpaulo} 671214501Srpaulo 672214501Srpaulo 673214501Srpaulovoid wps_er_ap_remove(struct wps_er *er, struct in_addr *addr) 674214501Srpaulo{ 675214501Srpaulo struct wps_er_ap *ap; 676214501Srpaulo dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) { 677214501Srpaulo if (ap->addr.s_addr == addr->s_addr) { 678214501Srpaulo wps_er_ap_remove_entry(er, ap); 679214501Srpaulo return; 680214501Srpaulo } 681214501Srpaulo } 682214501Srpaulo} 683214501Srpaulo 684214501Srpaulo 685214501Srpaulostatic void wps_er_ap_remove_all(struct wps_er *er) 686214501Srpaulo{ 687214501Srpaulo struct wps_er_ap *prev, *ap; 688252726Srpaulo struct wps_er_ap_settings *prev_s, *s; 689214501Srpaulo dl_list_for_each_safe(ap, prev, &er->ap, struct wps_er_ap, list) 690214501Srpaulo wps_er_ap_remove_entry(er, ap); 691252726Srpaulo dl_list_for_each_safe(s, prev_s, &er->ap_settings, 692252726Srpaulo struct wps_er_ap_settings, list) 693252726Srpaulo os_free(s); 694214501Srpaulo} 695214501Srpaulo 696214501Srpaulo 697214501Srpaulostatic void http_put_date(struct wpabuf *buf) 698214501Srpaulo{ 699214501Srpaulo wpabuf_put_str(buf, "Date: "); 700214501Srpaulo format_date(buf); 701214501Srpaulo wpabuf_put_str(buf, "\r\n"); 702214501Srpaulo} 703214501Srpaulo 704214501Srpaulo 705214501Srpaulostatic void wps_er_http_resp_not_found(struct http_request *req) 706214501Srpaulo{ 707214501Srpaulo struct wpabuf *buf; 708214501Srpaulo buf = wpabuf_alloc(200); 709214501Srpaulo if (buf == NULL) { 710214501Srpaulo http_request_deinit(req); 711214501Srpaulo return; 712214501Srpaulo } 713214501Srpaulo 714214501Srpaulo wpabuf_put_str(buf, 715214501Srpaulo "HTTP/1.1 404 Not Found\r\n" 716214501Srpaulo "Server: unspecified, UPnP/1.0, unspecified\r\n" 717214501Srpaulo "Connection: close\r\n"); 718214501Srpaulo http_put_date(buf); 719214501Srpaulo wpabuf_put_str(buf, "\r\n"); 720214501Srpaulo http_request_send_and_deinit(req, buf); 721214501Srpaulo} 722214501Srpaulo 723214501Srpaulo 724214501Srpaulostatic void wps_er_http_resp_ok(struct http_request *req) 725214501Srpaulo{ 726214501Srpaulo struct wpabuf *buf; 727214501Srpaulo buf = wpabuf_alloc(200); 728214501Srpaulo if (buf == NULL) { 729214501Srpaulo http_request_deinit(req); 730214501Srpaulo return; 731214501Srpaulo } 732214501Srpaulo 733214501Srpaulo wpabuf_put_str(buf, 734214501Srpaulo "HTTP/1.1 200 OK\r\n" 735214501Srpaulo "Server: unspecified, UPnP/1.0, unspecified\r\n" 736214501Srpaulo "Connection: close\r\n" 737214501Srpaulo "Content-Length: 0\r\n"); 738214501Srpaulo http_put_date(buf); 739214501Srpaulo wpabuf_put_str(buf, "\r\n"); 740214501Srpaulo http_request_send_and_deinit(req, buf); 741214501Srpaulo} 742214501Srpaulo 743214501Srpaulo 744214501Srpaulostatic void wps_er_sta_timeout(void *eloop_data, void *user_ctx) 745214501Srpaulo{ 746214501Srpaulo struct wps_er_sta *sta = eloop_data; 747214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: STA entry timed out"); 748214501Srpaulo dl_list_del(&sta->list); 749214501Srpaulo wps_er_sta_free(sta); 750214501Srpaulo} 751214501Srpaulo 752214501Srpaulo 753214501Srpaulostatic struct wps_er_sta * wps_er_add_sta_data(struct wps_er_ap *ap, 754214501Srpaulo const u8 *addr, 755214501Srpaulo struct wps_parse_attr *attr, 756214501Srpaulo int probe_req) 757214501Srpaulo{ 758252726Srpaulo struct wps_er_sta *sta = wps_er_sta_get(ap, addr, NULL); 759214501Srpaulo int new_sta = 0; 760214501Srpaulo int m1; 761214501Srpaulo 762214501Srpaulo m1 = !probe_req && attr->msg_type && *attr->msg_type == WPS_M1; 763214501Srpaulo 764214501Srpaulo if (sta == NULL) { 765214501Srpaulo /* 766214501Srpaulo * Only allow new STA entry to be added based on Probe Request 767214501Srpaulo * or M1. This will filter out bogus events and anything that 768214501Srpaulo * may have been ongoing at the time ER subscribed for events. 769214501Srpaulo */ 770214501Srpaulo if (!probe_req && !m1) 771214501Srpaulo return NULL; 772214501Srpaulo 773214501Srpaulo sta = os_zalloc(sizeof(*sta)); 774214501Srpaulo if (sta == NULL) 775214501Srpaulo return NULL; 776214501Srpaulo os_memcpy(sta->addr, addr, ETH_ALEN); 777214501Srpaulo sta->ap = ap; 778214501Srpaulo dl_list_add(&ap->sta, &sta->list); 779214501Srpaulo new_sta = 1; 780214501Srpaulo } 781214501Srpaulo 782214501Srpaulo if (m1) 783214501Srpaulo sta->m1_received = 1; 784214501Srpaulo 785214501Srpaulo if (attr->config_methods && (!probe_req || !sta->m1_received)) 786214501Srpaulo sta->config_methods = WPA_GET_BE16(attr->config_methods); 787214501Srpaulo if (attr->uuid_e && (!probe_req || !sta->m1_received)) 788214501Srpaulo os_memcpy(sta->uuid, attr->uuid_e, WPS_UUID_LEN); 789214501Srpaulo if (attr->primary_dev_type && (!probe_req || !sta->m1_received)) 790214501Srpaulo os_memcpy(sta->pri_dev_type, attr->primary_dev_type, 8); 791214501Srpaulo if (attr->dev_password_id && (!probe_req || !sta->m1_received)) 792214501Srpaulo sta->dev_passwd_id = WPA_GET_BE16(attr->dev_password_id); 793214501Srpaulo 794214501Srpaulo if (attr->manufacturer) { 795214501Srpaulo os_free(sta->manufacturer); 796214501Srpaulo sta->manufacturer = os_malloc(attr->manufacturer_len + 1); 797214501Srpaulo if (sta->manufacturer) { 798214501Srpaulo os_memcpy(sta->manufacturer, attr->manufacturer, 799214501Srpaulo attr->manufacturer_len); 800214501Srpaulo sta->manufacturer[attr->manufacturer_len] = '\0'; 801214501Srpaulo } 802214501Srpaulo } 803214501Srpaulo 804214501Srpaulo if (attr->model_name) { 805214501Srpaulo os_free(sta->model_name); 806214501Srpaulo sta->model_name = os_malloc(attr->model_name_len + 1); 807214501Srpaulo if (sta->model_name) { 808214501Srpaulo os_memcpy(sta->model_name, attr->model_name, 809214501Srpaulo attr->model_name_len); 810214501Srpaulo sta->model_name[attr->model_name_len] = '\0'; 811214501Srpaulo } 812214501Srpaulo } 813214501Srpaulo 814214501Srpaulo if (attr->model_number) { 815214501Srpaulo os_free(sta->model_number); 816214501Srpaulo sta->model_number = os_malloc(attr->model_number_len + 1); 817214501Srpaulo if (sta->model_number) { 818214501Srpaulo os_memcpy(sta->model_number, attr->model_number, 819214501Srpaulo attr->model_number_len); 820214501Srpaulo sta->model_number[attr->model_number_len] = '\0'; 821214501Srpaulo } 822214501Srpaulo } 823214501Srpaulo 824214501Srpaulo if (attr->serial_number) { 825214501Srpaulo os_free(sta->serial_number); 826214501Srpaulo sta->serial_number = os_malloc(attr->serial_number_len + 1); 827214501Srpaulo if (sta->serial_number) { 828214501Srpaulo os_memcpy(sta->serial_number, attr->serial_number, 829214501Srpaulo attr->serial_number_len); 830214501Srpaulo sta->serial_number[attr->serial_number_len] = '\0'; 831214501Srpaulo } 832214501Srpaulo } 833214501Srpaulo 834214501Srpaulo if (attr->dev_name) { 835214501Srpaulo os_free(sta->dev_name); 836214501Srpaulo sta->dev_name = os_malloc(attr->dev_name_len + 1); 837214501Srpaulo if (sta->dev_name) { 838214501Srpaulo os_memcpy(sta->dev_name, attr->dev_name, 839214501Srpaulo attr->dev_name_len); 840214501Srpaulo sta->dev_name[attr->dev_name_len] = '\0'; 841214501Srpaulo } 842214501Srpaulo } 843214501Srpaulo 844214501Srpaulo eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL); 845214501Srpaulo eloop_register_timeout(300, 0, wps_er_sta_timeout, sta, NULL); 846214501Srpaulo 847214501Srpaulo if (m1 || new_sta) 848214501Srpaulo wps_er_sta_event(ap->er->wps, sta, WPS_EV_ER_ENROLLEE_ADD); 849214501Srpaulo 850214501Srpaulo return sta; 851214501Srpaulo} 852214501Srpaulo 853214501Srpaulo 854214501Srpaulostatic void wps_er_process_wlanevent_probe_req(struct wps_er_ap *ap, 855214501Srpaulo const u8 *addr, 856214501Srpaulo struct wpabuf *msg) 857214501Srpaulo{ 858214501Srpaulo struct wps_parse_attr attr; 859214501Srpaulo 860214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: WLANEvent - Probe Request - from " 861214501Srpaulo MACSTR, MAC2STR(addr)); 862214501Srpaulo wpa_hexdump_buf(MSG_MSGDUMP, "WPS ER: WLANEvent - Enrollee's message " 863214501Srpaulo "(TLVs from Probe Request)", msg); 864214501Srpaulo 865252726Srpaulo if (wps_validate_probe_req(msg, addr) < 0) { 866252726Srpaulo wpa_printf(MSG_INFO, "WPS-STRICT: ER: Ignore invalid proxied " 867252726Srpaulo "Probe Request frame from " MACSTR, MAC2STR(addr)); 868252726Srpaulo return; 869252726Srpaulo } 870252726Srpaulo 871214501Srpaulo if (wps_parse_msg(msg, &attr) < 0) { 872214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse TLVs in " 873214501Srpaulo "WLANEvent message"); 874214501Srpaulo return; 875214501Srpaulo } 876214501Srpaulo 877214501Srpaulo wps_er_add_sta_data(ap, addr, &attr, 1); 878252726Srpaulo wps_registrar_probe_req_rx(ap->er->wps->registrar, addr, msg, 0); 879214501Srpaulo} 880214501Srpaulo 881214501Srpaulo 882214501Srpaulostatic void wps_er_http_put_wlan_response_cb(void *ctx, struct http_client *c, 883214501Srpaulo enum http_client_event event) 884214501Srpaulo{ 885214501Srpaulo struct wps_er_sta *sta = ctx; 886214501Srpaulo 887214501Srpaulo switch (event) { 888214501Srpaulo case HTTP_CLIENT_OK: 889214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: PutWLANResponse OK"); 890214501Srpaulo break; 891214501Srpaulo case HTTP_CLIENT_FAILED: 892214501Srpaulo case HTTP_CLIENT_INVALID_REPLY: 893214501Srpaulo case HTTP_CLIENT_TIMEOUT: 894214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: PutWLANResponse failed"); 895214501Srpaulo break; 896214501Srpaulo } 897214501Srpaulo http_client_free(sta->http); 898214501Srpaulo sta->http = NULL; 899214501Srpaulo} 900214501Srpaulo 901214501Srpaulo 902214501Srpaulostatic const char *soap_prefix = 903214501Srpaulo "<?xml version=\"1.0\"?>\n" 904214501Srpaulo "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" " 905214501Srpaulo "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n" 906214501Srpaulo "<s:Body>\n"; 907214501Srpaulostatic const char *soap_postfix = 908214501Srpaulo "</s:Body>\n</s:Envelope>\n"; 909214501Srpaulostatic const char *urn_wfawlanconfig = 910214501Srpaulo "urn:schemas-wifialliance-org:service:WFAWLANConfig:1"; 911214501Srpaulo 912214501Srpaulostatic struct wpabuf * wps_er_soap_hdr(const struct wpabuf *msg, 913214501Srpaulo const char *name, const char *arg_name, 914214501Srpaulo const char *path, 915214501Srpaulo const struct sockaddr_in *dst, 916214501Srpaulo char **len_ptr, char **body_ptr) 917214501Srpaulo{ 918214501Srpaulo unsigned char *encoded; 919214501Srpaulo size_t encoded_len; 920214501Srpaulo struct wpabuf *buf; 921214501Srpaulo 922214501Srpaulo if (msg) { 923214501Srpaulo encoded = base64_encode(wpabuf_head(msg), wpabuf_len(msg), 924214501Srpaulo &encoded_len); 925214501Srpaulo if (encoded == NULL) 926214501Srpaulo return NULL; 927214501Srpaulo } else { 928214501Srpaulo encoded = NULL; 929214501Srpaulo encoded_len = 0; 930214501Srpaulo } 931214501Srpaulo 932214501Srpaulo buf = wpabuf_alloc(1000 + encoded_len); 933214501Srpaulo if (buf == NULL) { 934214501Srpaulo os_free(encoded); 935214501Srpaulo return NULL; 936214501Srpaulo } 937214501Srpaulo 938214501Srpaulo wpabuf_printf(buf, 939214501Srpaulo "POST %s HTTP/1.1\r\n" 940214501Srpaulo "Host: %s:%d\r\n" 941214501Srpaulo "Content-Type: text/xml; charset=\"utf-8\"\r\n" 942214501Srpaulo "Content-Length: ", 943214501Srpaulo path, inet_ntoa(dst->sin_addr), ntohs(dst->sin_port)); 944214501Srpaulo 945214501Srpaulo *len_ptr = wpabuf_put(buf, 0); 946214501Srpaulo wpabuf_printf(buf, 947214501Srpaulo " \r\n" 948214501Srpaulo "SOAPACTION: \"%s#%s\"\r\n" 949214501Srpaulo "\r\n", 950214501Srpaulo urn_wfawlanconfig, name); 951214501Srpaulo 952214501Srpaulo *body_ptr = wpabuf_put(buf, 0); 953214501Srpaulo 954214501Srpaulo wpabuf_put_str(buf, soap_prefix); 955214501Srpaulo wpabuf_printf(buf, "<u:%s xmlns:u=\"", name); 956214501Srpaulo wpabuf_put_str(buf, urn_wfawlanconfig); 957214501Srpaulo wpabuf_put_str(buf, "\">\n"); 958214501Srpaulo if (encoded) { 959214501Srpaulo wpabuf_printf(buf, "<%s>%s</%s>\n", 960214501Srpaulo arg_name, (char *) encoded, arg_name); 961214501Srpaulo os_free(encoded); 962214501Srpaulo } 963214501Srpaulo 964214501Srpaulo return buf; 965214501Srpaulo} 966214501Srpaulo 967214501Srpaulo 968214501Srpaulostatic void wps_er_soap_end(struct wpabuf *buf, const char *name, 969214501Srpaulo char *len_ptr, char *body_ptr) 970214501Srpaulo{ 971214501Srpaulo char len_buf[10]; 972214501Srpaulo wpabuf_printf(buf, "</u:%s>\n", name); 973214501Srpaulo wpabuf_put_str(buf, soap_postfix); 974214501Srpaulo os_snprintf(len_buf, sizeof(len_buf), "%d", 975214501Srpaulo (int) ((char *) wpabuf_put(buf, 0) - body_ptr)); 976214501Srpaulo os_memcpy(len_ptr, len_buf, os_strlen(len_buf)); 977214501Srpaulo} 978214501Srpaulo 979214501Srpaulo 980214501Srpaulostatic void wps_er_sta_send_msg(struct wps_er_sta *sta, struct wpabuf *msg) 981214501Srpaulo{ 982214501Srpaulo struct wpabuf *buf; 983214501Srpaulo char *len_ptr, *body_ptr; 984214501Srpaulo struct sockaddr_in dst; 985214501Srpaulo char *url, *path; 986214501Srpaulo 987214501Srpaulo if (sta->http) { 988214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request for STA - " 989214501Srpaulo "ignore new request"); 990214501Srpaulo wpabuf_free(msg); 991214501Srpaulo return; 992214501Srpaulo } 993214501Srpaulo 994214501Srpaulo if (sta->ap->control_url == NULL) { 995214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP"); 996214501Srpaulo wpabuf_free(msg); 997214501Srpaulo return; 998214501Srpaulo } 999214501Srpaulo 1000214501Srpaulo url = http_client_url_parse(sta->ap->control_url, &dst, &path); 1001214501Srpaulo if (url == NULL) { 1002214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL"); 1003214501Srpaulo wpabuf_free(msg); 1004214501Srpaulo return; 1005214501Srpaulo } 1006214501Srpaulo 1007214501Srpaulo buf = wps_er_soap_hdr(msg, "PutWLANResponse", "NewMessage", path, &dst, 1008214501Srpaulo &len_ptr, &body_ptr); 1009214501Srpaulo wpabuf_free(msg); 1010214501Srpaulo os_free(url); 1011214501Srpaulo if (buf == NULL) 1012214501Srpaulo return; 1013214501Srpaulo wpabuf_printf(buf, "<NewWLANEventType>%d</NewWLANEventType>\n", 1014214501Srpaulo UPNP_WPS_WLANEVENT_TYPE_EAP); 1015214501Srpaulo wpabuf_printf(buf, "<NewWLANEventMAC>" MACSTR "</NewWLANEventMAC>\n", 1016214501Srpaulo MAC2STR(sta->addr)); 1017214501Srpaulo 1018214501Srpaulo wps_er_soap_end(buf, "PutWLANResponse", len_ptr, body_ptr); 1019214501Srpaulo 1020214501Srpaulo sta->http = http_client_addr(&dst, buf, 1000, 1021214501Srpaulo wps_er_http_put_wlan_response_cb, sta); 1022214501Srpaulo if (sta->http == NULL) 1023214501Srpaulo wpabuf_free(buf); 1024214501Srpaulo} 1025214501Srpaulo 1026214501Srpaulo 1027214501Srpaulostatic void wps_er_sta_process(struct wps_er_sta *sta, struct wpabuf *msg, 1028214501Srpaulo enum wsc_op_code op_code) 1029214501Srpaulo{ 1030214501Srpaulo enum wps_process_res res; 1031214501Srpaulo 1032214501Srpaulo res = wps_process_msg(sta->wps, op_code, msg); 1033214501Srpaulo if (res == WPS_CONTINUE) { 1034214501Srpaulo struct wpabuf *next = wps_get_msg(sta->wps, &op_code); 1035214501Srpaulo if (next) 1036214501Srpaulo wps_er_sta_send_msg(sta, next); 1037214501Srpaulo } else { 1038214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Protocol run %s with the " 1039214501Srpaulo "enrollee (res=%d)", 1040214501Srpaulo res == WPS_DONE ? "succeeded" : "failed", res); 1041214501Srpaulo wps_deinit(sta->wps); 1042214501Srpaulo sta->wps = NULL; 1043214501Srpaulo if (res == WPS_DONE) { 1044214501Srpaulo /* Remove the STA entry after short timeout */ 1045214501Srpaulo eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL); 1046214501Srpaulo eloop_register_timeout(10, 0, wps_er_sta_timeout, sta, 1047214501Srpaulo NULL); 1048214501Srpaulo } 1049214501Srpaulo } 1050214501Srpaulo} 1051214501Srpaulo 1052214501Srpaulo 1053214501Srpaulostatic void wps_er_sta_start(struct wps_er_sta *sta, struct wpabuf *msg) 1054214501Srpaulo{ 1055214501Srpaulo struct wps_config cfg; 1056214501Srpaulo 1057214501Srpaulo if (sta->wps) 1058214501Srpaulo wps_deinit(sta->wps); 1059214501Srpaulo 1060214501Srpaulo os_memset(&cfg, 0, sizeof(cfg)); 1061214501Srpaulo cfg.wps = sta->ap->er->wps; 1062214501Srpaulo cfg.registrar = 1; 1063214501Srpaulo cfg.peer_addr = sta->addr; 1064214501Srpaulo 1065214501Srpaulo sta->wps = wps_init(&cfg); 1066214501Srpaulo if (sta->wps == NULL) 1067214501Srpaulo return; 1068214501Srpaulo sta->wps->er = 1; 1069214501Srpaulo sta->wps->use_cred = sta->ap->ap_settings; 1070214501Srpaulo if (sta->ap->ap_settings) { 1071214501Srpaulo os_free(sta->cred); 1072214501Srpaulo sta->cred = os_malloc(sizeof(*sta->cred)); 1073214501Srpaulo if (sta->cred) { 1074214501Srpaulo os_memcpy(sta->cred, sta->ap->ap_settings, 1075214501Srpaulo sizeof(*sta->cred)); 1076214501Srpaulo sta->cred->cred_attr = NULL; 1077214501Srpaulo os_memcpy(sta->cred->mac_addr, sta->addr, ETH_ALEN); 1078214501Srpaulo sta->wps->use_cred = sta->cred; 1079214501Srpaulo } 1080214501Srpaulo } 1081214501Srpaulo 1082214501Srpaulo wps_er_sta_process(sta, msg, WSC_MSG); 1083214501Srpaulo} 1084214501Srpaulo 1085214501Srpaulo 1086214501Srpaulostatic void wps_er_process_wlanevent_eap(struct wps_er_ap *ap, const u8 *addr, 1087214501Srpaulo struct wpabuf *msg) 1088214501Srpaulo{ 1089214501Srpaulo struct wps_parse_attr attr; 1090214501Srpaulo struct wps_er_sta *sta; 1091214501Srpaulo 1092214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: WLANEvent - EAP - from " MACSTR, 1093214501Srpaulo MAC2STR(addr)); 1094214501Srpaulo wpa_hexdump_buf(MSG_MSGDUMP, "WPS ER: WLANEvent - Enrollee's message " 1095214501Srpaulo "(TLVs from EAP-WSC)", msg); 1096214501Srpaulo 1097214501Srpaulo if (wps_parse_msg(msg, &attr) < 0) { 1098214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse TLVs in " 1099214501Srpaulo "WLANEvent message"); 1100214501Srpaulo return; 1101214501Srpaulo } 1102214501Srpaulo 1103214501Srpaulo sta = wps_er_add_sta_data(ap, addr, &attr, 0); 1104214501Srpaulo if (sta == NULL) 1105214501Srpaulo return; 1106214501Srpaulo 1107214501Srpaulo if (attr.msg_type && *attr.msg_type == WPS_M1) 1108214501Srpaulo wps_er_sta_start(sta, msg); 1109214501Srpaulo else if (sta->wps) { 1110214501Srpaulo enum wsc_op_code op_code = WSC_MSG; 1111214501Srpaulo if (attr.msg_type) { 1112214501Srpaulo switch (*attr.msg_type) { 1113214501Srpaulo case WPS_WSC_ACK: 1114214501Srpaulo op_code = WSC_ACK; 1115214501Srpaulo break; 1116214501Srpaulo case WPS_WSC_NACK: 1117214501Srpaulo op_code = WSC_NACK; 1118214501Srpaulo break; 1119214501Srpaulo case WPS_WSC_DONE: 1120214501Srpaulo op_code = WSC_Done; 1121214501Srpaulo break; 1122214501Srpaulo } 1123214501Srpaulo } 1124214501Srpaulo wps_er_sta_process(sta, msg, op_code); 1125214501Srpaulo } 1126214501Srpaulo} 1127214501Srpaulo 1128214501Srpaulo 1129214501Srpaulostatic void wps_er_process_wlanevent(struct wps_er_ap *ap, 1130214501Srpaulo struct wpabuf *event) 1131214501Srpaulo{ 1132214501Srpaulo u8 *data; 1133214501Srpaulo u8 wlan_event_type; 1134214501Srpaulo u8 wlan_event_mac[ETH_ALEN]; 1135214501Srpaulo struct wpabuf msg; 1136214501Srpaulo 1137214501Srpaulo wpa_hexdump(MSG_MSGDUMP, "WPS ER: Received WLANEvent", 1138214501Srpaulo wpabuf_head(event), wpabuf_len(event)); 1139214501Srpaulo if (wpabuf_len(event) < 1 + 17) { 1140214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Too short WLANEvent"); 1141214501Srpaulo return; 1142214501Srpaulo } 1143214501Srpaulo 1144214501Srpaulo data = wpabuf_mhead(event); 1145214501Srpaulo wlan_event_type = data[0]; 1146214501Srpaulo if (hwaddr_aton((char *) data + 1, wlan_event_mac) < 0) { 1147214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Invalid WLANEventMAC in " 1148214501Srpaulo "WLANEvent"); 1149214501Srpaulo return; 1150214501Srpaulo } 1151214501Srpaulo 1152214501Srpaulo wpabuf_set(&msg, data + 1 + 17, wpabuf_len(event) - (1 + 17)); 1153214501Srpaulo 1154214501Srpaulo switch (wlan_event_type) { 1155214501Srpaulo case 1: 1156214501Srpaulo wps_er_process_wlanevent_probe_req(ap, wlan_event_mac, &msg); 1157214501Srpaulo break; 1158214501Srpaulo case 2: 1159214501Srpaulo wps_er_process_wlanevent_eap(ap, wlan_event_mac, &msg); 1160214501Srpaulo break; 1161214501Srpaulo default: 1162214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Unknown WLANEventType %d", 1163214501Srpaulo wlan_event_type); 1164214501Srpaulo break; 1165214501Srpaulo } 1166214501Srpaulo} 1167214501Srpaulo 1168214501Srpaulo 1169214501Srpaulostatic void wps_er_http_event(struct wps_er *er, struct http_request *req, 1170214501Srpaulo unsigned int ap_id) 1171214501Srpaulo{ 1172214501Srpaulo struct wps_er_ap *ap = wps_er_ap_get_id(er, ap_id); 1173214501Srpaulo struct wpabuf *event; 1174214501Srpaulo enum http_reply_code ret; 1175214501Srpaulo 1176214501Srpaulo if (ap == NULL) { 1177214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: HTTP event from unknown AP id " 1178214501Srpaulo "%u", ap_id); 1179214501Srpaulo wps_er_http_resp_not_found(req); 1180214501Srpaulo return; 1181214501Srpaulo } 1182214501Srpaulo wpa_printf(MSG_MSGDUMP, "WPS ER: HTTP event from AP id %u: %s", 1183214501Srpaulo ap_id, http_request_get_data(req)); 1184214501Srpaulo 1185214501Srpaulo event = xml_get_base64_item(http_request_get_data(req), "WLANEvent", 1186214501Srpaulo &ret); 1187214501Srpaulo if (event == NULL) { 1188214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Could not extract WLANEvent " 1189214501Srpaulo "from the event notification"); 1190214501Srpaulo /* 1191214501Srpaulo * Reply with OK anyway to avoid getting unregistered from 1192214501Srpaulo * events. 1193214501Srpaulo */ 1194214501Srpaulo wps_er_http_resp_ok(req); 1195214501Srpaulo return; 1196214501Srpaulo } 1197214501Srpaulo 1198214501Srpaulo wps_er_process_wlanevent(ap, event); 1199214501Srpaulo 1200214501Srpaulo wpabuf_free(event); 1201214501Srpaulo wps_er_http_resp_ok(req); 1202214501Srpaulo} 1203214501Srpaulo 1204214501Srpaulo 1205214501Srpaulostatic void wps_er_http_notify(struct wps_er *er, struct http_request *req) 1206214501Srpaulo{ 1207214501Srpaulo char *uri = http_request_get_uri(req); 1208214501Srpaulo 1209214501Srpaulo if (os_strncmp(uri, "/event/", 7) == 0) { 1210214501Srpaulo unsigned int event_id; 1211214501Srpaulo char *pos; 1212214501Srpaulo event_id = atoi(uri + 7); 1213214501Srpaulo if (event_id != er->event_id) { 1214214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: HTTP event for an " 1215214501Srpaulo "unknown event id %u", event_id); 1216214501Srpaulo return; 1217214501Srpaulo } 1218214501Srpaulo pos = os_strchr(uri + 7, '/'); 1219214501Srpaulo if (pos == NULL) 1220214501Srpaulo return; 1221214501Srpaulo pos++; 1222214501Srpaulo wps_er_http_event(er, req, atoi(pos)); 1223214501Srpaulo } else { 1224214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Unknown HTTP NOTIFY for '%s'", 1225214501Srpaulo uri); 1226214501Srpaulo wps_er_http_resp_not_found(req); 1227214501Srpaulo } 1228214501Srpaulo} 1229214501Srpaulo 1230214501Srpaulo 1231214501Srpaulostatic void wps_er_http_req(void *ctx, struct http_request *req) 1232214501Srpaulo{ 1233214501Srpaulo struct wps_er *er = ctx; 1234214501Srpaulo struct sockaddr_in *cli = http_request_get_cli_addr(req); 1235214501Srpaulo enum httpread_hdr_type type = http_request_get_type(req); 1236214501Srpaulo struct wpabuf *buf; 1237214501Srpaulo 1238214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: HTTP request: '%s' (type %d) from " 1239214501Srpaulo "%s:%d", 1240214501Srpaulo http_request_get_uri(req), type, 1241214501Srpaulo inet_ntoa(cli->sin_addr), ntohs(cli->sin_port)); 1242214501Srpaulo 1243214501Srpaulo switch (type) { 1244214501Srpaulo case HTTPREAD_HDR_TYPE_NOTIFY: 1245214501Srpaulo wps_er_http_notify(er, req); 1246214501Srpaulo break; 1247214501Srpaulo default: 1248214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Unsupported HTTP request type " 1249214501Srpaulo "%d", type); 1250214501Srpaulo buf = wpabuf_alloc(200); 1251214501Srpaulo if (buf == NULL) { 1252214501Srpaulo http_request_deinit(req); 1253214501Srpaulo return; 1254214501Srpaulo } 1255214501Srpaulo wpabuf_put_str(buf, 1256214501Srpaulo "HTTP/1.1 501 Unimplemented\r\n" 1257214501Srpaulo "Connection: close\r\n"); 1258214501Srpaulo http_put_date(buf); 1259214501Srpaulo wpabuf_put_str(buf, "\r\n"); 1260214501Srpaulo http_request_send_and_deinit(req, buf); 1261214501Srpaulo break; 1262214501Srpaulo } 1263214501Srpaulo} 1264214501Srpaulo 1265214501Srpaulo 1266214501Srpaulostruct wps_er * 1267252726Srpaulowps_er_init(struct wps_context *wps, const char *ifname, const char *filter) 1268214501Srpaulo{ 1269214501Srpaulo struct wps_er *er; 1270214501Srpaulo struct in_addr addr; 1271214501Srpaulo 1272214501Srpaulo er = os_zalloc(sizeof(*er)); 1273214501Srpaulo if (er == NULL) 1274214501Srpaulo return NULL; 1275214501Srpaulo dl_list_init(&er->ap); 1276214501Srpaulo dl_list_init(&er->ap_unsubscribing); 1277252726Srpaulo dl_list_init(&er->ap_settings); 1278214501Srpaulo 1279214501Srpaulo er->multicast_sd = -1; 1280214501Srpaulo er->ssdp_sd = -1; 1281214501Srpaulo 1282214501Srpaulo os_strlcpy(er->ifname, ifname, sizeof(er->ifname)); 1283214501Srpaulo er->wps = wps; 1284214501Srpaulo if (os_get_random((unsigned char *) &er->event_id, 1285214501Srpaulo sizeof(er->event_id)) < 0) { 1286214501Srpaulo wps_er_deinit(er, NULL, NULL); 1287214501Srpaulo return NULL; 1288214501Srpaulo } 1289214501Srpaulo /* Limit event_id to < 32 bits to avoid issues with atoi() */ 1290214501Srpaulo er->event_id &= 0x0fffffff; 1291214501Srpaulo 1292252726Srpaulo if (filter) { 1293252726Srpaulo if (inet_aton(filter, &er->filter_addr) == 0) { 1294252726Srpaulo wpa_printf(MSG_INFO, "WPS UPnP: Invalid filter " 1295252726Srpaulo "address %s", filter); 1296252726Srpaulo wps_er_deinit(er, NULL, NULL); 1297252726Srpaulo return NULL; 1298252726Srpaulo } 1299252726Srpaulo wpa_printf(MSG_DEBUG, "WPS UPnP: Only accepting connections " 1300252726Srpaulo "with %s", filter); 1301252726Srpaulo } 1302214501Srpaulo if (get_netif_info(ifname, &er->ip_addr, &er->ip_addr_text, 1303214501Srpaulo er->mac_addr)) { 1304214501Srpaulo wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address " 1305214501Srpaulo "for %s. Does it have IP address?", ifname); 1306214501Srpaulo wps_er_deinit(er, NULL, NULL); 1307214501Srpaulo return NULL; 1308214501Srpaulo } 1309214501Srpaulo 1310214501Srpaulo if (wps_er_ssdp_init(er) < 0) { 1311252726Srpaulo wpa_printf(MSG_INFO, "WPS UPnP: SSDP initialization failed"); 1312214501Srpaulo wps_er_deinit(er, NULL, NULL); 1313214501Srpaulo return NULL; 1314214501Srpaulo } 1315214501Srpaulo 1316214501Srpaulo addr.s_addr = er->ip_addr; 1317214501Srpaulo er->http_srv = http_server_init(&addr, -1, wps_er_http_req, er); 1318214501Srpaulo if (er->http_srv == NULL) { 1319252726Srpaulo wpa_printf(MSG_INFO, "WPS UPnP: HTTP initialization failed"); 1320214501Srpaulo wps_er_deinit(er, NULL, NULL); 1321214501Srpaulo return NULL; 1322214501Srpaulo } 1323214501Srpaulo er->http_port = http_server_get_port(er->http_srv); 1324214501Srpaulo 1325214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Start (ifname=%s ip_addr=%s)", 1326214501Srpaulo er->ifname, er->ip_addr_text); 1327214501Srpaulo 1328214501Srpaulo return er; 1329214501Srpaulo} 1330214501Srpaulo 1331214501Srpaulo 1332214501Srpaulovoid wps_er_refresh(struct wps_er *er) 1333214501Srpaulo{ 1334214501Srpaulo struct wps_er_ap *ap; 1335214501Srpaulo struct wps_er_sta *sta; 1336214501Srpaulo 1337214501Srpaulo dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) { 1338214501Srpaulo wps_er_ap_event(er->wps, ap, WPS_EV_ER_AP_ADD); 1339214501Srpaulo dl_list_for_each(sta, &ap->sta, struct wps_er_sta, list) 1340214501Srpaulo wps_er_sta_event(er->wps, sta, WPS_EV_ER_ENROLLEE_ADD); 1341214501Srpaulo } 1342214501Srpaulo 1343214501Srpaulo wps_er_send_ssdp_msearch(er); 1344214501Srpaulo} 1345214501Srpaulo 1346214501Srpaulo 1347214501Srpaulostatic void wps_er_deinit_finish(void *eloop_data, void *user_ctx) 1348214501Srpaulo{ 1349214501Srpaulo struct wps_er *er = eloop_data; 1350214501Srpaulo void (*deinit_done_cb)(void *ctx); 1351214501Srpaulo void *deinit_done_ctx; 1352214501Srpaulo 1353214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Finishing deinit"); 1354214501Srpaulo 1355214501Srpaulo deinit_done_cb = er->deinit_done_cb; 1356214501Srpaulo deinit_done_ctx = er->deinit_done_ctx; 1357214501Srpaulo os_free(er->ip_addr_text); 1358214501Srpaulo os_free(er); 1359214501Srpaulo 1360214501Srpaulo if (deinit_done_cb) 1361214501Srpaulo deinit_done_cb(deinit_done_ctx); 1362214501Srpaulo} 1363214501Srpaulo 1364214501Srpaulo 1365214501Srpaulovoid wps_er_deinit(struct wps_er *er, void (*cb)(void *ctx), void *ctx) 1366214501Srpaulo{ 1367214501Srpaulo if (er == NULL) 1368214501Srpaulo return; 1369214501Srpaulo http_server_deinit(er->http_srv); 1370214501Srpaulo wps_er_ap_remove_all(er); 1371214501Srpaulo wps_er_ssdp_deinit(er); 1372214501Srpaulo eloop_register_timeout(dl_list_empty(&er->ap_unsubscribing) ? 0 : 5, 0, 1373214501Srpaulo wps_er_deinit_finish, er, NULL); 1374214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Finish deinit from timeout"); 1375214501Srpaulo er->deinitializing = 1; 1376214501Srpaulo er->deinit_done_cb = cb; 1377214501Srpaulo er->deinit_done_ctx = ctx; 1378214501Srpaulo} 1379214501Srpaulo 1380214501Srpaulo 1381214501Srpaulostatic void wps_er_http_set_sel_reg_cb(void *ctx, struct http_client *c, 1382214501Srpaulo enum http_client_event event) 1383214501Srpaulo{ 1384214501Srpaulo struct wps_er_ap *ap = ctx; 1385252726Srpaulo union wps_event_data data; 1386214501Srpaulo 1387252726Srpaulo os_memset(&data, 0, sizeof(data)); 1388252726Srpaulo 1389214501Srpaulo switch (event) { 1390214501Srpaulo case HTTP_CLIENT_OK: 1391214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar OK"); 1392252726Srpaulo data.set_sel_reg.state = WPS_ER_SET_SEL_REG_DONE; 1393252726Srpaulo data.set_sel_reg.uuid = ap->uuid; 1394214501Srpaulo break; 1395214501Srpaulo case HTTP_CLIENT_FAILED: 1396214501Srpaulo case HTTP_CLIENT_INVALID_REPLY: 1397214501Srpaulo case HTTP_CLIENT_TIMEOUT: 1398214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar failed"); 1399252726Srpaulo data.set_sel_reg.state = WPS_ER_SET_SEL_REG_FAILED; 1400252726Srpaulo data.set_sel_reg.uuid = ap->uuid; 1401214501Srpaulo break; 1402214501Srpaulo } 1403214501Srpaulo http_client_free(ap->http); 1404214501Srpaulo ap->http = NULL; 1405252726Srpaulo 1406252726Srpaulo if (data.set_sel_reg.uuid) 1407252726Srpaulo ap->er->wps->event_cb(ap->er->wps->cb_ctx, 1408252726Srpaulo WPS_EV_ER_SET_SELECTED_REGISTRAR, &data); 1409214501Srpaulo} 1410214501Srpaulo 1411214501Srpaulo 1412214501Srpaulostatic void wps_er_send_set_sel_reg(struct wps_er_ap *ap, struct wpabuf *msg) 1413214501Srpaulo{ 1414214501Srpaulo struct wpabuf *buf; 1415214501Srpaulo char *len_ptr, *body_ptr; 1416214501Srpaulo struct sockaddr_in dst; 1417214501Srpaulo char *url, *path; 1418214501Srpaulo 1419214501Srpaulo if (ap->control_url == NULL) { 1420214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP"); 1421214501Srpaulo return; 1422214501Srpaulo } 1423214501Srpaulo 1424214501Srpaulo if (ap->http) { 1425214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request for AP - " 1426214501Srpaulo "ignore new request"); 1427214501Srpaulo return; 1428214501Srpaulo } 1429214501Srpaulo 1430252726Srpaulo if (ap->wps) { 1431252726Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Pending WPS operation for AP - " 1432252726Srpaulo "skip SetSelectedRegistrar"); 1433252726Srpaulo return; 1434252726Srpaulo } 1435252726Srpaulo 1436214501Srpaulo url = http_client_url_parse(ap->control_url, &dst, &path); 1437214501Srpaulo if (url == NULL) { 1438214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL"); 1439214501Srpaulo return; 1440214501Srpaulo } 1441214501Srpaulo 1442214501Srpaulo buf = wps_er_soap_hdr(msg, "SetSelectedRegistrar", "NewMessage", path, 1443214501Srpaulo &dst, &len_ptr, &body_ptr); 1444214501Srpaulo os_free(url); 1445214501Srpaulo if (buf == NULL) 1446214501Srpaulo return; 1447214501Srpaulo 1448214501Srpaulo wps_er_soap_end(buf, "SetSelectedRegistrar", len_ptr, body_ptr); 1449214501Srpaulo 1450214501Srpaulo ap->http = http_client_addr(&dst, buf, 1000, 1451214501Srpaulo wps_er_http_set_sel_reg_cb, ap); 1452214501Srpaulo if (ap->http == NULL) 1453214501Srpaulo wpabuf_free(buf); 1454214501Srpaulo} 1455214501Srpaulo 1456214501Srpaulo 1457214501Srpaulostatic int wps_er_build_selected_registrar(struct wpabuf *msg, int sel_reg) 1458214501Srpaulo{ 1459214501Srpaulo wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR); 1460214501Srpaulo wpabuf_put_be16(msg, 1); 1461214501Srpaulo wpabuf_put_u8(msg, !!sel_reg); 1462214501Srpaulo return 0; 1463214501Srpaulo} 1464214501Srpaulo 1465214501Srpaulo 1466214501Srpaulostatic int wps_er_build_dev_password_id(struct wpabuf *msg, u16 dev_passwd_id) 1467214501Srpaulo{ 1468214501Srpaulo wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID); 1469214501Srpaulo wpabuf_put_be16(msg, 2); 1470214501Srpaulo wpabuf_put_be16(msg, dev_passwd_id); 1471214501Srpaulo return 0; 1472214501Srpaulo} 1473214501Srpaulo 1474214501Srpaulo 1475214501Srpaulostatic int wps_er_build_sel_reg_config_methods(struct wpabuf *msg, 1476214501Srpaulo u16 sel_reg_config_methods) 1477214501Srpaulo{ 1478214501Srpaulo wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR_CONFIG_METHODS); 1479214501Srpaulo wpabuf_put_be16(msg, 2); 1480214501Srpaulo wpabuf_put_be16(msg, sel_reg_config_methods); 1481214501Srpaulo return 0; 1482214501Srpaulo} 1483214501Srpaulo 1484214501Srpaulo 1485252726Srpaulostatic int wps_er_build_uuid_r(struct wpabuf *msg, const u8 *uuid_r) 1486252726Srpaulo{ 1487252726Srpaulo#ifdef CONFIG_WPS2 1488252726Srpaulo wpabuf_put_be16(msg, ATTR_UUID_R); 1489252726Srpaulo wpabuf_put_be16(msg, WPS_UUID_LEN); 1490252726Srpaulo wpabuf_put_data(msg, uuid_r, WPS_UUID_LEN); 1491252726Srpaulo#endif /* CONFIG_WPS2 */ 1492252726Srpaulo return 0; 1493252726Srpaulo} 1494252726Srpaulo 1495252726Srpaulo 1496214501Srpaulovoid wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id, 1497214501Srpaulo u16 sel_reg_config_methods) 1498214501Srpaulo{ 1499214501Srpaulo struct wpabuf *msg; 1500214501Srpaulo struct wps_er_ap *ap; 1501252726Srpaulo struct wps_registrar *reg = er->wps->registrar; 1502252726Srpaulo const u8 *auth_macs; 1503252726Srpaulo#ifdef CONFIG_WPS2 1504252726Srpaulo u8 bcast[ETH_ALEN]; 1505252726Srpaulo#endif /* CONFIG_WPS2 */ 1506252726Srpaulo size_t count; 1507252726Srpaulo union wps_event_data data; 1508214501Srpaulo 1509252726Srpaulo if (er->skip_set_sel_reg) { 1510252726Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Skip SetSelectedRegistrar"); 1511252726Srpaulo return; 1512252726Srpaulo } 1513252726Srpaulo 1514214501Srpaulo msg = wpabuf_alloc(500); 1515214501Srpaulo if (msg == NULL) 1516214501Srpaulo return; 1517214501Srpaulo 1518252726Srpaulo auth_macs = wps_authorized_macs(reg, &count); 1519252726Srpaulo#ifdef CONFIG_WPS2 1520252726Srpaulo if (count == 0) { 1521252726Srpaulo os_memset(bcast, 0xff, ETH_ALEN); 1522252726Srpaulo auth_macs = bcast; 1523252726Srpaulo count = 1; 1524252726Srpaulo } 1525252726Srpaulo#endif /* CONFIG_WPS2 */ 1526252726Srpaulo 1527214501Srpaulo if (wps_build_version(msg) || 1528214501Srpaulo wps_er_build_selected_registrar(msg, sel_reg) || 1529214501Srpaulo wps_er_build_dev_password_id(msg, dev_passwd_id) || 1530252726Srpaulo wps_er_build_sel_reg_config_methods(msg, sel_reg_config_methods) || 1531252726Srpaulo wps_build_wfa_ext(msg, 0, auth_macs, count) || 1532252726Srpaulo wps_er_build_uuid_r(msg, er->wps->uuid)) { 1533214501Srpaulo wpabuf_free(msg); 1534214501Srpaulo return; 1535214501Srpaulo } 1536214501Srpaulo 1537252726Srpaulo os_memset(&data, 0, sizeof(data)); 1538252726Srpaulo data.set_sel_reg.sel_reg = sel_reg; 1539252726Srpaulo data.set_sel_reg.dev_passwd_id = dev_passwd_id; 1540252726Srpaulo data.set_sel_reg.sel_reg_config_methods = sel_reg_config_methods; 1541252726Srpaulo data.set_sel_reg.state = WPS_ER_SET_SEL_REG_START; 1542252726Srpaulo 1543252726Srpaulo dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) { 1544252726Srpaulo if (er->set_sel_reg_uuid_filter && 1545252726Srpaulo os_memcmp(ap->uuid, er->set_sel_reg_uuid_filter, 1546252726Srpaulo WPS_UUID_LEN) != 0) 1547252726Srpaulo continue; 1548252726Srpaulo data.set_sel_reg.uuid = ap->uuid; 1549252726Srpaulo er->wps->event_cb(er->wps->cb_ctx, 1550252726Srpaulo WPS_EV_ER_SET_SELECTED_REGISTRAR, &data); 1551214501Srpaulo wps_er_send_set_sel_reg(ap, msg); 1552252726Srpaulo } 1553214501Srpaulo 1554214501Srpaulo wpabuf_free(msg); 1555214501Srpaulo} 1556214501Srpaulo 1557214501Srpaulo 1558214501Srpauloint wps_er_pbc(struct wps_er *er, const u8 *uuid) 1559214501Srpaulo{ 1560252726Srpaulo int res; 1561252726Srpaulo struct wps_er_ap *ap; 1562252726Srpaulo 1563214501Srpaulo if (er == NULL || er->wps == NULL) 1564214501Srpaulo return -1; 1565214501Srpaulo 1566252726Srpaulo if (wps_registrar_pbc_overlap(er->wps->registrar, NULL, NULL)) { 1567252726Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: PBC overlap - do not start PBC " 1568252726Srpaulo "mode"); 1569252726Srpaulo return -2; 1570252726Srpaulo } 1571252726Srpaulo 1572252726Srpaulo ap = wps_er_ap_get(er, NULL, uuid); 1573252726Srpaulo if (ap == NULL) { 1574252726Srpaulo struct wps_er_sta *sta = NULL; 1575252726Srpaulo dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) { 1576252726Srpaulo sta = wps_er_sta_get(ap, NULL, uuid); 1577252726Srpaulo if (sta) { 1578252726Srpaulo uuid = ap->uuid; 1579252726Srpaulo break; 1580252726Srpaulo } 1581252726Srpaulo } 1582252726Srpaulo if (sta == NULL) 1583252726Srpaulo return -3; /* Unknown UUID */ 1584252726Srpaulo } 1585252726Srpaulo 1586252726Srpaulo if (ap->ap_settings == NULL) { 1587252726Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: AP settings not known"); 1588252726Srpaulo return -4; 1589252726Srpaulo } 1590252726Srpaulo 1591252726Srpaulo er->set_sel_reg_uuid_filter = uuid; 1592252726Srpaulo res = wps_registrar_button_pushed(er->wps->registrar, NULL); 1593252726Srpaulo er->set_sel_reg_uuid_filter = NULL; 1594252726Srpaulo if (res) 1595214501Srpaulo return -1; 1596214501Srpaulo 1597214501Srpaulo return 0; 1598214501Srpaulo} 1599214501Srpaulo 1600214501Srpaulo 1601214501Srpaulostatic void wps_er_ap_settings_cb(void *ctx, const struct wps_credential *cred) 1602214501Srpaulo{ 1603214501Srpaulo struct wps_er_ap *ap = ctx; 1604252726Srpaulo union wps_event_data data; 1605252726Srpaulo 1606214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: AP Settings received"); 1607214501Srpaulo os_free(ap->ap_settings); 1608214501Srpaulo ap->ap_settings = os_malloc(sizeof(*cred)); 1609214501Srpaulo if (ap->ap_settings) { 1610214501Srpaulo os_memcpy(ap->ap_settings, cred, sizeof(*cred)); 1611214501Srpaulo ap->ap_settings->cred_attr = NULL; 1612214501Srpaulo } 1613214501Srpaulo 1614252726Srpaulo os_memset(&data, 0, sizeof(data)); 1615252726Srpaulo data.ap_settings.uuid = ap->uuid; 1616252726Srpaulo data.ap_settings.cred = cred; 1617252726Srpaulo ap->er->wps->event_cb(ap->er->wps->cb_ctx, WPS_EV_ER_AP_SETTINGS, 1618252726Srpaulo &data); 1619214501Srpaulo} 1620214501Srpaulo 1621214501Srpaulo 1622214501Srpaulostatic void wps_er_http_put_message_cb(void *ctx, struct http_client *c, 1623214501Srpaulo enum http_client_event event) 1624214501Srpaulo{ 1625214501Srpaulo struct wps_er_ap *ap = ctx; 1626214501Srpaulo struct wpabuf *reply; 1627214501Srpaulo char *msg = NULL; 1628214501Srpaulo 1629214501Srpaulo switch (event) { 1630214501Srpaulo case HTTP_CLIENT_OK: 1631214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: PutMessage OK"); 1632214501Srpaulo reply = http_client_get_body(c); 1633214501Srpaulo if (reply == NULL) 1634214501Srpaulo break; 1635214501Srpaulo msg = os_zalloc(wpabuf_len(reply) + 1); 1636214501Srpaulo if (msg == NULL) 1637214501Srpaulo break; 1638214501Srpaulo os_memcpy(msg, wpabuf_head(reply), wpabuf_len(reply)); 1639214501Srpaulo break; 1640214501Srpaulo case HTTP_CLIENT_FAILED: 1641214501Srpaulo case HTTP_CLIENT_INVALID_REPLY: 1642214501Srpaulo case HTTP_CLIENT_TIMEOUT: 1643214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: PutMessage failed"); 1644214501Srpaulo if (ap->wps) { 1645214501Srpaulo wps_deinit(ap->wps); 1646214501Srpaulo ap->wps = NULL; 1647214501Srpaulo } 1648214501Srpaulo break; 1649214501Srpaulo } 1650214501Srpaulo http_client_free(ap->http); 1651214501Srpaulo ap->http = NULL; 1652214501Srpaulo 1653214501Srpaulo if (msg) { 1654214501Srpaulo struct wpabuf *buf; 1655214501Srpaulo enum http_reply_code ret; 1656214501Srpaulo buf = xml_get_base64_item(msg, "NewOutMessage", &ret); 1657214501Srpaulo os_free(msg); 1658214501Srpaulo if (buf == NULL) { 1659214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Could not extract " 1660214501Srpaulo "NewOutMessage from PutMessage response"); 1661252726Srpaulo wps_deinit(ap->wps); 1662252726Srpaulo ap->wps = NULL; 1663214501Srpaulo return; 1664214501Srpaulo } 1665214501Srpaulo wps_er_ap_process(ap, buf); 1666214501Srpaulo wpabuf_free(buf); 1667214501Srpaulo } 1668214501Srpaulo} 1669214501Srpaulo 1670214501Srpaulo 1671214501Srpaulostatic void wps_er_ap_put_message(struct wps_er_ap *ap, 1672214501Srpaulo const struct wpabuf *msg) 1673214501Srpaulo{ 1674214501Srpaulo struct wpabuf *buf; 1675214501Srpaulo char *len_ptr, *body_ptr; 1676214501Srpaulo struct sockaddr_in dst; 1677214501Srpaulo char *url, *path; 1678214501Srpaulo 1679214501Srpaulo if (ap->http) { 1680214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP operation ongoing " 1681214501Srpaulo "with the AP - cannot continue learn"); 1682214501Srpaulo return; 1683214501Srpaulo } 1684214501Srpaulo 1685214501Srpaulo if (ap->control_url == NULL) { 1686214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP"); 1687214501Srpaulo return; 1688214501Srpaulo } 1689214501Srpaulo 1690214501Srpaulo url = http_client_url_parse(ap->control_url, &dst, &path); 1691214501Srpaulo if (url == NULL) { 1692214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL"); 1693214501Srpaulo return; 1694214501Srpaulo } 1695214501Srpaulo 1696214501Srpaulo buf = wps_er_soap_hdr(msg, "PutMessage", "NewInMessage", path, &dst, 1697214501Srpaulo &len_ptr, &body_ptr); 1698214501Srpaulo os_free(url); 1699214501Srpaulo if (buf == NULL) 1700214501Srpaulo return; 1701214501Srpaulo 1702214501Srpaulo wps_er_soap_end(buf, "PutMessage", len_ptr, body_ptr); 1703214501Srpaulo 1704214501Srpaulo ap->http = http_client_addr(&dst, buf, 10000, 1705214501Srpaulo wps_er_http_put_message_cb, ap); 1706214501Srpaulo if (ap->http == NULL) 1707214501Srpaulo wpabuf_free(buf); 1708214501Srpaulo} 1709214501Srpaulo 1710214501Srpaulo 1711214501Srpaulostatic void wps_er_ap_process(struct wps_er_ap *ap, struct wpabuf *msg) 1712214501Srpaulo{ 1713214501Srpaulo enum wps_process_res res; 1714252726Srpaulo struct wps_parse_attr attr; 1715252726Srpaulo enum wsc_op_code op_code; 1716214501Srpaulo 1717252726Srpaulo op_code = WSC_MSG; 1718252726Srpaulo if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type) { 1719252726Srpaulo switch (*attr.msg_type) { 1720252726Srpaulo case WPS_WSC_ACK: 1721252726Srpaulo op_code = WSC_ACK; 1722252726Srpaulo break; 1723252726Srpaulo case WPS_WSC_NACK: 1724252726Srpaulo op_code = WSC_NACK; 1725252726Srpaulo break; 1726252726Srpaulo case WPS_WSC_DONE: 1727252726Srpaulo op_code = WSC_Done; 1728252726Srpaulo break; 1729252726Srpaulo } 1730252726Srpaulo } 1731252726Srpaulo 1732252726Srpaulo res = wps_process_msg(ap->wps, op_code, msg); 1733214501Srpaulo if (res == WPS_CONTINUE) { 1734214501Srpaulo struct wpabuf *next = wps_get_msg(ap->wps, &op_code); 1735214501Srpaulo if (next) { 1736214501Srpaulo wps_er_ap_put_message(ap, next); 1737214501Srpaulo wpabuf_free(next); 1738214501Srpaulo } else { 1739214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Failed to build " 1740214501Srpaulo "message"); 1741214501Srpaulo wps_deinit(ap->wps); 1742214501Srpaulo ap->wps = NULL; 1743214501Srpaulo } 1744252726Srpaulo } else if (res == WPS_DONE) { 1745252726Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Protocol run done"); 1746252726Srpaulo wps_deinit(ap->wps); 1747252726Srpaulo ap->wps = NULL; 1748214501Srpaulo } else { 1749214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Failed to process message from " 1750214501Srpaulo "AP (res=%d)", res); 1751214501Srpaulo wps_deinit(ap->wps); 1752214501Srpaulo ap->wps = NULL; 1753214501Srpaulo } 1754214501Srpaulo} 1755214501Srpaulo 1756214501Srpaulo 1757214501Srpaulostatic void wps_er_ap_learn_m1(struct wps_er_ap *ap, struct wpabuf *m1) 1758214501Srpaulo{ 1759214501Srpaulo struct wps_config cfg; 1760214501Srpaulo 1761214501Srpaulo if (ap->wps) { 1762214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Protocol run already in " 1763214501Srpaulo "progress with this AP"); 1764214501Srpaulo return; 1765214501Srpaulo } 1766214501Srpaulo 1767214501Srpaulo os_memset(&cfg, 0, sizeof(cfg)); 1768214501Srpaulo cfg.wps = ap->er->wps; 1769214501Srpaulo cfg.registrar = 1; 1770214501Srpaulo ap->wps = wps_init(&cfg); 1771214501Srpaulo if (ap->wps == NULL) 1772214501Srpaulo return; 1773214501Srpaulo ap->wps->ap_settings_cb = wps_er_ap_settings_cb; 1774214501Srpaulo ap->wps->ap_settings_cb_ctx = ap; 1775214501Srpaulo 1776214501Srpaulo wps_er_ap_process(ap, m1); 1777214501Srpaulo} 1778214501Srpaulo 1779214501Srpaulo 1780214501Srpaulostatic void wps_er_ap_learn(struct wps_er_ap *ap, const char *dev_info) 1781214501Srpaulo{ 1782214501Srpaulo struct wpabuf *info; 1783214501Srpaulo enum http_reply_code ret; 1784214501Srpaulo 1785214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Received GetDeviceInfo response (M1) " 1786214501Srpaulo "from the AP"); 1787214501Srpaulo info = xml_get_base64_item(dev_info, "NewDeviceInfo", &ret); 1788214501Srpaulo if (info == NULL) { 1789214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Could not extract " 1790214501Srpaulo "NewDeviceInfo from GetDeviceInfo response"); 1791214501Srpaulo return; 1792214501Srpaulo } 1793214501Srpaulo 1794214501Srpaulo ap->m1_handler(ap, info); 1795214501Srpaulo wpabuf_free(info); 1796214501Srpaulo} 1797214501Srpaulo 1798214501Srpaulo 1799214501Srpaulostatic void wps_er_http_get_dev_info_cb(void *ctx, struct http_client *c, 1800214501Srpaulo enum http_client_event event) 1801214501Srpaulo{ 1802214501Srpaulo struct wps_er_ap *ap = ctx; 1803214501Srpaulo struct wpabuf *reply; 1804214501Srpaulo char *dev_info = NULL; 1805214501Srpaulo 1806214501Srpaulo switch (event) { 1807214501Srpaulo case HTTP_CLIENT_OK: 1808214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: GetDeviceInfo OK"); 1809214501Srpaulo reply = http_client_get_body(c); 1810214501Srpaulo if (reply == NULL) 1811214501Srpaulo break; 1812214501Srpaulo dev_info = os_zalloc(wpabuf_len(reply) + 1); 1813214501Srpaulo if (dev_info == NULL) 1814214501Srpaulo break; 1815214501Srpaulo os_memcpy(dev_info, wpabuf_head(reply), wpabuf_len(reply)); 1816214501Srpaulo break; 1817214501Srpaulo case HTTP_CLIENT_FAILED: 1818214501Srpaulo case HTTP_CLIENT_INVALID_REPLY: 1819214501Srpaulo case HTTP_CLIENT_TIMEOUT: 1820214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: GetDeviceInfo failed"); 1821214501Srpaulo break; 1822214501Srpaulo } 1823214501Srpaulo http_client_free(ap->http); 1824214501Srpaulo ap->http = NULL; 1825214501Srpaulo 1826214501Srpaulo if (dev_info) { 1827214501Srpaulo wps_er_ap_learn(ap, dev_info); 1828214501Srpaulo os_free(dev_info); 1829214501Srpaulo } 1830214501Srpaulo} 1831214501Srpaulo 1832214501Srpaulo 1833214501Srpaulostatic int wps_er_send_get_device_info(struct wps_er_ap *ap, 1834214501Srpaulo void (*m1_handler)(struct wps_er_ap *ap, 1835214501Srpaulo struct wpabuf *m1)) 1836214501Srpaulo{ 1837214501Srpaulo struct wpabuf *buf; 1838214501Srpaulo char *len_ptr, *body_ptr; 1839214501Srpaulo struct sockaddr_in dst; 1840214501Srpaulo char *url, *path; 1841214501Srpaulo 1842214501Srpaulo if (ap->http) { 1843214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP operation ongoing " 1844214501Srpaulo "with the AP - cannot get device info"); 1845214501Srpaulo return -1; 1846214501Srpaulo } 1847214501Srpaulo 1848214501Srpaulo if (ap->control_url == NULL) { 1849214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP"); 1850214501Srpaulo return -1; 1851214501Srpaulo } 1852214501Srpaulo 1853214501Srpaulo url = http_client_url_parse(ap->control_url, &dst, &path); 1854214501Srpaulo if (url == NULL) { 1855214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL"); 1856214501Srpaulo return -1; 1857214501Srpaulo } 1858214501Srpaulo 1859214501Srpaulo buf = wps_er_soap_hdr(NULL, "GetDeviceInfo", NULL, path, &dst, 1860214501Srpaulo &len_ptr, &body_ptr); 1861214501Srpaulo os_free(url); 1862214501Srpaulo if (buf == NULL) 1863214501Srpaulo return -1; 1864214501Srpaulo 1865214501Srpaulo wps_er_soap_end(buf, "GetDeviceInfo", len_ptr, body_ptr); 1866214501Srpaulo 1867214501Srpaulo ap->http = http_client_addr(&dst, buf, 10000, 1868214501Srpaulo wps_er_http_get_dev_info_cb, ap); 1869214501Srpaulo if (ap->http == NULL) { 1870214501Srpaulo wpabuf_free(buf); 1871214501Srpaulo return -1; 1872214501Srpaulo } 1873214501Srpaulo 1874214501Srpaulo ap->m1_handler = m1_handler; 1875214501Srpaulo 1876214501Srpaulo return 0; 1877214501Srpaulo} 1878214501Srpaulo 1879214501Srpaulo 1880214501Srpauloint wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin, 1881214501Srpaulo size_t pin_len) 1882214501Srpaulo{ 1883214501Srpaulo struct wps_er_ap *ap; 1884214501Srpaulo 1885214501Srpaulo if (er == NULL) 1886214501Srpaulo return -1; 1887214501Srpaulo 1888214501Srpaulo ap = wps_er_ap_get(er, NULL, uuid); 1889214501Srpaulo if (ap == NULL) { 1890214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: AP not found for learn " 1891214501Srpaulo "request"); 1892214501Srpaulo return -1; 1893214501Srpaulo } 1894214501Srpaulo if (ap->wps) { 1895214501Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing " 1896214501Srpaulo "with the AP - cannot start learn"); 1897214501Srpaulo return -1; 1898214501Srpaulo } 1899214501Srpaulo 1900214501Srpaulo if (wps_er_send_get_device_info(ap, wps_er_ap_learn_m1) < 0) 1901214501Srpaulo return -1; 1902214501Srpaulo 1903252726Srpaulo er->skip_set_sel_reg = 1; 1904252726Srpaulo wps_registrar_add_pin(er->wps->registrar, NULL, uuid, pin, pin_len, 0); 1905252726Srpaulo er->skip_set_sel_reg = 0; 1906214501Srpaulo 1907214501Srpaulo return 0; 1908214501Srpaulo} 1909252726Srpaulo 1910252726Srpaulo 1911252726Srpauloint wps_er_set_config(struct wps_er *er, const u8 *uuid, 1912252726Srpaulo const struct wps_credential *cred) 1913252726Srpaulo{ 1914252726Srpaulo struct wps_er_ap *ap; 1915252726Srpaulo 1916252726Srpaulo if (er == NULL) 1917252726Srpaulo return -1; 1918252726Srpaulo 1919252726Srpaulo ap = wps_er_ap_get(er, NULL, uuid); 1920252726Srpaulo if (ap == NULL) { 1921252726Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: AP not found for set config " 1922252726Srpaulo "request"); 1923252726Srpaulo return -1; 1924252726Srpaulo } 1925252726Srpaulo 1926252726Srpaulo os_free(ap->ap_settings); 1927252726Srpaulo ap->ap_settings = os_malloc(sizeof(*cred)); 1928252726Srpaulo if (ap->ap_settings == NULL) 1929252726Srpaulo return -1; 1930252726Srpaulo os_memcpy(ap->ap_settings, cred, sizeof(*cred)); 1931252726Srpaulo ap->ap_settings->cred_attr = NULL; 1932252726Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Updated local AP settings based set " 1933252726Srpaulo "config request"); 1934252726Srpaulo 1935252726Srpaulo return 0; 1936252726Srpaulo} 1937252726Srpaulo 1938252726Srpaulo 1939252726Srpaulostatic void wps_er_ap_config_m1(struct wps_er_ap *ap, struct wpabuf *m1) 1940252726Srpaulo{ 1941252726Srpaulo struct wps_config cfg; 1942252726Srpaulo 1943252726Srpaulo if (ap->wps) { 1944252726Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Protocol run already in " 1945252726Srpaulo "progress with this AP"); 1946252726Srpaulo return; 1947252726Srpaulo } 1948252726Srpaulo 1949252726Srpaulo os_memset(&cfg, 0, sizeof(cfg)); 1950252726Srpaulo cfg.wps = ap->er->wps; 1951252726Srpaulo cfg.registrar = 1; 1952252726Srpaulo cfg.new_ap_settings = ap->ap_settings; 1953252726Srpaulo ap->wps = wps_init(&cfg); 1954252726Srpaulo if (ap->wps == NULL) 1955252726Srpaulo return; 1956252726Srpaulo ap->wps->ap_settings_cb = NULL; 1957252726Srpaulo ap->wps->ap_settings_cb_ctx = NULL; 1958252726Srpaulo 1959252726Srpaulo wps_er_ap_process(ap, m1); 1960252726Srpaulo} 1961252726Srpaulo 1962252726Srpaulo 1963252726Srpauloint wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin, 1964252726Srpaulo size_t pin_len, const struct wps_credential *cred) 1965252726Srpaulo{ 1966252726Srpaulo struct wps_er_ap *ap; 1967252726Srpaulo 1968252726Srpaulo if (er == NULL) 1969252726Srpaulo return -1; 1970252726Srpaulo 1971252726Srpaulo ap = wps_er_ap_get(er, NULL, uuid); 1972252726Srpaulo if (ap == NULL) { 1973252726Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: AP not found for config " 1974252726Srpaulo "request"); 1975252726Srpaulo return -1; 1976252726Srpaulo } 1977252726Srpaulo if (ap->wps) { 1978252726Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing " 1979252726Srpaulo "with the AP - cannot start config"); 1980252726Srpaulo return -1; 1981252726Srpaulo } 1982252726Srpaulo 1983252726Srpaulo os_free(ap->ap_settings); 1984252726Srpaulo ap->ap_settings = os_malloc(sizeof(*cred)); 1985252726Srpaulo if (ap->ap_settings == NULL) 1986252726Srpaulo return -1; 1987252726Srpaulo os_memcpy(ap->ap_settings, cred, sizeof(*cred)); 1988252726Srpaulo ap->ap_settings->cred_attr = NULL; 1989252726Srpaulo 1990252726Srpaulo if (wps_er_send_get_device_info(ap, wps_er_ap_config_m1) < 0) 1991252726Srpaulo return -1; 1992252726Srpaulo 1993252726Srpaulo er->skip_set_sel_reg = 1; 1994252726Srpaulo wps_registrar_add_pin(er->wps->registrar, NULL, uuid, pin, pin_len, 0); 1995252726Srpaulo er->skip_set_sel_reg = 0; 1996252726Srpaulo 1997252726Srpaulo return 0; 1998252726Srpaulo} 1999252726Srpaulo 2000252726Srpaulo 2001252726Srpaulo#ifdef CONFIG_WPS_NFC 2002252726Srpaulostruct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid) 2003252726Srpaulo{ 2004252726Srpaulo struct wps_er_ap *ap; 2005252726Srpaulo struct wpabuf *ret; 2006252726Srpaulo struct wps_data data; 2007252726Srpaulo 2008252726Srpaulo if (er == NULL) 2009252726Srpaulo return NULL; 2010252726Srpaulo 2011252726Srpaulo ap = wps_er_ap_get(er, NULL, uuid); 2012252726Srpaulo if (ap == NULL) 2013252726Srpaulo return NULL; 2014252726Srpaulo if (ap->ap_settings == NULL) { 2015252726Srpaulo wpa_printf(MSG_DEBUG, "WPS ER: No settings known for the " 2016252726Srpaulo "selected AP"); 2017252726Srpaulo return NULL; 2018252726Srpaulo } 2019252726Srpaulo 2020252726Srpaulo ret = wpabuf_alloc(500); 2021252726Srpaulo if (ret == NULL) 2022252726Srpaulo return NULL; 2023252726Srpaulo 2024252726Srpaulo os_memset(&data, 0, sizeof(data)); 2025252726Srpaulo data.wps = er->wps; 2026252726Srpaulo data.use_cred = ap->ap_settings; 2027252726Srpaulo if (wps_build_version(ret) || 2028252726Srpaulo wps_build_cred(&data, ret) || 2029252726Srpaulo wps_build_wfa_ext(ret, 0, NULL, 0)) { 2030252726Srpaulo wpabuf_free(ret); 2031252726Srpaulo return NULL; 2032252726Srpaulo } 2033252726Srpaulo 2034252726Srpaulo return ret; 2035252726Srpaulo} 2036252726Srpaulo#endif /* CONFIG_WPS_NFC */ 2037