18dbcf02cSchristos /* 28dbcf02cSchristos * Wi-Fi Protected Setup - External Registrar 38dbcf02cSchristos * Copyright (c) 2009, Jouni Malinen <j@w1.fi> 48dbcf02cSchristos * 58dbcf02cSchristos * This program is free software; you can redistribute it and/or modify 68dbcf02cSchristos * it under the terms of the GNU General Public License version 2 as 78dbcf02cSchristos * published by the Free Software Foundation. 88dbcf02cSchristos * 98dbcf02cSchristos * Alternatively, this software may be distributed under the terms of BSD 108dbcf02cSchristos * license. 118dbcf02cSchristos * 128dbcf02cSchristos * See README and COPYING for more details. 138dbcf02cSchristos */ 148dbcf02cSchristos 158dbcf02cSchristos #include "includes.h" 168dbcf02cSchristos 178dbcf02cSchristos #include "common.h" 188dbcf02cSchristos #include "base64.h" 198dbcf02cSchristos #include "uuid.h" 208dbcf02cSchristos #include "eloop.h" 218dbcf02cSchristos #include "httpread.h" 228dbcf02cSchristos #include "http_client.h" 238dbcf02cSchristos #include "http_server.h" 248dbcf02cSchristos #include "upnp_xml.h" 258dbcf02cSchristos #include "wps_i.h" 268dbcf02cSchristos #include "wps_upnp.h" 278dbcf02cSchristos #include "wps_upnp_i.h" 288dbcf02cSchristos #include "wps_er.h" 298dbcf02cSchristos 308dbcf02cSchristos 318dbcf02cSchristos static void wps_er_deinit_finish(void *eloop_data, void *user_ctx); 328dbcf02cSchristos static void wps_er_ap_timeout(void *eloop_data, void *user_ctx); 338dbcf02cSchristos static void wps_er_sta_timeout(void *eloop_data, void *user_ctx); 348dbcf02cSchristos static void wps_er_ap_process(struct wps_er_ap *ap, struct wpabuf *msg); 358dbcf02cSchristos static int wps_er_send_get_device_info(struct wps_er_ap *ap, 368dbcf02cSchristos void (*m1_handler)(struct wps_er_ap *ap, 378dbcf02cSchristos struct wpabuf *m1)); 388dbcf02cSchristos 398dbcf02cSchristos 408dbcf02cSchristos static void wps_er_sta_event(struct wps_context *wps, struct wps_er_sta *sta, 418dbcf02cSchristos enum wps_event event) 428dbcf02cSchristos { 438dbcf02cSchristos union wps_event_data data; 448dbcf02cSchristos struct wps_event_er_enrollee *ev = &data.enrollee; 458dbcf02cSchristos 468dbcf02cSchristos if (wps->event_cb == NULL) 478dbcf02cSchristos return; 488dbcf02cSchristos 498dbcf02cSchristos os_memset(&data, 0, sizeof(data)); 508dbcf02cSchristos ev->uuid = sta->uuid; 518dbcf02cSchristos ev->mac_addr = sta->addr; 528dbcf02cSchristos ev->m1_received = sta->m1_received; 538dbcf02cSchristos ev->config_methods = sta->config_methods; 548dbcf02cSchristos ev->dev_passwd_id = sta->dev_passwd_id; 558dbcf02cSchristos ev->pri_dev_type = sta->pri_dev_type; 568dbcf02cSchristos ev->dev_name = sta->dev_name; 578dbcf02cSchristos ev->manufacturer = sta->manufacturer; 588dbcf02cSchristos ev->model_name = sta->model_name; 598dbcf02cSchristos ev->model_number = sta->model_number; 608dbcf02cSchristos ev->serial_number = sta->serial_number; 618dbcf02cSchristos wps->event_cb(wps->cb_ctx, event, &data); 628dbcf02cSchristos } 638dbcf02cSchristos 648dbcf02cSchristos 65*42669be3Schristos static struct wps_er_sta * wps_er_sta_get(struct wps_er_ap *ap, const u8 *addr, 66*42669be3Schristos const u8 *uuid) 678dbcf02cSchristos { 688dbcf02cSchristos struct wps_er_sta *sta; 698dbcf02cSchristos dl_list_for_each(sta, &ap->sta, struct wps_er_sta, list) { 70*42669be3Schristos if ((addr == NULL || 71*42669be3Schristos os_memcmp(sta->addr, addr, ETH_ALEN) == 0) && 72*42669be3Schristos (uuid == NULL || 73*42669be3Schristos os_memcmp(uuid, sta->uuid, WPS_UUID_LEN) == 0)) 748dbcf02cSchristos return sta; 758dbcf02cSchristos } 768dbcf02cSchristos return NULL; 778dbcf02cSchristos } 788dbcf02cSchristos 798dbcf02cSchristos 808dbcf02cSchristos static void wps_er_sta_free(struct wps_er_sta *sta) 818dbcf02cSchristos { 828dbcf02cSchristos wps_er_sta_event(sta->ap->er->wps, sta, WPS_EV_ER_ENROLLEE_REMOVE); 838dbcf02cSchristos if (sta->wps) 848dbcf02cSchristos wps_deinit(sta->wps); 858dbcf02cSchristos os_free(sta->manufacturer); 868dbcf02cSchristos os_free(sta->model_name); 878dbcf02cSchristos os_free(sta->model_number); 888dbcf02cSchristos os_free(sta->serial_number); 898dbcf02cSchristos os_free(sta->dev_name); 908dbcf02cSchristos http_client_free(sta->http); 918dbcf02cSchristos eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL); 921b7205bfSchristos os_free(sta->cred); 938dbcf02cSchristos os_free(sta); 948dbcf02cSchristos } 958dbcf02cSchristos 968dbcf02cSchristos 978dbcf02cSchristos static void wps_er_sta_remove_all(struct wps_er_ap *ap) 988dbcf02cSchristos { 998dbcf02cSchristos struct wps_er_sta *prev, *sta; 1008dbcf02cSchristos dl_list_for_each_safe(sta, prev, &ap->sta, struct wps_er_sta, list) 1018dbcf02cSchristos wps_er_sta_free(sta); 1028dbcf02cSchristos } 1038dbcf02cSchristos 1048dbcf02cSchristos 1058dbcf02cSchristos static struct wps_er_ap * wps_er_ap_get(struct wps_er *er, 1068dbcf02cSchristos struct in_addr *addr, const u8 *uuid) 1078dbcf02cSchristos { 1088dbcf02cSchristos struct wps_er_ap *ap; 1098dbcf02cSchristos dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) { 1108dbcf02cSchristos if ((addr == NULL || ap->addr.s_addr == addr->s_addr) && 1118dbcf02cSchristos (uuid == NULL || 1128dbcf02cSchristos os_memcmp(uuid, ap->uuid, WPS_UUID_LEN) == 0)) 1138dbcf02cSchristos return ap; 1148dbcf02cSchristos } 1158dbcf02cSchristos return NULL; 1168dbcf02cSchristos } 1178dbcf02cSchristos 1188dbcf02cSchristos 1198dbcf02cSchristos static struct wps_er_ap * wps_er_ap_get_id(struct wps_er *er, unsigned int id) 1208dbcf02cSchristos { 1218dbcf02cSchristos struct wps_er_ap *ap; 1228dbcf02cSchristos dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) { 1238dbcf02cSchristos if (ap->id == id) 1248dbcf02cSchristos return ap; 1258dbcf02cSchristos } 1268dbcf02cSchristos return NULL; 1278dbcf02cSchristos } 1288dbcf02cSchristos 1298dbcf02cSchristos 1308dbcf02cSchristos static void wps_er_ap_event(struct wps_context *wps, struct wps_er_ap *ap, 1318dbcf02cSchristos enum wps_event event) 1328dbcf02cSchristos { 1338dbcf02cSchristos union wps_event_data data; 1348dbcf02cSchristos struct wps_event_er_ap *evap = &data.ap; 1358dbcf02cSchristos 1368dbcf02cSchristos if (wps->event_cb == NULL) 1378dbcf02cSchristos return; 1388dbcf02cSchristos 1398dbcf02cSchristos os_memset(&data, 0, sizeof(data)); 1408dbcf02cSchristos evap->uuid = ap->uuid; 1418dbcf02cSchristos evap->friendly_name = ap->friendly_name; 1428dbcf02cSchristos evap->manufacturer = ap->manufacturer; 1438dbcf02cSchristos evap->manufacturer_url = ap->manufacturer_url; 1448dbcf02cSchristos evap->model_description = ap->model_description; 1458dbcf02cSchristos evap->model_name = ap->model_name; 1468dbcf02cSchristos evap->model_number = ap->model_number; 1478dbcf02cSchristos evap->model_url = ap->model_url; 1488dbcf02cSchristos evap->serial_number = ap->serial_number; 1498dbcf02cSchristos evap->upc = ap->upc; 1508dbcf02cSchristos evap->pri_dev_type = ap->pri_dev_type; 1518dbcf02cSchristos evap->wps_state = ap->wps_state; 1528dbcf02cSchristos evap->mac_addr = ap->mac_addr; 1538dbcf02cSchristos wps->event_cb(wps->cb_ctx, event, &data); 1548dbcf02cSchristos } 1558dbcf02cSchristos 1568dbcf02cSchristos 1578dbcf02cSchristos static void wps_er_ap_free(struct wps_er_ap *ap) 1588dbcf02cSchristos { 1598dbcf02cSchristos http_client_free(ap->http); 1608dbcf02cSchristos ap->http = NULL; 1618dbcf02cSchristos 1628dbcf02cSchristos os_free(ap->location); 1638dbcf02cSchristos os_free(ap->friendly_name); 1648dbcf02cSchristos os_free(ap->manufacturer); 1658dbcf02cSchristos os_free(ap->manufacturer_url); 1668dbcf02cSchristos os_free(ap->model_description); 1678dbcf02cSchristos os_free(ap->model_name); 1688dbcf02cSchristos os_free(ap->model_number); 1698dbcf02cSchristos os_free(ap->model_url); 1708dbcf02cSchristos os_free(ap->serial_number); 1718dbcf02cSchristos os_free(ap->udn); 1728dbcf02cSchristos os_free(ap->upc); 1738dbcf02cSchristos 1748dbcf02cSchristos os_free(ap->scpd_url); 1758dbcf02cSchristos os_free(ap->control_url); 1768dbcf02cSchristos os_free(ap->event_sub_url); 1778dbcf02cSchristos 1788dbcf02cSchristos os_free(ap->ap_settings); 1798dbcf02cSchristos 1808dbcf02cSchristos os_free(ap); 1818dbcf02cSchristos } 1828dbcf02cSchristos 1838dbcf02cSchristos 1848dbcf02cSchristos static void wps_er_ap_unsubscribed(struct wps_er *er, struct wps_er_ap *ap) 1858dbcf02cSchristos { 1868dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Unsubscribed from AP %s (%s)", 1878dbcf02cSchristos inet_ntoa(ap->addr), ap->location); 1888dbcf02cSchristos dl_list_del(&ap->list); 1898dbcf02cSchristos wps_er_ap_free(ap); 1908dbcf02cSchristos 1918dbcf02cSchristos if (er->deinitializing && dl_list_empty(&er->ap_unsubscribing)) { 1928dbcf02cSchristos eloop_cancel_timeout(wps_er_deinit_finish, er, NULL); 1938dbcf02cSchristos wps_er_deinit_finish(er, NULL); 1948dbcf02cSchristos } 1958dbcf02cSchristos } 1968dbcf02cSchristos 1978dbcf02cSchristos 1988dbcf02cSchristos static void wps_er_http_unsubscribe_cb(void *ctx, struct http_client *c, 1998dbcf02cSchristos enum http_client_event event) 2008dbcf02cSchristos { 2018dbcf02cSchristos struct wps_er_ap *ap = ctx; 2028dbcf02cSchristos 2038dbcf02cSchristos switch (event) { 2048dbcf02cSchristos case HTTP_CLIENT_OK: 2058dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Unsubscribed from events"); 2068dbcf02cSchristos ap->subscribed = 0; 2078dbcf02cSchristos break; 2088dbcf02cSchristos case HTTP_CLIENT_FAILED: 2098dbcf02cSchristos case HTTP_CLIENT_INVALID_REPLY: 2108dbcf02cSchristos case HTTP_CLIENT_TIMEOUT: 2118dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to unsubscribe from " 2128dbcf02cSchristos "events"); 2138dbcf02cSchristos break; 2148dbcf02cSchristos } 2158dbcf02cSchristos http_client_free(ap->http); 2168dbcf02cSchristos ap->http = NULL; 2178dbcf02cSchristos 2188dbcf02cSchristos /* 2198dbcf02cSchristos * Need to get rid of the AP entry regardless of whether we managed to 2208dbcf02cSchristos * unsubscribe cleanly or not. 2218dbcf02cSchristos */ 2228dbcf02cSchristos wps_er_ap_unsubscribed(ap->er, ap); 2238dbcf02cSchristos } 2248dbcf02cSchristos 2258dbcf02cSchristos 2268dbcf02cSchristos static void wps_er_ap_unsubscribe(struct wps_er *er, struct wps_er_ap *ap) 2278dbcf02cSchristos { 2288dbcf02cSchristos struct wpabuf *req; 2298dbcf02cSchristos struct sockaddr_in dst; 2308dbcf02cSchristos char *url, *path; 2318dbcf02cSchristos char sid[100]; 2328dbcf02cSchristos 2338dbcf02cSchristos if (ap->event_sub_url == NULL) { 2348dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: No eventSubURL - cannot " 2358dbcf02cSchristos "subscribe"); 2368dbcf02cSchristos goto fail; 2378dbcf02cSchristos } 2388dbcf02cSchristos if (ap->http) { 2398dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request - cannot " 2408dbcf02cSchristos "send subscribe request"); 2418dbcf02cSchristos goto fail; 2428dbcf02cSchristos } 2438dbcf02cSchristos 2448dbcf02cSchristos url = http_client_url_parse(ap->event_sub_url, &dst, &path); 2458dbcf02cSchristos if (url == NULL) { 2468dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse eventSubURL"); 2478dbcf02cSchristos goto fail; 2488dbcf02cSchristos } 2498dbcf02cSchristos 2508dbcf02cSchristos req = wpabuf_alloc(os_strlen(ap->event_sub_url) + 1000); 2518dbcf02cSchristos if (req == NULL) { 2528dbcf02cSchristos os_free(url); 2538dbcf02cSchristos goto fail; 2548dbcf02cSchristos } 2558dbcf02cSchristos uuid_bin2str(ap->sid, sid, sizeof(sid)); 2568dbcf02cSchristos wpabuf_printf(req, 2578dbcf02cSchristos "UNSUBSCRIBE %s HTTP/1.1\r\n" 2588dbcf02cSchristos "HOST: %s:%d\r\n" 2598dbcf02cSchristos "SID: uuid:%s\r\n" 2608dbcf02cSchristos "\r\n", 2618dbcf02cSchristos path, inet_ntoa(dst.sin_addr), ntohs(dst.sin_port), sid); 2628dbcf02cSchristos os_free(url); 2638dbcf02cSchristos wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Unsubscription request", 2648dbcf02cSchristos wpabuf_head(req), wpabuf_len(req)); 2658dbcf02cSchristos 2668dbcf02cSchristos ap->http = http_client_addr(&dst, req, 1000, 2678dbcf02cSchristos wps_er_http_unsubscribe_cb, ap); 2688dbcf02cSchristos if (ap->http == NULL) { 2698dbcf02cSchristos wpabuf_free(req); 2708dbcf02cSchristos goto fail; 2718dbcf02cSchristos } 2728dbcf02cSchristos return; 2738dbcf02cSchristos 2748dbcf02cSchristos fail: 2758dbcf02cSchristos /* 2768dbcf02cSchristos * Need to get rid of the AP entry even when we fail to unsubscribe 2778dbcf02cSchristos * cleanly. 2788dbcf02cSchristos */ 2798dbcf02cSchristos wps_er_ap_unsubscribed(ap->er, ap); 2808dbcf02cSchristos } 2818dbcf02cSchristos 282*42669be3Schristos 283*42669be3Schristos static struct wps_er_ap_settings * wps_er_ap_get_settings(struct wps_er *er, 284*42669be3Schristos const u8 *uuid) 285*42669be3Schristos { 286*42669be3Schristos struct wps_er_ap_settings *s; 287*42669be3Schristos dl_list_for_each(s, &er->ap_settings, struct wps_er_ap_settings, list) 288*42669be3Schristos if (os_memcmp(uuid, s->uuid, WPS_UUID_LEN) == 0) 289*42669be3Schristos return s; 290*42669be3Schristos return NULL; 291*42669be3Schristos } 292*42669be3Schristos 293*42669be3Schristos 294*42669be3Schristos int wps_er_ap_cache_settings(struct wps_er *er, struct in_addr *addr) 295*42669be3Schristos { 296*42669be3Schristos struct wps_er_ap *ap; 297*42669be3Schristos struct wps_er_ap_settings *settings; 298*42669be3Schristos 299*42669be3Schristos ap = wps_er_ap_get(er, addr, NULL); 300*42669be3Schristos if (ap == NULL || ap->ap_settings == NULL) 301*42669be3Schristos return -1; 302*42669be3Schristos 303*42669be3Schristos settings = wps_er_ap_get_settings(er, ap->uuid); 304*42669be3Schristos if (!settings) { 305*42669be3Schristos settings = os_zalloc(sizeof(*settings)); 306*42669be3Schristos if (settings == NULL) 307*42669be3Schristos return -1; 308*42669be3Schristos os_memcpy(settings->uuid, ap->uuid, WPS_UUID_LEN); 309*42669be3Schristos dl_list_add(&er->ap_settings, &settings->list); 310*42669be3Schristos } 311*42669be3Schristos os_memcpy(&settings->ap_settings, ap->ap_settings, 312*42669be3Schristos sizeof(struct wps_credential)); 313*42669be3Schristos 314*42669be3Schristos return 0; 315*42669be3Schristos } 316*42669be3Schristos 317*42669be3Schristos 318*42669be3Schristos static int wps_er_ap_use_cached_settings(struct wps_er *er, 319*42669be3Schristos struct wps_er_ap *ap) 320*42669be3Schristos { 321*42669be3Schristos struct wps_er_ap_settings *s; 322*42669be3Schristos 323*42669be3Schristos if (ap->ap_settings) 324*42669be3Schristos return 0; 325*42669be3Schristos 326*42669be3Schristos s = wps_er_ap_get_settings(ap->er, ap->uuid); 327*42669be3Schristos if (!s) 328*42669be3Schristos return -1; 329*42669be3Schristos 330*42669be3Schristos ap->ap_settings = os_malloc(sizeof(*ap->ap_settings)); 331*42669be3Schristos if (ap->ap_settings == NULL) 332*42669be3Schristos return -1; 333*42669be3Schristos 334*42669be3Schristos os_memcpy(ap->ap_settings, &s->ap_settings, sizeof(*ap->ap_settings)); 335*42669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: Use cached AP settings"); 336*42669be3Schristos return 0; 337*42669be3Schristos } 338*42669be3Schristos 339*42669be3Schristos 3408dbcf02cSchristos static void wps_er_ap_remove_entry(struct wps_er *er, struct wps_er_ap *ap) 3418dbcf02cSchristos { 3428dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Removing AP entry for %s (%s)", 3438dbcf02cSchristos inet_ntoa(ap->addr), ap->location); 3448dbcf02cSchristos eloop_cancel_timeout(wps_er_ap_timeout, er, ap); 3458dbcf02cSchristos wps_er_sta_remove_all(ap); 3468dbcf02cSchristos wps_er_ap_event(er->wps, ap, WPS_EV_ER_AP_REMOVE); 3478dbcf02cSchristos http_client_free(ap->http); 3488dbcf02cSchristos ap->http = NULL; 3498dbcf02cSchristos if (ap->wps) { 3508dbcf02cSchristos wps_deinit(ap->wps); 3518dbcf02cSchristos ap->wps = NULL; 3528dbcf02cSchristos } 3538dbcf02cSchristos 3548dbcf02cSchristos dl_list_del(&ap->list); 3558dbcf02cSchristos if (ap->subscribed) { 3568dbcf02cSchristos dl_list_add(&er->ap_unsubscribing, &ap->list); 3578dbcf02cSchristos wps_er_ap_unsubscribe(er, ap); 3588dbcf02cSchristos } else 3598dbcf02cSchristos wps_er_ap_free(ap); 3608dbcf02cSchristos } 3618dbcf02cSchristos 3628dbcf02cSchristos 3638dbcf02cSchristos static void wps_er_ap_timeout(void *eloop_data, void *user_ctx) 3648dbcf02cSchristos { 3658dbcf02cSchristos struct wps_er *er = eloop_data; 3668dbcf02cSchristos struct wps_er_ap *ap = user_ctx; 3678dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: AP advertisement timed out"); 3688dbcf02cSchristos wps_er_ap_remove_entry(er, ap); 3698dbcf02cSchristos } 3708dbcf02cSchristos 3718dbcf02cSchristos 3728dbcf02cSchristos static int wps_er_get_sid(struct wps_er_ap *ap, char *sid) 3738dbcf02cSchristos { 3748dbcf02cSchristos char *pos; 3758dbcf02cSchristos char txt[100]; 3768dbcf02cSchristos 3778dbcf02cSchristos if (!sid) { 3788dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: No SID received from %s (%s)", 3798dbcf02cSchristos inet_ntoa(ap->addr), ap->location); 3808dbcf02cSchristos return -1; 3818dbcf02cSchristos } 3828dbcf02cSchristos 3838dbcf02cSchristos pos = os_strstr(sid, "uuid:"); 3848dbcf02cSchristos if (!pos) { 3858dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Invalid SID received from " 3868dbcf02cSchristos "%s (%s): '%s'", inet_ntoa(ap->addr), ap->location, 3878dbcf02cSchristos sid); 3888dbcf02cSchristos return -1; 3898dbcf02cSchristos } 3908dbcf02cSchristos 3918dbcf02cSchristos pos += 5; 3928dbcf02cSchristos if (uuid_str2bin(pos, ap->sid) < 0) { 3938dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Invalid SID received from " 3948dbcf02cSchristos "%s (%s): '%s'", inet_ntoa(ap->addr), ap->location, 3958dbcf02cSchristos sid); 3968dbcf02cSchristos return -1; 3978dbcf02cSchristos } 3988dbcf02cSchristos 3998dbcf02cSchristos uuid_bin2str(ap->sid, txt, sizeof(txt)); 4008dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: SID for subscription with %s (%s): %s", 4018dbcf02cSchristos inet_ntoa(ap->addr), ap->location, txt); 4028dbcf02cSchristos 4038dbcf02cSchristos return 0; 4048dbcf02cSchristos } 4058dbcf02cSchristos 4068dbcf02cSchristos 4078dbcf02cSchristos static void wps_er_http_subscribe_cb(void *ctx, struct http_client *c, 4088dbcf02cSchristos enum http_client_event event) 4098dbcf02cSchristos { 4108dbcf02cSchristos struct wps_er_ap *ap = ctx; 4118dbcf02cSchristos 4128dbcf02cSchristos switch (event) { 4138dbcf02cSchristos case HTTP_CLIENT_OK: 4148dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Subscribed to events"); 4158dbcf02cSchristos ap->subscribed = 1; 4168dbcf02cSchristos wps_er_get_sid(ap, http_client_get_hdr_line(c, "SID")); 417*42669be3Schristos wps_er_ap_use_cached_settings(ap->er, ap); 4188dbcf02cSchristos wps_er_ap_event(ap->er->wps, ap, WPS_EV_ER_AP_ADD); 4198dbcf02cSchristos break; 4208dbcf02cSchristos case HTTP_CLIENT_FAILED: 4218dbcf02cSchristos case HTTP_CLIENT_INVALID_REPLY: 4228dbcf02cSchristos case HTTP_CLIENT_TIMEOUT: 4238dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to subscribe to events"); 4248dbcf02cSchristos break; 4258dbcf02cSchristos } 4268dbcf02cSchristos http_client_free(ap->http); 4278dbcf02cSchristos ap->http = NULL; 4288dbcf02cSchristos } 4298dbcf02cSchristos 4308dbcf02cSchristos 4318dbcf02cSchristos static void wps_er_subscribe(struct wps_er_ap *ap) 4328dbcf02cSchristos { 4338dbcf02cSchristos struct wpabuf *req; 4348dbcf02cSchristos struct sockaddr_in dst; 4358dbcf02cSchristos char *url, *path; 4368dbcf02cSchristos 4378dbcf02cSchristos if (ap->event_sub_url == NULL) { 4388dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: No eventSubURL - cannot " 4398dbcf02cSchristos "subscribe"); 4408dbcf02cSchristos return; 4418dbcf02cSchristos } 4428dbcf02cSchristos if (ap->http) { 4438dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request - cannot " 4448dbcf02cSchristos "send subscribe request"); 4458dbcf02cSchristos return; 4468dbcf02cSchristos } 4478dbcf02cSchristos 4488dbcf02cSchristos url = http_client_url_parse(ap->event_sub_url, &dst, &path); 4498dbcf02cSchristos if (url == NULL) { 4508dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse eventSubURL"); 4518dbcf02cSchristos return; 4528dbcf02cSchristos } 4538dbcf02cSchristos 4548dbcf02cSchristos req = wpabuf_alloc(os_strlen(ap->event_sub_url) + 1000); 4558dbcf02cSchristos if (req == NULL) { 4568dbcf02cSchristos os_free(url); 4578dbcf02cSchristos return; 4588dbcf02cSchristos } 4598dbcf02cSchristos wpabuf_printf(req, 4608dbcf02cSchristos "SUBSCRIBE %s HTTP/1.1\r\n" 4618dbcf02cSchristos "HOST: %s:%d\r\n" 4628dbcf02cSchristos "CALLBACK: <http://%s:%d/event/%u/%u>\r\n" 4638dbcf02cSchristos "NT: upnp:event\r\n" 4648dbcf02cSchristos "TIMEOUT: Second-%d\r\n" 4658dbcf02cSchristos "\r\n", 4668dbcf02cSchristos path, inet_ntoa(dst.sin_addr), ntohs(dst.sin_port), 4678dbcf02cSchristos ap->er->ip_addr_text, ap->er->http_port, 4688dbcf02cSchristos ap->er->event_id, ap->id, 1800); 4698dbcf02cSchristos os_free(url); 4708dbcf02cSchristos wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Subscription request", 4718dbcf02cSchristos wpabuf_head(req), wpabuf_len(req)); 4728dbcf02cSchristos 4738dbcf02cSchristos ap->http = http_client_addr(&dst, req, 1000, wps_er_http_subscribe_cb, 4748dbcf02cSchristos ap); 4758dbcf02cSchristos if (ap->http == NULL) 4768dbcf02cSchristos wpabuf_free(req); 4778dbcf02cSchristos } 4788dbcf02cSchristos 4798dbcf02cSchristos 4808dbcf02cSchristos static void wps_er_ap_get_m1(struct wps_er_ap *ap, struct wpabuf *m1) 4818dbcf02cSchristos { 4828dbcf02cSchristos struct wps_parse_attr attr; 4838dbcf02cSchristos 4848dbcf02cSchristos if (wps_parse_msg(m1, &attr) < 0) { 4858dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse M1"); 4868dbcf02cSchristos return; 4878dbcf02cSchristos } 4888dbcf02cSchristos if (attr.primary_dev_type) 4898dbcf02cSchristos os_memcpy(ap->pri_dev_type, attr.primary_dev_type, 8); 4908dbcf02cSchristos if (attr.wps_state) 4918dbcf02cSchristos ap->wps_state = *attr.wps_state; 4928dbcf02cSchristos if (attr.mac_addr) 4938dbcf02cSchristos os_memcpy(ap->mac_addr, attr.mac_addr, ETH_ALEN); 4948dbcf02cSchristos 4958dbcf02cSchristos wps_er_subscribe(ap); 4968dbcf02cSchristos } 4978dbcf02cSchristos 4988dbcf02cSchristos 4998dbcf02cSchristos static void wps_er_get_device_info(struct wps_er_ap *ap) 5008dbcf02cSchristos { 5018dbcf02cSchristos wps_er_send_get_device_info(ap, wps_er_ap_get_m1); 5028dbcf02cSchristos } 5038dbcf02cSchristos 5048dbcf02cSchristos 505*42669be3Schristos static const char * wps_er_find_wfadevice(const char *data) 506*42669be3Schristos { 507*42669be3Schristos const char *tag, *tagname, *end; 508*42669be3Schristos char *val; 509*42669be3Schristos int found = 0; 510*42669be3Schristos 511*42669be3Schristos while (!found) { 512*42669be3Schristos /* Find next <device> */ 513*42669be3Schristos for (;;) { 514*42669be3Schristos if (xml_next_tag(data, &tag, &tagname, &end)) 515*42669be3Schristos return NULL; 516*42669be3Schristos data = end; 517*42669be3Schristos if (!os_strncasecmp(tagname, "device", 6) && 518*42669be3Schristos *tag != '/' && 519*42669be3Schristos (tagname[6] == '>' || !isgraph(tagname[6]))) { 520*42669be3Schristos break; 521*42669be3Schristos } 522*42669be3Schristos } 523*42669be3Schristos 524*42669be3Schristos /* Check whether deviceType is WFADevice */ 525*42669be3Schristos val = xml_get_first_item(data, "deviceType"); 526*42669be3Schristos if (val == NULL) 527*42669be3Schristos return NULL; 528*42669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: Found deviceType '%s'", val); 529*42669be3Schristos found = os_strcasecmp(val, "urn:schemas-wifialliance-org:" 530*42669be3Schristos "device:WFADevice:1") == 0; 531*42669be3Schristos os_free(val); 532*42669be3Schristos } 533*42669be3Schristos 534*42669be3Schristos return data; 535*42669be3Schristos } 536*42669be3Schristos 537*42669be3Schristos 5388dbcf02cSchristos static void wps_er_parse_device_description(struct wps_er_ap *ap, 5398dbcf02cSchristos struct wpabuf *reply) 5408dbcf02cSchristos { 5418dbcf02cSchristos /* Note: reply includes null termination after the buffer data */ 542*42669be3Schristos const char *tmp, *data = wpabuf_head(reply); 5438dbcf02cSchristos char *pos; 5448dbcf02cSchristos 5458dbcf02cSchristos wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Device info", 5468dbcf02cSchristos wpabuf_head(reply), wpabuf_len(reply)); 5478dbcf02cSchristos 548*42669be3Schristos /* 549*42669be3Schristos * The root device description may include multiple devices, so first 550*42669be3Schristos * find the beginning of the WFADevice description to allow the 551*42669be3Schristos * simplistic parser to pick the correct entries. 552*42669be3Schristos */ 553*42669be3Schristos tmp = wps_er_find_wfadevice(data); 554*42669be3Schristos if (tmp == NULL) { 555*42669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: WFADevice:1 device not found - " 556*42669be3Schristos "trying to parse invalid data"); 557*42669be3Schristos } else 558*42669be3Schristos data = tmp; 559*42669be3Schristos 5608dbcf02cSchristos ap->friendly_name = xml_get_first_item(data, "friendlyName"); 5618dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: friendlyName='%s'", ap->friendly_name); 5628dbcf02cSchristos 5638dbcf02cSchristos ap->manufacturer = xml_get_first_item(data, "manufacturer"); 5648dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: manufacturer='%s'", ap->manufacturer); 5658dbcf02cSchristos 5668dbcf02cSchristos ap->manufacturer_url = xml_get_first_item(data, "manufacturerURL"); 5678dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: manufacturerURL='%s'", 5688dbcf02cSchristos ap->manufacturer_url); 5698dbcf02cSchristos 5708dbcf02cSchristos ap->model_description = xml_get_first_item(data, "modelDescription"); 5718dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: modelDescription='%s'", 5728dbcf02cSchristos ap->model_description); 5738dbcf02cSchristos 5748dbcf02cSchristos ap->model_name = xml_get_first_item(data, "modelName"); 5758dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: modelName='%s'", ap->model_name); 5768dbcf02cSchristos 5778dbcf02cSchristos ap->model_number = xml_get_first_item(data, "modelNumber"); 5788dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: modelNumber='%s'", ap->model_number); 5798dbcf02cSchristos 5808dbcf02cSchristos ap->model_url = xml_get_first_item(data, "modelURL"); 5818dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: modelURL='%s'", ap->model_url); 5828dbcf02cSchristos 5838dbcf02cSchristos ap->serial_number = xml_get_first_item(data, "serialNumber"); 5848dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: serialNumber='%s'", ap->serial_number); 5858dbcf02cSchristos 5868dbcf02cSchristos ap->udn = xml_get_first_item(data, "UDN"); 5878dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: UDN='%s'", ap->udn); 5888dbcf02cSchristos pos = os_strstr(ap->udn, "uuid:"); 5898dbcf02cSchristos if (pos) { 5908dbcf02cSchristos pos += 5; 5918dbcf02cSchristos if (uuid_str2bin(pos, ap->uuid) < 0) 5928dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Invalid UUID in UDN"); 5938dbcf02cSchristos } 5948dbcf02cSchristos 5958dbcf02cSchristos ap->upc = xml_get_first_item(data, "UPC"); 5968dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: UPC='%s'", ap->upc); 5978dbcf02cSchristos 5988dbcf02cSchristos ap->scpd_url = http_link_update( 5998dbcf02cSchristos xml_get_first_item(data, "SCPDURL"), ap->location); 6008dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: SCPDURL='%s'", ap->scpd_url); 6018dbcf02cSchristos 6028dbcf02cSchristos ap->control_url = http_link_update( 6038dbcf02cSchristos xml_get_first_item(data, "controlURL"), ap->location); 6048dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: controlURL='%s'", ap->control_url); 6058dbcf02cSchristos 6068dbcf02cSchristos ap->event_sub_url = http_link_update( 6078dbcf02cSchristos xml_get_first_item(data, "eventSubURL"), ap->location); 6088dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: eventSubURL='%s'", ap->event_sub_url); 6098dbcf02cSchristos } 6108dbcf02cSchristos 6118dbcf02cSchristos 6128dbcf02cSchristos static void wps_er_http_dev_desc_cb(void *ctx, struct http_client *c, 6138dbcf02cSchristos enum http_client_event event) 6148dbcf02cSchristos { 6158dbcf02cSchristos struct wps_er_ap *ap = ctx; 6168dbcf02cSchristos struct wpabuf *reply; 6178dbcf02cSchristos int ok = 0; 6188dbcf02cSchristos 6198dbcf02cSchristos switch (event) { 6208dbcf02cSchristos case HTTP_CLIENT_OK: 6218dbcf02cSchristos reply = http_client_get_body(c); 6228dbcf02cSchristos if (reply == NULL) 6238dbcf02cSchristos break; 6248dbcf02cSchristos wps_er_parse_device_description(ap, reply); 6258dbcf02cSchristos ok = 1; 6268dbcf02cSchristos break; 6278dbcf02cSchristos case HTTP_CLIENT_FAILED: 6288dbcf02cSchristos case HTTP_CLIENT_INVALID_REPLY: 6298dbcf02cSchristos case HTTP_CLIENT_TIMEOUT: 6308dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to fetch device info"); 6318dbcf02cSchristos break; 6328dbcf02cSchristos } 6338dbcf02cSchristos http_client_free(ap->http); 6348dbcf02cSchristos ap->http = NULL; 6358dbcf02cSchristos if (ok) 6368dbcf02cSchristos wps_er_get_device_info(ap); 6378dbcf02cSchristos } 6388dbcf02cSchristos 6398dbcf02cSchristos 6408dbcf02cSchristos void wps_er_ap_add(struct wps_er *er, const u8 *uuid, struct in_addr *addr, 6418dbcf02cSchristos const char *location, int max_age) 6428dbcf02cSchristos { 6438dbcf02cSchristos struct wps_er_ap *ap; 6448dbcf02cSchristos 6458dbcf02cSchristos ap = wps_er_ap_get(er, addr, uuid); 6468dbcf02cSchristos if (ap) { 6478dbcf02cSchristos /* Update advertisement timeout */ 6488dbcf02cSchristos eloop_cancel_timeout(wps_er_ap_timeout, er, ap); 6498dbcf02cSchristos eloop_register_timeout(max_age, 0, wps_er_ap_timeout, er, ap); 6508dbcf02cSchristos return; 6518dbcf02cSchristos } 6528dbcf02cSchristos 6538dbcf02cSchristos ap = os_zalloc(sizeof(*ap)); 6548dbcf02cSchristos if (ap == NULL) 6558dbcf02cSchristos return; 6568dbcf02cSchristos dl_list_init(&ap->sta); 6578dbcf02cSchristos ap->er = er; 6588dbcf02cSchristos ap->id = ++er->next_ap_id; 6598dbcf02cSchristos ap->location = os_strdup(location); 6608dbcf02cSchristos if (ap->location == NULL) { 6618dbcf02cSchristos os_free(ap); 6628dbcf02cSchristos return; 6638dbcf02cSchristos } 6648dbcf02cSchristos dl_list_add(&er->ap, &ap->list); 6658dbcf02cSchristos 6668dbcf02cSchristos ap->addr.s_addr = addr->s_addr; 6678dbcf02cSchristos os_memcpy(ap->uuid, uuid, WPS_UUID_LEN); 6688dbcf02cSchristos eloop_register_timeout(max_age, 0, wps_er_ap_timeout, er, ap); 6698dbcf02cSchristos 6708dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Added AP entry for %s (%s)", 6718dbcf02cSchristos inet_ntoa(ap->addr), ap->location); 6728dbcf02cSchristos 6738dbcf02cSchristos /* Fetch device description */ 6748dbcf02cSchristos ap->http = http_client_url(ap->location, NULL, 10000, 6758dbcf02cSchristos wps_er_http_dev_desc_cb, ap); 6768dbcf02cSchristos } 6778dbcf02cSchristos 6788dbcf02cSchristos 6798dbcf02cSchristos void wps_er_ap_remove(struct wps_er *er, struct in_addr *addr) 6808dbcf02cSchristos { 6818dbcf02cSchristos struct wps_er_ap *ap; 6828dbcf02cSchristos dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) { 6838dbcf02cSchristos if (ap->addr.s_addr == addr->s_addr) { 6848dbcf02cSchristos wps_er_ap_remove_entry(er, ap); 6858dbcf02cSchristos return; 6868dbcf02cSchristos } 6878dbcf02cSchristos } 6888dbcf02cSchristos } 6898dbcf02cSchristos 6908dbcf02cSchristos 6918dbcf02cSchristos static void wps_er_ap_remove_all(struct wps_er *er) 6928dbcf02cSchristos { 6938dbcf02cSchristos struct wps_er_ap *prev, *ap; 694*42669be3Schristos struct wps_er_ap_settings *prev_s, *s; 6958dbcf02cSchristos dl_list_for_each_safe(ap, prev, &er->ap, struct wps_er_ap, list) 6968dbcf02cSchristos wps_er_ap_remove_entry(er, ap); 697*42669be3Schristos dl_list_for_each_safe(s, prev_s, &er->ap_settings, 698*42669be3Schristos struct wps_er_ap_settings, list) 699*42669be3Schristos os_free(s); 7008dbcf02cSchristos } 7018dbcf02cSchristos 7028dbcf02cSchristos 7038dbcf02cSchristos static void http_put_date(struct wpabuf *buf) 7048dbcf02cSchristos { 7058dbcf02cSchristos wpabuf_put_str(buf, "Date: "); 7068dbcf02cSchristos format_date(buf); 7078dbcf02cSchristos wpabuf_put_str(buf, "\r\n"); 7088dbcf02cSchristos } 7098dbcf02cSchristos 7108dbcf02cSchristos 7118dbcf02cSchristos static void wps_er_http_resp_not_found(struct http_request *req) 7128dbcf02cSchristos { 7138dbcf02cSchristos struct wpabuf *buf; 7148dbcf02cSchristos buf = wpabuf_alloc(200); 7158dbcf02cSchristos if (buf == NULL) { 7168dbcf02cSchristos http_request_deinit(req); 7178dbcf02cSchristos return; 7188dbcf02cSchristos } 7198dbcf02cSchristos 7208dbcf02cSchristos wpabuf_put_str(buf, 7218dbcf02cSchristos "HTTP/1.1 404 Not Found\r\n" 7228dbcf02cSchristos "Server: unspecified, UPnP/1.0, unspecified\r\n" 7238dbcf02cSchristos "Connection: close\r\n"); 7248dbcf02cSchristos http_put_date(buf); 7258dbcf02cSchristos wpabuf_put_str(buf, "\r\n"); 7268dbcf02cSchristos http_request_send_and_deinit(req, buf); 7278dbcf02cSchristos } 7288dbcf02cSchristos 7298dbcf02cSchristos 7308dbcf02cSchristos static void wps_er_http_resp_ok(struct http_request *req) 7318dbcf02cSchristos { 7328dbcf02cSchristos struct wpabuf *buf; 7338dbcf02cSchristos buf = wpabuf_alloc(200); 7348dbcf02cSchristos if (buf == NULL) { 7358dbcf02cSchristos http_request_deinit(req); 7368dbcf02cSchristos return; 7378dbcf02cSchristos } 7388dbcf02cSchristos 7398dbcf02cSchristos wpabuf_put_str(buf, 7408dbcf02cSchristos "HTTP/1.1 200 OK\r\n" 7418dbcf02cSchristos "Server: unspecified, UPnP/1.0, unspecified\r\n" 7428dbcf02cSchristos "Connection: close\r\n" 7438dbcf02cSchristos "Content-Length: 0\r\n"); 7448dbcf02cSchristos http_put_date(buf); 7458dbcf02cSchristos wpabuf_put_str(buf, "\r\n"); 7468dbcf02cSchristos http_request_send_and_deinit(req, buf); 7478dbcf02cSchristos } 7488dbcf02cSchristos 7498dbcf02cSchristos 7508dbcf02cSchristos static void wps_er_sta_timeout(void *eloop_data, void *user_ctx) 7518dbcf02cSchristos { 7528dbcf02cSchristos struct wps_er_sta *sta = eloop_data; 7538dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: STA entry timed out"); 7548dbcf02cSchristos dl_list_del(&sta->list); 7558dbcf02cSchristos wps_er_sta_free(sta); 7568dbcf02cSchristos } 7578dbcf02cSchristos 7588dbcf02cSchristos 7598dbcf02cSchristos static struct wps_er_sta * wps_er_add_sta_data(struct wps_er_ap *ap, 7608dbcf02cSchristos const u8 *addr, 7618dbcf02cSchristos struct wps_parse_attr *attr, 7628dbcf02cSchristos int probe_req) 7638dbcf02cSchristos { 764*42669be3Schristos struct wps_er_sta *sta = wps_er_sta_get(ap, addr, NULL); 7658dbcf02cSchristos int new_sta = 0; 7668dbcf02cSchristos int m1; 7678dbcf02cSchristos 7688dbcf02cSchristos m1 = !probe_req && attr->msg_type && *attr->msg_type == WPS_M1; 7698dbcf02cSchristos 7708dbcf02cSchristos if (sta == NULL) { 7718dbcf02cSchristos /* 7728dbcf02cSchristos * Only allow new STA entry to be added based on Probe Request 7738dbcf02cSchristos * or M1. This will filter out bogus events and anything that 7748dbcf02cSchristos * may have been ongoing at the time ER subscribed for events. 7758dbcf02cSchristos */ 7768dbcf02cSchristos if (!probe_req && !m1) 7778dbcf02cSchristos return NULL; 7788dbcf02cSchristos 7798dbcf02cSchristos sta = os_zalloc(sizeof(*sta)); 7808dbcf02cSchristos if (sta == NULL) 7818dbcf02cSchristos return NULL; 7828dbcf02cSchristos os_memcpy(sta->addr, addr, ETH_ALEN); 7838dbcf02cSchristos sta->ap = ap; 7848dbcf02cSchristos dl_list_add(&ap->sta, &sta->list); 7858dbcf02cSchristos new_sta = 1; 7868dbcf02cSchristos } 7878dbcf02cSchristos 7888dbcf02cSchristos if (m1) 7898dbcf02cSchristos sta->m1_received = 1; 7908dbcf02cSchristos 7918dbcf02cSchristos if (attr->config_methods && (!probe_req || !sta->m1_received)) 7928dbcf02cSchristos sta->config_methods = WPA_GET_BE16(attr->config_methods); 7938dbcf02cSchristos if (attr->uuid_e && (!probe_req || !sta->m1_received)) 7948dbcf02cSchristos os_memcpy(sta->uuid, attr->uuid_e, WPS_UUID_LEN); 7958dbcf02cSchristos if (attr->primary_dev_type && (!probe_req || !sta->m1_received)) 7968dbcf02cSchristos os_memcpy(sta->pri_dev_type, attr->primary_dev_type, 8); 7978dbcf02cSchristos if (attr->dev_password_id && (!probe_req || !sta->m1_received)) 7988dbcf02cSchristos sta->dev_passwd_id = WPA_GET_BE16(attr->dev_password_id); 7998dbcf02cSchristos 8008dbcf02cSchristos if (attr->manufacturer) { 8018dbcf02cSchristos os_free(sta->manufacturer); 8028dbcf02cSchristos sta->manufacturer = os_malloc(attr->manufacturer_len + 1); 8038dbcf02cSchristos if (sta->manufacturer) { 8048dbcf02cSchristos os_memcpy(sta->manufacturer, attr->manufacturer, 8058dbcf02cSchristos attr->manufacturer_len); 8068dbcf02cSchristos sta->manufacturer[attr->manufacturer_len] = '\0'; 8078dbcf02cSchristos } 8088dbcf02cSchristos } 8098dbcf02cSchristos 8108dbcf02cSchristos if (attr->model_name) { 8118dbcf02cSchristos os_free(sta->model_name); 8128dbcf02cSchristos sta->model_name = os_malloc(attr->model_name_len + 1); 8138dbcf02cSchristos if (sta->model_name) { 8148dbcf02cSchristos os_memcpy(sta->model_name, attr->model_name, 8158dbcf02cSchristos attr->model_name_len); 8168dbcf02cSchristos sta->model_name[attr->model_name_len] = '\0'; 8178dbcf02cSchristos } 8188dbcf02cSchristos } 8198dbcf02cSchristos 8208dbcf02cSchristos if (attr->model_number) { 8218dbcf02cSchristos os_free(sta->model_number); 8228dbcf02cSchristos sta->model_number = os_malloc(attr->model_number_len + 1); 8238dbcf02cSchristos if (sta->model_number) { 8248dbcf02cSchristos os_memcpy(sta->model_number, attr->model_number, 8258dbcf02cSchristos attr->model_number_len); 8268dbcf02cSchristos sta->model_number[attr->model_number_len] = '\0'; 8278dbcf02cSchristos } 8288dbcf02cSchristos } 8298dbcf02cSchristos 8308dbcf02cSchristos if (attr->serial_number) { 8318dbcf02cSchristos os_free(sta->serial_number); 8328dbcf02cSchristos sta->serial_number = os_malloc(attr->serial_number_len + 1); 8338dbcf02cSchristos if (sta->serial_number) { 8348dbcf02cSchristos os_memcpy(sta->serial_number, attr->serial_number, 8358dbcf02cSchristos attr->serial_number_len); 8368dbcf02cSchristos sta->serial_number[attr->serial_number_len] = '\0'; 8378dbcf02cSchristos } 8388dbcf02cSchristos } 8398dbcf02cSchristos 8408dbcf02cSchristos if (attr->dev_name) { 8418dbcf02cSchristos os_free(sta->dev_name); 8428dbcf02cSchristos sta->dev_name = os_malloc(attr->dev_name_len + 1); 8438dbcf02cSchristos if (sta->dev_name) { 8448dbcf02cSchristos os_memcpy(sta->dev_name, attr->dev_name, 8458dbcf02cSchristos attr->dev_name_len); 8468dbcf02cSchristos sta->dev_name[attr->dev_name_len] = '\0'; 8478dbcf02cSchristos } 8488dbcf02cSchristos } 8498dbcf02cSchristos 8508dbcf02cSchristos eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL); 8518dbcf02cSchristos eloop_register_timeout(300, 0, wps_er_sta_timeout, sta, NULL); 8528dbcf02cSchristos 8538dbcf02cSchristos if (m1 || new_sta) 8548dbcf02cSchristos wps_er_sta_event(ap->er->wps, sta, WPS_EV_ER_ENROLLEE_ADD); 8558dbcf02cSchristos 8568dbcf02cSchristos return sta; 8578dbcf02cSchristos } 8588dbcf02cSchristos 8598dbcf02cSchristos 8608dbcf02cSchristos static void wps_er_process_wlanevent_probe_req(struct wps_er_ap *ap, 8618dbcf02cSchristos const u8 *addr, 8628dbcf02cSchristos struct wpabuf *msg) 8638dbcf02cSchristos { 8648dbcf02cSchristos struct wps_parse_attr attr; 8658dbcf02cSchristos 8668dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: WLANEvent - Probe Request - from " 8678dbcf02cSchristos MACSTR, MAC2STR(addr)); 8688dbcf02cSchristos wpa_hexdump_buf(MSG_MSGDUMP, "WPS ER: WLANEvent - Enrollee's message " 8698dbcf02cSchristos "(TLVs from Probe Request)", msg); 8708dbcf02cSchristos 871*42669be3Schristos if (wps_validate_probe_req(msg, addr) < 0) { 872*42669be3Schristos wpa_printf(MSG_INFO, "WPS-STRICT: ER: Ignore invalid proxied " 873*42669be3Schristos "Probe Request frame from " MACSTR, MAC2STR(addr)); 874*42669be3Schristos return; 875*42669be3Schristos } 876*42669be3Schristos 8778dbcf02cSchristos if (wps_parse_msg(msg, &attr) < 0) { 8788dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse TLVs in " 8798dbcf02cSchristos "WLANEvent message"); 8808dbcf02cSchristos return; 8818dbcf02cSchristos } 8828dbcf02cSchristos 8838dbcf02cSchristos wps_er_add_sta_data(ap, addr, &attr, 1); 884*42669be3Schristos wps_registrar_probe_req_rx(ap->er->wps->registrar, addr, msg, 0); 8858dbcf02cSchristos } 8868dbcf02cSchristos 8878dbcf02cSchristos 8888dbcf02cSchristos static void wps_er_http_put_wlan_response_cb(void *ctx, struct http_client *c, 8898dbcf02cSchristos enum http_client_event event) 8908dbcf02cSchristos { 8918dbcf02cSchristos struct wps_er_sta *sta = ctx; 8928dbcf02cSchristos 8938dbcf02cSchristos switch (event) { 8948dbcf02cSchristos case HTTP_CLIENT_OK: 8958dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: PutWLANResponse OK"); 8968dbcf02cSchristos break; 8978dbcf02cSchristos case HTTP_CLIENT_FAILED: 8988dbcf02cSchristos case HTTP_CLIENT_INVALID_REPLY: 8998dbcf02cSchristos case HTTP_CLIENT_TIMEOUT: 9008dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: PutWLANResponse failed"); 9018dbcf02cSchristos break; 9028dbcf02cSchristos } 9038dbcf02cSchristos http_client_free(sta->http); 9048dbcf02cSchristos sta->http = NULL; 9058dbcf02cSchristos } 9068dbcf02cSchristos 9078dbcf02cSchristos 9088dbcf02cSchristos static const char *soap_prefix = 9098dbcf02cSchristos "<?xml version=\"1.0\"?>\n" 9108dbcf02cSchristos "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" " 9118dbcf02cSchristos "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n" 9128dbcf02cSchristos "<s:Body>\n"; 9138dbcf02cSchristos static const char *soap_postfix = 9148dbcf02cSchristos "</s:Body>\n</s:Envelope>\n"; 9158dbcf02cSchristos static const char *urn_wfawlanconfig = 9168dbcf02cSchristos "urn:schemas-wifialliance-org:service:WFAWLANConfig:1"; 9178dbcf02cSchristos 9188dbcf02cSchristos static struct wpabuf * wps_er_soap_hdr(const struct wpabuf *msg, 9198dbcf02cSchristos const char *name, const char *arg_name, 9208dbcf02cSchristos const char *path, 9218dbcf02cSchristos const struct sockaddr_in *dst, 9228dbcf02cSchristos char **len_ptr, char **body_ptr) 9238dbcf02cSchristos { 9248dbcf02cSchristos unsigned char *encoded; 9258dbcf02cSchristos size_t encoded_len; 9268dbcf02cSchristos struct wpabuf *buf; 9278dbcf02cSchristos 9288dbcf02cSchristos if (msg) { 9298dbcf02cSchristos encoded = base64_encode(wpabuf_head(msg), wpabuf_len(msg), 9308dbcf02cSchristos &encoded_len); 9318dbcf02cSchristos if (encoded == NULL) 9328dbcf02cSchristos return NULL; 9338dbcf02cSchristos } else { 9348dbcf02cSchristos encoded = NULL; 9358dbcf02cSchristos encoded_len = 0; 9368dbcf02cSchristos } 9378dbcf02cSchristos 9388dbcf02cSchristos buf = wpabuf_alloc(1000 + encoded_len); 9398dbcf02cSchristos if (buf == NULL) { 9408dbcf02cSchristos os_free(encoded); 9418dbcf02cSchristos return NULL; 9428dbcf02cSchristos } 9438dbcf02cSchristos 9448dbcf02cSchristos wpabuf_printf(buf, 9458dbcf02cSchristos "POST %s HTTP/1.1\r\n" 9468dbcf02cSchristos "Host: %s:%d\r\n" 9478dbcf02cSchristos "Content-Type: text/xml; charset=\"utf-8\"\r\n" 9488dbcf02cSchristos "Content-Length: ", 9498dbcf02cSchristos path, inet_ntoa(dst->sin_addr), ntohs(dst->sin_port)); 9508dbcf02cSchristos 9518dbcf02cSchristos *len_ptr = wpabuf_put(buf, 0); 9528dbcf02cSchristos wpabuf_printf(buf, 9538dbcf02cSchristos " \r\n" 9548dbcf02cSchristos "SOAPACTION: \"%s#%s\"\r\n" 9558dbcf02cSchristos "\r\n", 9568dbcf02cSchristos urn_wfawlanconfig, name); 9578dbcf02cSchristos 9588dbcf02cSchristos *body_ptr = wpabuf_put(buf, 0); 9598dbcf02cSchristos 9608dbcf02cSchristos wpabuf_put_str(buf, soap_prefix); 9618dbcf02cSchristos wpabuf_printf(buf, "<u:%s xmlns:u=\"", name); 9628dbcf02cSchristos wpabuf_put_str(buf, urn_wfawlanconfig); 9638dbcf02cSchristos wpabuf_put_str(buf, "\">\n"); 9648dbcf02cSchristos if (encoded) { 9658dbcf02cSchristos wpabuf_printf(buf, "<%s>%s</%s>\n", 9668dbcf02cSchristos arg_name, (char *) encoded, arg_name); 9678dbcf02cSchristos os_free(encoded); 9688dbcf02cSchristos } 9698dbcf02cSchristos 9708dbcf02cSchristos return buf; 9718dbcf02cSchristos } 9728dbcf02cSchristos 9738dbcf02cSchristos 9748dbcf02cSchristos static void wps_er_soap_end(struct wpabuf *buf, const char *name, 9758dbcf02cSchristos char *len_ptr, char *body_ptr) 9768dbcf02cSchristos { 9778dbcf02cSchristos char len_buf[10]; 9788dbcf02cSchristos wpabuf_printf(buf, "</u:%s>\n", name); 9798dbcf02cSchristos wpabuf_put_str(buf, soap_postfix); 9808dbcf02cSchristos os_snprintf(len_buf, sizeof(len_buf), "%d", 9818dbcf02cSchristos (int) ((char *) wpabuf_put(buf, 0) - body_ptr)); 9828dbcf02cSchristos os_memcpy(len_ptr, len_buf, os_strlen(len_buf)); 9838dbcf02cSchristos } 9848dbcf02cSchristos 9858dbcf02cSchristos 9868dbcf02cSchristos static void wps_er_sta_send_msg(struct wps_er_sta *sta, struct wpabuf *msg) 9878dbcf02cSchristos { 9888dbcf02cSchristos struct wpabuf *buf; 9898dbcf02cSchristos char *len_ptr, *body_ptr; 9908dbcf02cSchristos struct sockaddr_in dst; 9918dbcf02cSchristos char *url, *path; 9928dbcf02cSchristos 9938dbcf02cSchristos if (sta->http) { 9948dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request for STA - " 9958dbcf02cSchristos "ignore new request"); 9968dbcf02cSchristos wpabuf_free(msg); 9978dbcf02cSchristos return; 9988dbcf02cSchristos } 9998dbcf02cSchristos 10008dbcf02cSchristos if (sta->ap->control_url == NULL) { 10018dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP"); 10028dbcf02cSchristos wpabuf_free(msg); 10038dbcf02cSchristos return; 10048dbcf02cSchristos } 10058dbcf02cSchristos 10068dbcf02cSchristos url = http_client_url_parse(sta->ap->control_url, &dst, &path); 10078dbcf02cSchristos if (url == NULL) { 10088dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL"); 10098dbcf02cSchristos wpabuf_free(msg); 10108dbcf02cSchristos return; 10118dbcf02cSchristos } 10128dbcf02cSchristos 10138dbcf02cSchristos buf = wps_er_soap_hdr(msg, "PutWLANResponse", "NewMessage", path, &dst, 10148dbcf02cSchristos &len_ptr, &body_ptr); 10158dbcf02cSchristos wpabuf_free(msg); 10168dbcf02cSchristos os_free(url); 10178dbcf02cSchristos if (buf == NULL) 10188dbcf02cSchristos return; 10198dbcf02cSchristos wpabuf_printf(buf, "<NewWLANEventType>%d</NewWLANEventType>\n", 10208dbcf02cSchristos UPNP_WPS_WLANEVENT_TYPE_EAP); 10218dbcf02cSchristos wpabuf_printf(buf, "<NewWLANEventMAC>" MACSTR "</NewWLANEventMAC>\n", 10228dbcf02cSchristos MAC2STR(sta->addr)); 10238dbcf02cSchristos 10248dbcf02cSchristos wps_er_soap_end(buf, "PutWLANResponse", len_ptr, body_ptr); 10258dbcf02cSchristos 10268dbcf02cSchristos sta->http = http_client_addr(&dst, buf, 1000, 10278dbcf02cSchristos wps_er_http_put_wlan_response_cb, sta); 10288dbcf02cSchristos if (sta->http == NULL) 10298dbcf02cSchristos wpabuf_free(buf); 10308dbcf02cSchristos } 10318dbcf02cSchristos 10328dbcf02cSchristos 10338dbcf02cSchristos static void wps_er_sta_process(struct wps_er_sta *sta, struct wpabuf *msg, 10348dbcf02cSchristos enum wsc_op_code op_code) 10358dbcf02cSchristos { 10368dbcf02cSchristos enum wps_process_res res; 10378dbcf02cSchristos 10388dbcf02cSchristos res = wps_process_msg(sta->wps, op_code, msg); 10398dbcf02cSchristos if (res == WPS_CONTINUE) { 10408dbcf02cSchristos struct wpabuf *next = wps_get_msg(sta->wps, &op_code); 10418dbcf02cSchristos if (next) 10428dbcf02cSchristos wps_er_sta_send_msg(sta, next); 10438dbcf02cSchristos } else { 10448dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Protocol run %s with the " 10458dbcf02cSchristos "enrollee (res=%d)", 10468dbcf02cSchristos res == WPS_DONE ? "succeeded" : "failed", res); 10478dbcf02cSchristos wps_deinit(sta->wps); 10488dbcf02cSchristos sta->wps = NULL; 10498dbcf02cSchristos if (res == WPS_DONE) { 10508dbcf02cSchristos /* Remove the STA entry after short timeout */ 10518dbcf02cSchristos eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL); 10528dbcf02cSchristos eloop_register_timeout(10, 0, wps_er_sta_timeout, sta, 10538dbcf02cSchristos NULL); 10548dbcf02cSchristos } 10558dbcf02cSchristos } 10568dbcf02cSchristos } 10578dbcf02cSchristos 10588dbcf02cSchristos 10598dbcf02cSchristos static void wps_er_sta_start(struct wps_er_sta *sta, struct wpabuf *msg) 10608dbcf02cSchristos { 10618dbcf02cSchristos struct wps_config cfg; 10628dbcf02cSchristos 10638dbcf02cSchristos if (sta->wps) 10648dbcf02cSchristos wps_deinit(sta->wps); 10658dbcf02cSchristos 10668dbcf02cSchristos os_memset(&cfg, 0, sizeof(cfg)); 10678dbcf02cSchristos cfg.wps = sta->ap->er->wps; 10688dbcf02cSchristos cfg.registrar = 1; 10698dbcf02cSchristos cfg.peer_addr = sta->addr; 10708dbcf02cSchristos 10718dbcf02cSchristos sta->wps = wps_init(&cfg); 10728dbcf02cSchristos if (sta->wps == NULL) 10738dbcf02cSchristos return; 10748dbcf02cSchristos sta->wps->er = 1; 10758dbcf02cSchristos sta->wps->use_cred = sta->ap->ap_settings; 10761b7205bfSchristos if (sta->ap->ap_settings) { 10771b7205bfSchristos os_free(sta->cred); 10781b7205bfSchristos sta->cred = os_malloc(sizeof(*sta->cred)); 10791b7205bfSchristos if (sta->cred) { 10801b7205bfSchristos os_memcpy(sta->cred, sta->ap->ap_settings, 10811b7205bfSchristos sizeof(*sta->cred)); 10821b7205bfSchristos sta->cred->cred_attr = NULL; 10831b7205bfSchristos os_memcpy(sta->cred->mac_addr, sta->addr, ETH_ALEN); 10841b7205bfSchristos sta->wps->use_cred = sta->cred; 10851b7205bfSchristos } 10861b7205bfSchristos } 10878dbcf02cSchristos 10888dbcf02cSchristos wps_er_sta_process(sta, msg, WSC_MSG); 10898dbcf02cSchristos } 10908dbcf02cSchristos 10918dbcf02cSchristos 10928dbcf02cSchristos static void wps_er_process_wlanevent_eap(struct wps_er_ap *ap, const u8 *addr, 10938dbcf02cSchristos struct wpabuf *msg) 10948dbcf02cSchristos { 10958dbcf02cSchristos struct wps_parse_attr attr; 10968dbcf02cSchristos struct wps_er_sta *sta; 10978dbcf02cSchristos 10988dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: WLANEvent - EAP - from " MACSTR, 10998dbcf02cSchristos MAC2STR(addr)); 11008dbcf02cSchristos wpa_hexdump_buf(MSG_MSGDUMP, "WPS ER: WLANEvent - Enrollee's message " 11018dbcf02cSchristos "(TLVs from EAP-WSC)", msg); 11028dbcf02cSchristos 11038dbcf02cSchristos if (wps_parse_msg(msg, &attr) < 0) { 11048dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse TLVs in " 11058dbcf02cSchristos "WLANEvent message"); 11068dbcf02cSchristos return; 11078dbcf02cSchristos } 11088dbcf02cSchristos 11098dbcf02cSchristos sta = wps_er_add_sta_data(ap, addr, &attr, 0); 11108dbcf02cSchristos if (sta == NULL) 11118dbcf02cSchristos return; 11128dbcf02cSchristos 11138dbcf02cSchristos if (attr.msg_type && *attr.msg_type == WPS_M1) 11148dbcf02cSchristos wps_er_sta_start(sta, msg); 11158dbcf02cSchristos else if (sta->wps) { 11168dbcf02cSchristos enum wsc_op_code op_code = WSC_MSG; 11178dbcf02cSchristos if (attr.msg_type) { 11188dbcf02cSchristos switch (*attr.msg_type) { 11198dbcf02cSchristos case WPS_WSC_ACK: 11208dbcf02cSchristos op_code = WSC_ACK; 11218dbcf02cSchristos break; 11228dbcf02cSchristos case WPS_WSC_NACK: 11238dbcf02cSchristos op_code = WSC_NACK; 11248dbcf02cSchristos break; 11258dbcf02cSchristos case WPS_WSC_DONE: 11268dbcf02cSchristos op_code = WSC_Done; 11278dbcf02cSchristos break; 11288dbcf02cSchristos } 11298dbcf02cSchristos } 11308dbcf02cSchristos wps_er_sta_process(sta, msg, op_code); 11318dbcf02cSchristos } 11328dbcf02cSchristos } 11338dbcf02cSchristos 11348dbcf02cSchristos 11358dbcf02cSchristos static void wps_er_process_wlanevent(struct wps_er_ap *ap, 11368dbcf02cSchristos struct wpabuf *event) 11378dbcf02cSchristos { 11388dbcf02cSchristos u8 *data; 11398dbcf02cSchristos u8 wlan_event_type; 11408dbcf02cSchristos u8 wlan_event_mac[ETH_ALEN]; 11418dbcf02cSchristos struct wpabuf msg; 11428dbcf02cSchristos 11438dbcf02cSchristos wpa_hexdump(MSG_MSGDUMP, "WPS ER: Received WLANEvent", 11448dbcf02cSchristos wpabuf_head(event), wpabuf_len(event)); 11458dbcf02cSchristos if (wpabuf_len(event) < 1 + 17) { 11468dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Too short WLANEvent"); 11478dbcf02cSchristos return; 11488dbcf02cSchristos } 11498dbcf02cSchristos 11508dbcf02cSchristos data = wpabuf_mhead(event); 11518dbcf02cSchristos wlan_event_type = data[0]; 11528dbcf02cSchristos if (hwaddr_aton((char *) data + 1, wlan_event_mac) < 0) { 11538dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Invalid WLANEventMAC in " 11548dbcf02cSchristos "WLANEvent"); 11558dbcf02cSchristos return; 11568dbcf02cSchristos } 11578dbcf02cSchristos 11588dbcf02cSchristos wpabuf_set(&msg, data + 1 + 17, wpabuf_len(event) - (1 + 17)); 11598dbcf02cSchristos 11608dbcf02cSchristos switch (wlan_event_type) { 11618dbcf02cSchristos case 1: 11628dbcf02cSchristos wps_er_process_wlanevent_probe_req(ap, wlan_event_mac, &msg); 11638dbcf02cSchristos break; 11648dbcf02cSchristos case 2: 11658dbcf02cSchristos wps_er_process_wlanevent_eap(ap, wlan_event_mac, &msg); 11668dbcf02cSchristos break; 11678dbcf02cSchristos default: 11688dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Unknown WLANEventType %d", 11698dbcf02cSchristos wlan_event_type); 11708dbcf02cSchristos break; 11718dbcf02cSchristos } 11728dbcf02cSchristos } 11738dbcf02cSchristos 11748dbcf02cSchristos 11758dbcf02cSchristos static void wps_er_http_event(struct wps_er *er, struct http_request *req, 11768dbcf02cSchristos unsigned int ap_id) 11778dbcf02cSchristos { 11788dbcf02cSchristos struct wps_er_ap *ap = wps_er_ap_get_id(er, ap_id); 11798dbcf02cSchristos struct wpabuf *event; 11808dbcf02cSchristos enum http_reply_code ret; 11818dbcf02cSchristos 11828dbcf02cSchristos if (ap == NULL) { 11838dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: HTTP event from unknown AP id " 11848dbcf02cSchristos "%u", ap_id); 11858dbcf02cSchristos wps_er_http_resp_not_found(req); 11868dbcf02cSchristos return; 11878dbcf02cSchristos } 11888dbcf02cSchristos wpa_printf(MSG_MSGDUMP, "WPS ER: HTTP event from AP id %u: %s", 11898dbcf02cSchristos ap_id, http_request_get_data(req)); 11908dbcf02cSchristos 11918dbcf02cSchristos event = xml_get_base64_item(http_request_get_data(req), "WLANEvent", 11928dbcf02cSchristos &ret); 11938dbcf02cSchristos if (event == NULL) { 11948dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Could not extract WLANEvent " 11958dbcf02cSchristos "from the event notification"); 11968dbcf02cSchristos /* 11978dbcf02cSchristos * Reply with OK anyway to avoid getting unregistered from 11988dbcf02cSchristos * events. 11998dbcf02cSchristos */ 12008dbcf02cSchristos wps_er_http_resp_ok(req); 12018dbcf02cSchristos return; 12028dbcf02cSchristos } 12038dbcf02cSchristos 12048dbcf02cSchristos wps_er_process_wlanevent(ap, event); 12058dbcf02cSchristos 12068dbcf02cSchristos wpabuf_free(event); 12078dbcf02cSchristos wps_er_http_resp_ok(req); 12088dbcf02cSchristos } 12098dbcf02cSchristos 12108dbcf02cSchristos 12118dbcf02cSchristos static void wps_er_http_notify(struct wps_er *er, struct http_request *req) 12128dbcf02cSchristos { 12138dbcf02cSchristos char *uri = http_request_get_uri(req); 12148dbcf02cSchristos 12158dbcf02cSchristos if (os_strncmp(uri, "/event/", 7) == 0) { 12168dbcf02cSchristos unsigned int event_id; 12178dbcf02cSchristos char *pos; 12188dbcf02cSchristos event_id = atoi(uri + 7); 12198dbcf02cSchristos if (event_id != er->event_id) { 12208dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: HTTP event for an " 12218dbcf02cSchristos "unknown event id %u", event_id); 12228dbcf02cSchristos return; 12238dbcf02cSchristos } 12248dbcf02cSchristos pos = os_strchr(uri + 7, '/'); 12258dbcf02cSchristos if (pos == NULL) 12268dbcf02cSchristos return; 12278dbcf02cSchristos pos++; 12288dbcf02cSchristos wps_er_http_event(er, req, atoi(pos)); 12298dbcf02cSchristos } else { 12308dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Unknown HTTP NOTIFY for '%s'", 12318dbcf02cSchristos uri); 12328dbcf02cSchristos wps_er_http_resp_not_found(req); 12338dbcf02cSchristos } 12348dbcf02cSchristos } 12358dbcf02cSchristos 12368dbcf02cSchristos 12378dbcf02cSchristos static void wps_er_http_req(void *ctx, struct http_request *req) 12388dbcf02cSchristos { 12398dbcf02cSchristos struct wps_er *er = ctx; 12408dbcf02cSchristos struct sockaddr_in *cli = http_request_get_cli_addr(req); 12418dbcf02cSchristos enum httpread_hdr_type type = http_request_get_type(req); 12428dbcf02cSchristos struct wpabuf *buf; 12438dbcf02cSchristos 12448dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: HTTP request: '%s' (type %d) from " 12458dbcf02cSchristos "%s:%d", 12468dbcf02cSchristos http_request_get_uri(req), type, 12478dbcf02cSchristos inet_ntoa(cli->sin_addr), ntohs(cli->sin_port)); 12488dbcf02cSchristos 12498dbcf02cSchristos switch (type) { 12508dbcf02cSchristos case HTTPREAD_HDR_TYPE_NOTIFY: 12518dbcf02cSchristos wps_er_http_notify(er, req); 12528dbcf02cSchristos break; 12538dbcf02cSchristos default: 12548dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Unsupported HTTP request type " 12558dbcf02cSchristos "%d", type); 12568dbcf02cSchristos buf = wpabuf_alloc(200); 12578dbcf02cSchristos if (buf == NULL) { 12588dbcf02cSchristos http_request_deinit(req); 12598dbcf02cSchristos return; 12608dbcf02cSchristos } 12618dbcf02cSchristos wpabuf_put_str(buf, 12628dbcf02cSchristos "HTTP/1.1 501 Unimplemented\r\n" 12638dbcf02cSchristos "Connection: close\r\n"); 12648dbcf02cSchristos http_put_date(buf); 12658dbcf02cSchristos wpabuf_put_str(buf, "\r\n"); 12668dbcf02cSchristos http_request_send_and_deinit(req, buf); 12678dbcf02cSchristos break; 12688dbcf02cSchristos } 12698dbcf02cSchristos } 12708dbcf02cSchristos 12718dbcf02cSchristos 12728dbcf02cSchristos struct wps_er * 1273*42669be3Schristos wps_er_init(struct wps_context *wps, const char *ifname, const char *filter) 12748dbcf02cSchristos { 12758dbcf02cSchristos struct wps_er *er; 12768dbcf02cSchristos struct in_addr addr; 12778dbcf02cSchristos 12788dbcf02cSchristos er = os_zalloc(sizeof(*er)); 12798dbcf02cSchristos if (er == NULL) 12808dbcf02cSchristos return NULL; 12818dbcf02cSchristos dl_list_init(&er->ap); 12828dbcf02cSchristos dl_list_init(&er->ap_unsubscribing); 1283*42669be3Schristos dl_list_init(&er->ap_settings); 12848dbcf02cSchristos 12858dbcf02cSchristos er->multicast_sd = -1; 12868dbcf02cSchristos er->ssdp_sd = -1; 12878dbcf02cSchristos 12888dbcf02cSchristos os_strlcpy(er->ifname, ifname, sizeof(er->ifname)); 12898dbcf02cSchristos er->wps = wps; 12908dbcf02cSchristos if (os_get_random((unsigned char *) &er->event_id, 12918dbcf02cSchristos sizeof(er->event_id)) < 0) { 12928dbcf02cSchristos wps_er_deinit(er, NULL, NULL); 12938dbcf02cSchristos return NULL; 12948dbcf02cSchristos } 12951b7205bfSchristos /* Limit event_id to < 32 bits to avoid issues with atoi() */ 12961b7205bfSchristos er->event_id &= 0x0fffffff; 12978dbcf02cSchristos 1298*42669be3Schristos if (filter) { 1299*42669be3Schristos if (inet_aton(filter, &er->filter_addr) == 0) { 1300*42669be3Schristos wpa_printf(MSG_INFO, "WPS UPnP: Invalid filter " 1301*42669be3Schristos "address %s", filter); 1302*42669be3Schristos wps_er_deinit(er, NULL, NULL); 1303*42669be3Schristos return NULL; 1304*42669be3Schristos } 1305*42669be3Schristos wpa_printf(MSG_DEBUG, "WPS UPnP: Only accepting connections " 1306*42669be3Schristos "with %s", filter); 1307*42669be3Schristos } 13088dbcf02cSchristos if (get_netif_info(ifname, &er->ip_addr, &er->ip_addr_text, 13098dbcf02cSchristos er->mac_addr)) { 13108dbcf02cSchristos wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address " 13118dbcf02cSchristos "for %s. Does it have IP address?", ifname); 13128dbcf02cSchristos wps_er_deinit(er, NULL, NULL); 13138dbcf02cSchristos return NULL; 13148dbcf02cSchristos } 13158dbcf02cSchristos 13168dbcf02cSchristos if (wps_er_ssdp_init(er) < 0) { 1317*42669be3Schristos wpa_printf(MSG_INFO, "WPS UPnP: SSDP initialization failed"); 13188dbcf02cSchristos wps_er_deinit(er, NULL, NULL); 13198dbcf02cSchristos return NULL; 13208dbcf02cSchristos } 13218dbcf02cSchristos 13228dbcf02cSchristos addr.s_addr = er->ip_addr; 13238dbcf02cSchristos er->http_srv = http_server_init(&addr, -1, wps_er_http_req, er); 13248dbcf02cSchristos if (er->http_srv == NULL) { 1325*42669be3Schristos wpa_printf(MSG_INFO, "WPS UPnP: HTTP initialization failed"); 13268dbcf02cSchristos wps_er_deinit(er, NULL, NULL); 13278dbcf02cSchristos return NULL; 13288dbcf02cSchristos } 13298dbcf02cSchristos er->http_port = http_server_get_port(er->http_srv); 13308dbcf02cSchristos 13318dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Start (ifname=%s ip_addr=%s)", 13328dbcf02cSchristos er->ifname, er->ip_addr_text); 13338dbcf02cSchristos 13348dbcf02cSchristos return er; 13358dbcf02cSchristos } 13368dbcf02cSchristos 13378dbcf02cSchristos 13388dbcf02cSchristos void wps_er_refresh(struct wps_er *er) 13398dbcf02cSchristos { 13408dbcf02cSchristos struct wps_er_ap *ap; 13418dbcf02cSchristos struct wps_er_sta *sta; 13428dbcf02cSchristos 13438dbcf02cSchristos dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) { 13448dbcf02cSchristos wps_er_ap_event(er->wps, ap, WPS_EV_ER_AP_ADD); 13458dbcf02cSchristos dl_list_for_each(sta, &ap->sta, struct wps_er_sta, list) 13468dbcf02cSchristos wps_er_sta_event(er->wps, sta, WPS_EV_ER_ENROLLEE_ADD); 13478dbcf02cSchristos } 13488dbcf02cSchristos 13498dbcf02cSchristos wps_er_send_ssdp_msearch(er); 13508dbcf02cSchristos } 13518dbcf02cSchristos 13528dbcf02cSchristos 13538dbcf02cSchristos static void wps_er_deinit_finish(void *eloop_data, void *user_ctx) 13548dbcf02cSchristos { 13558dbcf02cSchristos struct wps_er *er = eloop_data; 13568dbcf02cSchristos void (*deinit_done_cb)(void *ctx); 13578dbcf02cSchristos void *deinit_done_ctx; 13588dbcf02cSchristos 13598dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Finishing deinit"); 13608dbcf02cSchristos 13618dbcf02cSchristos deinit_done_cb = er->deinit_done_cb; 13628dbcf02cSchristos deinit_done_ctx = er->deinit_done_ctx; 13638dbcf02cSchristos os_free(er->ip_addr_text); 13648dbcf02cSchristos os_free(er); 13658dbcf02cSchristos 13668dbcf02cSchristos if (deinit_done_cb) 13678dbcf02cSchristos deinit_done_cb(deinit_done_ctx); 13688dbcf02cSchristos } 13698dbcf02cSchristos 13708dbcf02cSchristos 13718dbcf02cSchristos void wps_er_deinit(struct wps_er *er, void (*cb)(void *ctx), void *ctx) 13728dbcf02cSchristos { 13738dbcf02cSchristos if (er == NULL) 13748dbcf02cSchristos return; 13758dbcf02cSchristos http_server_deinit(er->http_srv); 13768dbcf02cSchristos wps_er_ap_remove_all(er); 13778dbcf02cSchristos wps_er_ssdp_deinit(er); 13788dbcf02cSchristos eloop_register_timeout(dl_list_empty(&er->ap_unsubscribing) ? 0 : 5, 0, 13798dbcf02cSchristos wps_er_deinit_finish, er, NULL); 13808dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Finish deinit from timeout"); 13818dbcf02cSchristos er->deinitializing = 1; 13828dbcf02cSchristos er->deinit_done_cb = cb; 13838dbcf02cSchristos er->deinit_done_ctx = ctx; 13848dbcf02cSchristos } 13858dbcf02cSchristos 13868dbcf02cSchristos 13878dbcf02cSchristos static void wps_er_http_set_sel_reg_cb(void *ctx, struct http_client *c, 13888dbcf02cSchristos enum http_client_event event) 13898dbcf02cSchristos { 13908dbcf02cSchristos struct wps_er_ap *ap = ctx; 1391*42669be3Schristos union wps_event_data data; 1392*42669be3Schristos 1393*42669be3Schristos os_memset(&data, 0, sizeof(data)); 13948dbcf02cSchristos 13958dbcf02cSchristos switch (event) { 13968dbcf02cSchristos case HTTP_CLIENT_OK: 13978dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar OK"); 1398*42669be3Schristos data.set_sel_reg.state = WPS_ER_SET_SEL_REG_DONE; 1399*42669be3Schristos data.set_sel_reg.uuid = ap->uuid; 14008dbcf02cSchristos break; 14018dbcf02cSchristos case HTTP_CLIENT_FAILED: 14028dbcf02cSchristos case HTTP_CLIENT_INVALID_REPLY: 14038dbcf02cSchristos case HTTP_CLIENT_TIMEOUT: 14048dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar failed"); 1405*42669be3Schristos data.set_sel_reg.state = WPS_ER_SET_SEL_REG_FAILED; 1406*42669be3Schristos data.set_sel_reg.uuid = ap->uuid; 14078dbcf02cSchristos break; 14088dbcf02cSchristos } 14098dbcf02cSchristos http_client_free(ap->http); 14108dbcf02cSchristos ap->http = NULL; 1411*42669be3Schristos 1412*42669be3Schristos if (data.set_sel_reg.uuid) 1413*42669be3Schristos ap->er->wps->event_cb(ap->er->wps->cb_ctx, 1414*42669be3Schristos WPS_EV_ER_SET_SELECTED_REGISTRAR, &data); 14158dbcf02cSchristos } 14168dbcf02cSchristos 14178dbcf02cSchristos 14188dbcf02cSchristos static void wps_er_send_set_sel_reg(struct wps_er_ap *ap, struct wpabuf *msg) 14198dbcf02cSchristos { 14208dbcf02cSchristos struct wpabuf *buf; 14218dbcf02cSchristos char *len_ptr, *body_ptr; 14228dbcf02cSchristos struct sockaddr_in dst; 14238dbcf02cSchristos char *url, *path; 14248dbcf02cSchristos 14258dbcf02cSchristos if (ap->control_url == NULL) { 14268dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP"); 14278dbcf02cSchristos return; 14288dbcf02cSchristos } 14298dbcf02cSchristos 14308dbcf02cSchristos if (ap->http) { 14318dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request for AP - " 14328dbcf02cSchristos "ignore new request"); 14338dbcf02cSchristos return; 14348dbcf02cSchristos } 14358dbcf02cSchristos 1436*42669be3Schristos if (ap->wps) { 1437*42669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: Pending WPS operation for AP - " 1438*42669be3Schristos "skip SetSelectedRegistrar"); 1439*42669be3Schristos return; 1440*42669be3Schristos } 1441*42669be3Schristos 14428dbcf02cSchristos url = http_client_url_parse(ap->control_url, &dst, &path); 14438dbcf02cSchristos if (url == NULL) { 14448dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL"); 14458dbcf02cSchristos return; 14468dbcf02cSchristos } 14478dbcf02cSchristos 14488dbcf02cSchristos buf = wps_er_soap_hdr(msg, "SetSelectedRegistrar", "NewMessage", path, 14498dbcf02cSchristos &dst, &len_ptr, &body_ptr); 14508dbcf02cSchristos os_free(url); 14518dbcf02cSchristos if (buf == NULL) 14528dbcf02cSchristos return; 14538dbcf02cSchristos 14548dbcf02cSchristos wps_er_soap_end(buf, "SetSelectedRegistrar", len_ptr, body_ptr); 14558dbcf02cSchristos 14568dbcf02cSchristos ap->http = http_client_addr(&dst, buf, 1000, 14578dbcf02cSchristos wps_er_http_set_sel_reg_cb, ap); 14588dbcf02cSchristos if (ap->http == NULL) 14598dbcf02cSchristos wpabuf_free(buf); 14608dbcf02cSchristos } 14618dbcf02cSchristos 14628dbcf02cSchristos 14638dbcf02cSchristos static int wps_er_build_selected_registrar(struct wpabuf *msg, int sel_reg) 14648dbcf02cSchristos { 14658dbcf02cSchristos wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR); 14668dbcf02cSchristos wpabuf_put_be16(msg, 1); 14678dbcf02cSchristos wpabuf_put_u8(msg, !!sel_reg); 14688dbcf02cSchristos return 0; 14698dbcf02cSchristos } 14708dbcf02cSchristos 14718dbcf02cSchristos 14728dbcf02cSchristos static int wps_er_build_dev_password_id(struct wpabuf *msg, u16 dev_passwd_id) 14738dbcf02cSchristos { 14748dbcf02cSchristos wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID); 14758dbcf02cSchristos wpabuf_put_be16(msg, 2); 14768dbcf02cSchristos wpabuf_put_be16(msg, dev_passwd_id); 14778dbcf02cSchristos return 0; 14788dbcf02cSchristos } 14798dbcf02cSchristos 14808dbcf02cSchristos 14818dbcf02cSchristos static int wps_er_build_sel_reg_config_methods(struct wpabuf *msg, 14828dbcf02cSchristos u16 sel_reg_config_methods) 14838dbcf02cSchristos { 14848dbcf02cSchristos wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR_CONFIG_METHODS); 14858dbcf02cSchristos wpabuf_put_be16(msg, 2); 14868dbcf02cSchristos wpabuf_put_be16(msg, sel_reg_config_methods); 14878dbcf02cSchristos return 0; 14888dbcf02cSchristos } 14898dbcf02cSchristos 14908dbcf02cSchristos 1491*42669be3Schristos static int wps_er_build_uuid_r(struct wpabuf *msg, const u8 *uuid_r) 1492*42669be3Schristos { 1493*42669be3Schristos #ifdef CONFIG_WPS2 1494*42669be3Schristos wpabuf_put_be16(msg, ATTR_UUID_R); 1495*42669be3Schristos wpabuf_put_be16(msg, WPS_UUID_LEN); 1496*42669be3Schristos wpabuf_put_data(msg, uuid_r, WPS_UUID_LEN); 1497*42669be3Schristos #endif /* CONFIG_WPS2 */ 1498*42669be3Schristos return 0; 1499*42669be3Schristos } 1500*42669be3Schristos 1501*42669be3Schristos 15028dbcf02cSchristos void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id, 15038dbcf02cSchristos u16 sel_reg_config_methods) 15048dbcf02cSchristos { 15058dbcf02cSchristos struct wpabuf *msg; 15068dbcf02cSchristos struct wps_er_ap *ap; 1507*42669be3Schristos struct wps_registrar *reg = er->wps->registrar; 1508*42669be3Schristos const u8 *auth_macs; 1509*42669be3Schristos #ifdef CONFIG_WPS2 1510*42669be3Schristos u8 bcast[ETH_ALEN]; 1511*42669be3Schristos #endif /* CONFIG_WPS2 */ 1512*42669be3Schristos size_t count; 1513*42669be3Schristos union wps_event_data data; 1514*42669be3Schristos 1515*42669be3Schristos if (er->skip_set_sel_reg) { 1516*42669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: Skip SetSelectedRegistrar"); 1517*42669be3Schristos return; 1518*42669be3Schristos } 15198dbcf02cSchristos 15208dbcf02cSchristos msg = wpabuf_alloc(500); 15218dbcf02cSchristos if (msg == NULL) 15228dbcf02cSchristos return; 15238dbcf02cSchristos 1524*42669be3Schristos auth_macs = wps_authorized_macs(reg, &count); 1525*42669be3Schristos #ifdef CONFIG_WPS2 1526*42669be3Schristos if (count == 0) { 1527*42669be3Schristos os_memset(bcast, 0xff, ETH_ALEN); 1528*42669be3Schristos auth_macs = bcast; 1529*42669be3Schristos count = 1; 1530*42669be3Schristos } 1531*42669be3Schristos #endif /* CONFIG_WPS2 */ 1532*42669be3Schristos 15338dbcf02cSchristos if (wps_build_version(msg) || 15348dbcf02cSchristos wps_er_build_selected_registrar(msg, sel_reg) || 15358dbcf02cSchristos wps_er_build_dev_password_id(msg, dev_passwd_id) || 1536*42669be3Schristos wps_er_build_sel_reg_config_methods(msg, sel_reg_config_methods) || 1537*42669be3Schristos wps_build_wfa_ext(msg, 0, auth_macs, count) || 1538*42669be3Schristos wps_er_build_uuid_r(msg, er->wps->uuid)) { 15398dbcf02cSchristos wpabuf_free(msg); 15408dbcf02cSchristos return; 15418dbcf02cSchristos } 15428dbcf02cSchristos 1543*42669be3Schristos os_memset(&data, 0, sizeof(data)); 1544*42669be3Schristos data.set_sel_reg.sel_reg = sel_reg; 1545*42669be3Schristos data.set_sel_reg.dev_passwd_id = dev_passwd_id; 1546*42669be3Schristos data.set_sel_reg.sel_reg_config_methods = sel_reg_config_methods; 1547*42669be3Schristos data.set_sel_reg.state = WPS_ER_SET_SEL_REG_START; 1548*42669be3Schristos 1549*42669be3Schristos dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) { 1550*42669be3Schristos if (er->set_sel_reg_uuid_filter && 1551*42669be3Schristos os_memcmp(ap->uuid, er->set_sel_reg_uuid_filter, 1552*42669be3Schristos WPS_UUID_LEN) != 0) 1553*42669be3Schristos continue; 1554*42669be3Schristos data.set_sel_reg.uuid = ap->uuid; 1555*42669be3Schristos er->wps->event_cb(er->wps->cb_ctx, 1556*42669be3Schristos WPS_EV_ER_SET_SELECTED_REGISTRAR, &data); 15578dbcf02cSchristos wps_er_send_set_sel_reg(ap, msg); 1558*42669be3Schristos } 15598dbcf02cSchristos 15608dbcf02cSchristos wpabuf_free(msg); 15618dbcf02cSchristos } 15628dbcf02cSchristos 15638dbcf02cSchristos 15648dbcf02cSchristos int wps_er_pbc(struct wps_er *er, const u8 *uuid) 15658dbcf02cSchristos { 1566*42669be3Schristos int res; 1567*42669be3Schristos struct wps_er_ap *ap; 1568*42669be3Schristos 15698dbcf02cSchristos if (er == NULL || er->wps == NULL) 15708dbcf02cSchristos return -1; 15718dbcf02cSchristos 1572*42669be3Schristos if (wps_registrar_pbc_overlap(er->wps->registrar, NULL, NULL)) { 1573*42669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: PBC overlap - do not start PBC " 1574*42669be3Schristos "mode"); 1575*42669be3Schristos return -2; 1576*42669be3Schristos } 1577*42669be3Schristos 1578*42669be3Schristos ap = wps_er_ap_get(er, NULL, uuid); 1579*42669be3Schristos if (ap == NULL) { 1580*42669be3Schristos struct wps_er_sta *sta = NULL; 1581*42669be3Schristos dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) { 1582*42669be3Schristos sta = wps_er_sta_get(ap, NULL, uuid); 1583*42669be3Schristos if (sta) { 1584*42669be3Schristos uuid = ap->uuid; 1585*42669be3Schristos break; 1586*42669be3Schristos } 1587*42669be3Schristos } 1588*42669be3Schristos if (sta == NULL) 1589*42669be3Schristos return -3; /* Unknown UUID */ 1590*42669be3Schristos } 1591*42669be3Schristos 1592*42669be3Schristos if (ap->ap_settings == NULL) { 1593*42669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: AP settings not known"); 1594*42669be3Schristos return -4; 1595*42669be3Schristos } 1596*42669be3Schristos 1597*42669be3Schristos er->set_sel_reg_uuid_filter = uuid; 1598*42669be3Schristos res = wps_registrar_button_pushed(er->wps->registrar, NULL); 1599*42669be3Schristos er->set_sel_reg_uuid_filter = NULL; 1600*42669be3Schristos if (res) 16018dbcf02cSchristos return -1; 16028dbcf02cSchristos 16038dbcf02cSchristos return 0; 16048dbcf02cSchristos } 16058dbcf02cSchristos 16068dbcf02cSchristos 16078dbcf02cSchristos static void wps_er_ap_settings_cb(void *ctx, const struct wps_credential *cred) 16088dbcf02cSchristos { 16098dbcf02cSchristos struct wps_er_ap *ap = ctx; 1610*42669be3Schristos union wps_event_data data; 1611*42669be3Schristos 16128dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: AP Settings received"); 16138dbcf02cSchristos os_free(ap->ap_settings); 16148dbcf02cSchristos ap->ap_settings = os_malloc(sizeof(*cred)); 16158dbcf02cSchristos if (ap->ap_settings) { 16168dbcf02cSchristos os_memcpy(ap->ap_settings, cred, sizeof(*cred)); 16178dbcf02cSchristos ap->ap_settings->cred_attr = NULL; 16188dbcf02cSchristos } 16198dbcf02cSchristos 1620*42669be3Schristos os_memset(&data, 0, sizeof(data)); 1621*42669be3Schristos data.ap_settings.uuid = ap->uuid; 1622*42669be3Schristos data.ap_settings.cred = cred; 1623*42669be3Schristos ap->er->wps->event_cb(ap->er->wps->cb_ctx, WPS_EV_ER_AP_SETTINGS, 1624*42669be3Schristos &data); 16258dbcf02cSchristos } 16268dbcf02cSchristos 16278dbcf02cSchristos 16288dbcf02cSchristos static void wps_er_http_put_message_cb(void *ctx, struct http_client *c, 16298dbcf02cSchristos enum http_client_event event) 16308dbcf02cSchristos { 16318dbcf02cSchristos struct wps_er_ap *ap = ctx; 16328dbcf02cSchristos struct wpabuf *reply; 16338dbcf02cSchristos char *msg = NULL; 16348dbcf02cSchristos 16358dbcf02cSchristos switch (event) { 16368dbcf02cSchristos case HTTP_CLIENT_OK: 16378dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: PutMessage OK"); 16388dbcf02cSchristos reply = http_client_get_body(c); 16398dbcf02cSchristos if (reply == NULL) 16408dbcf02cSchristos break; 16418dbcf02cSchristos msg = os_zalloc(wpabuf_len(reply) + 1); 16428dbcf02cSchristos if (msg == NULL) 16438dbcf02cSchristos break; 16448dbcf02cSchristos os_memcpy(msg, wpabuf_head(reply), wpabuf_len(reply)); 16458dbcf02cSchristos break; 16468dbcf02cSchristos case HTTP_CLIENT_FAILED: 16478dbcf02cSchristos case HTTP_CLIENT_INVALID_REPLY: 16488dbcf02cSchristos case HTTP_CLIENT_TIMEOUT: 16498dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: PutMessage failed"); 16508dbcf02cSchristos if (ap->wps) { 16518dbcf02cSchristos wps_deinit(ap->wps); 16528dbcf02cSchristos ap->wps = NULL; 16538dbcf02cSchristos } 16548dbcf02cSchristos break; 16558dbcf02cSchristos } 16568dbcf02cSchristos http_client_free(ap->http); 16578dbcf02cSchristos ap->http = NULL; 16588dbcf02cSchristos 16598dbcf02cSchristos if (msg) { 16608dbcf02cSchristos struct wpabuf *buf; 16618dbcf02cSchristos enum http_reply_code ret; 16628dbcf02cSchristos buf = xml_get_base64_item(msg, "NewOutMessage", &ret); 16638dbcf02cSchristos os_free(msg); 16648dbcf02cSchristos if (buf == NULL) { 16658dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Could not extract " 16668dbcf02cSchristos "NewOutMessage from PutMessage response"); 1667*42669be3Schristos wps_deinit(ap->wps); 1668*42669be3Schristos ap->wps = NULL; 16698dbcf02cSchristos return; 16708dbcf02cSchristos } 16718dbcf02cSchristos wps_er_ap_process(ap, buf); 16728dbcf02cSchristos wpabuf_free(buf); 16738dbcf02cSchristos } 16748dbcf02cSchristos } 16758dbcf02cSchristos 16768dbcf02cSchristos 16778dbcf02cSchristos static void wps_er_ap_put_message(struct wps_er_ap *ap, 16788dbcf02cSchristos const struct wpabuf *msg) 16798dbcf02cSchristos { 16808dbcf02cSchristos struct wpabuf *buf; 16818dbcf02cSchristos char *len_ptr, *body_ptr; 16828dbcf02cSchristos struct sockaddr_in dst; 16838dbcf02cSchristos char *url, *path; 16848dbcf02cSchristos 16858dbcf02cSchristos if (ap->http) { 16868dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP operation ongoing " 16878dbcf02cSchristos "with the AP - cannot continue learn"); 16888dbcf02cSchristos return; 16898dbcf02cSchristos } 16908dbcf02cSchristos 16918dbcf02cSchristos if (ap->control_url == NULL) { 16928dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP"); 16938dbcf02cSchristos return; 16948dbcf02cSchristos } 16958dbcf02cSchristos 16968dbcf02cSchristos url = http_client_url_parse(ap->control_url, &dst, &path); 16978dbcf02cSchristos if (url == NULL) { 16988dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL"); 16998dbcf02cSchristos return; 17008dbcf02cSchristos } 17018dbcf02cSchristos 17028dbcf02cSchristos buf = wps_er_soap_hdr(msg, "PutMessage", "NewInMessage", path, &dst, 17038dbcf02cSchristos &len_ptr, &body_ptr); 17048dbcf02cSchristos os_free(url); 17058dbcf02cSchristos if (buf == NULL) 17068dbcf02cSchristos return; 17078dbcf02cSchristos 17088dbcf02cSchristos wps_er_soap_end(buf, "PutMessage", len_ptr, body_ptr); 17098dbcf02cSchristos 17108dbcf02cSchristos ap->http = http_client_addr(&dst, buf, 10000, 17118dbcf02cSchristos wps_er_http_put_message_cb, ap); 17128dbcf02cSchristos if (ap->http == NULL) 17138dbcf02cSchristos wpabuf_free(buf); 17148dbcf02cSchristos } 17158dbcf02cSchristos 17168dbcf02cSchristos 17178dbcf02cSchristos static void wps_er_ap_process(struct wps_er_ap *ap, struct wpabuf *msg) 17188dbcf02cSchristos { 17198dbcf02cSchristos enum wps_process_res res; 1720*42669be3Schristos struct wps_parse_attr attr; 17218dbcf02cSchristos enum wsc_op_code op_code; 1722*42669be3Schristos 1723*42669be3Schristos op_code = WSC_MSG; 1724*42669be3Schristos if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type) { 1725*42669be3Schristos switch (*attr.msg_type) { 1726*42669be3Schristos case WPS_WSC_ACK: 1727*42669be3Schristos op_code = WSC_ACK; 1728*42669be3Schristos break; 1729*42669be3Schristos case WPS_WSC_NACK: 1730*42669be3Schristos op_code = WSC_NACK; 1731*42669be3Schristos break; 1732*42669be3Schristos case WPS_WSC_DONE: 1733*42669be3Schristos op_code = WSC_Done; 1734*42669be3Schristos break; 1735*42669be3Schristos } 1736*42669be3Schristos } 1737*42669be3Schristos 1738*42669be3Schristos res = wps_process_msg(ap->wps, op_code, msg); 1739*42669be3Schristos if (res == WPS_CONTINUE) { 17408dbcf02cSchristos struct wpabuf *next = wps_get_msg(ap->wps, &op_code); 17418dbcf02cSchristos if (next) { 17428dbcf02cSchristos wps_er_ap_put_message(ap, next); 17438dbcf02cSchristos wpabuf_free(next); 17448dbcf02cSchristos } else { 17458dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to build " 17468dbcf02cSchristos "message"); 17478dbcf02cSchristos wps_deinit(ap->wps); 17488dbcf02cSchristos ap->wps = NULL; 17498dbcf02cSchristos } 1750*42669be3Schristos } else if (res == WPS_DONE) { 1751*42669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: Protocol run done"); 1752*42669be3Schristos wps_deinit(ap->wps); 1753*42669be3Schristos ap->wps = NULL; 17548dbcf02cSchristos } else { 17558dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to process message from " 17568dbcf02cSchristos "AP (res=%d)", res); 17578dbcf02cSchristos wps_deinit(ap->wps); 17588dbcf02cSchristos ap->wps = NULL; 17598dbcf02cSchristos } 17608dbcf02cSchristos } 17618dbcf02cSchristos 17628dbcf02cSchristos 17638dbcf02cSchristos static void wps_er_ap_learn_m1(struct wps_er_ap *ap, struct wpabuf *m1) 17648dbcf02cSchristos { 17658dbcf02cSchristos struct wps_config cfg; 17668dbcf02cSchristos 17678dbcf02cSchristos if (ap->wps) { 17688dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Protocol run already in " 17698dbcf02cSchristos "progress with this AP"); 17708dbcf02cSchristos return; 17718dbcf02cSchristos } 17728dbcf02cSchristos 17738dbcf02cSchristos os_memset(&cfg, 0, sizeof(cfg)); 17748dbcf02cSchristos cfg.wps = ap->er->wps; 17758dbcf02cSchristos cfg.registrar = 1; 17768dbcf02cSchristos ap->wps = wps_init(&cfg); 17778dbcf02cSchristos if (ap->wps == NULL) 17788dbcf02cSchristos return; 17798dbcf02cSchristos ap->wps->ap_settings_cb = wps_er_ap_settings_cb; 17808dbcf02cSchristos ap->wps->ap_settings_cb_ctx = ap; 17818dbcf02cSchristos 17828dbcf02cSchristos wps_er_ap_process(ap, m1); 17838dbcf02cSchristos } 17848dbcf02cSchristos 17858dbcf02cSchristos 17868dbcf02cSchristos static void wps_er_ap_learn(struct wps_er_ap *ap, const char *dev_info) 17878dbcf02cSchristos { 17888dbcf02cSchristos struct wpabuf *info; 17898dbcf02cSchristos enum http_reply_code ret; 17908dbcf02cSchristos 17918dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Received GetDeviceInfo response (M1) " 17928dbcf02cSchristos "from the AP"); 17938dbcf02cSchristos info = xml_get_base64_item(dev_info, "NewDeviceInfo", &ret); 17948dbcf02cSchristos if (info == NULL) { 17958dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Could not extract " 17968dbcf02cSchristos "NewDeviceInfo from GetDeviceInfo response"); 17978dbcf02cSchristos return; 17988dbcf02cSchristos } 17998dbcf02cSchristos 18008dbcf02cSchristos ap->m1_handler(ap, info); 18018dbcf02cSchristos wpabuf_free(info); 18028dbcf02cSchristos } 18038dbcf02cSchristos 18048dbcf02cSchristos 18058dbcf02cSchristos static void wps_er_http_get_dev_info_cb(void *ctx, struct http_client *c, 18068dbcf02cSchristos enum http_client_event event) 18078dbcf02cSchristos { 18088dbcf02cSchristos struct wps_er_ap *ap = ctx; 18098dbcf02cSchristos struct wpabuf *reply; 18108dbcf02cSchristos char *dev_info = NULL; 18118dbcf02cSchristos 18128dbcf02cSchristos switch (event) { 18138dbcf02cSchristos case HTTP_CLIENT_OK: 18148dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: GetDeviceInfo OK"); 18158dbcf02cSchristos reply = http_client_get_body(c); 18168dbcf02cSchristos if (reply == NULL) 18178dbcf02cSchristos break; 18188dbcf02cSchristos dev_info = os_zalloc(wpabuf_len(reply) + 1); 18198dbcf02cSchristos if (dev_info == NULL) 18208dbcf02cSchristos break; 18218dbcf02cSchristos os_memcpy(dev_info, wpabuf_head(reply), wpabuf_len(reply)); 18228dbcf02cSchristos break; 18238dbcf02cSchristos case HTTP_CLIENT_FAILED: 18248dbcf02cSchristos case HTTP_CLIENT_INVALID_REPLY: 18258dbcf02cSchristos case HTTP_CLIENT_TIMEOUT: 18268dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: GetDeviceInfo failed"); 18278dbcf02cSchristos break; 18288dbcf02cSchristos } 18298dbcf02cSchristos http_client_free(ap->http); 18308dbcf02cSchristos ap->http = NULL; 18318dbcf02cSchristos 18328dbcf02cSchristos if (dev_info) { 18338dbcf02cSchristos wps_er_ap_learn(ap, dev_info); 18348dbcf02cSchristos os_free(dev_info); 18358dbcf02cSchristos } 18368dbcf02cSchristos } 18378dbcf02cSchristos 18388dbcf02cSchristos 18398dbcf02cSchristos static int wps_er_send_get_device_info(struct wps_er_ap *ap, 18408dbcf02cSchristos void (*m1_handler)(struct wps_er_ap *ap, 18418dbcf02cSchristos struct wpabuf *m1)) 18428dbcf02cSchristos { 18438dbcf02cSchristos struct wpabuf *buf; 18448dbcf02cSchristos char *len_ptr, *body_ptr; 18458dbcf02cSchristos struct sockaddr_in dst; 18468dbcf02cSchristos char *url, *path; 18478dbcf02cSchristos 18488dbcf02cSchristos if (ap->http) { 18498dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP operation ongoing " 18508dbcf02cSchristos "with the AP - cannot get device info"); 18518dbcf02cSchristos return -1; 18528dbcf02cSchristos } 18538dbcf02cSchristos 18548dbcf02cSchristos if (ap->control_url == NULL) { 18558dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP"); 18568dbcf02cSchristos return -1; 18578dbcf02cSchristos } 18588dbcf02cSchristos 18598dbcf02cSchristos url = http_client_url_parse(ap->control_url, &dst, &path); 18608dbcf02cSchristos if (url == NULL) { 18618dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL"); 18628dbcf02cSchristos return -1; 18638dbcf02cSchristos } 18648dbcf02cSchristos 18658dbcf02cSchristos buf = wps_er_soap_hdr(NULL, "GetDeviceInfo", NULL, path, &dst, 18668dbcf02cSchristos &len_ptr, &body_ptr); 18678dbcf02cSchristos os_free(url); 18688dbcf02cSchristos if (buf == NULL) 18698dbcf02cSchristos return -1; 18708dbcf02cSchristos 18718dbcf02cSchristos wps_er_soap_end(buf, "GetDeviceInfo", len_ptr, body_ptr); 18728dbcf02cSchristos 18738dbcf02cSchristos ap->http = http_client_addr(&dst, buf, 10000, 18748dbcf02cSchristos wps_er_http_get_dev_info_cb, ap); 18758dbcf02cSchristos if (ap->http == NULL) { 18768dbcf02cSchristos wpabuf_free(buf); 18778dbcf02cSchristos return -1; 18788dbcf02cSchristos } 18798dbcf02cSchristos 18808dbcf02cSchristos ap->m1_handler = m1_handler; 18818dbcf02cSchristos 18828dbcf02cSchristos return 0; 18838dbcf02cSchristos } 18848dbcf02cSchristos 18858dbcf02cSchristos 18868dbcf02cSchristos int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin, 18878dbcf02cSchristos size_t pin_len) 18888dbcf02cSchristos { 18898dbcf02cSchristos struct wps_er_ap *ap; 18908dbcf02cSchristos 18918dbcf02cSchristos if (er == NULL) 18928dbcf02cSchristos return -1; 18938dbcf02cSchristos 18948dbcf02cSchristos ap = wps_er_ap_get(er, NULL, uuid); 18958dbcf02cSchristos if (ap == NULL) { 18968dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: AP not found for learn " 18978dbcf02cSchristos "request"); 18988dbcf02cSchristos return -1; 18998dbcf02cSchristos } 19008dbcf02cSchristos if (ap->wps) { 19018dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing " 19028dbcf02cSchristos "with the AP - cannot start learn"); 19038dbcf02cSchristos return -1; 19048dbcf02cSchristos } 19058dbcf02cSchristos 19068dbcf02cSchristos if (wps_er_send_get_device_info(ap, wps_er_ap_learn_m1) < 0) 19078dbcf02cSchristos return -1; 19088dbcf02cSchristos 1909*42669be3Schristos er->skip_set_sel_reg = 1; 1910*42669be3Schristos wps_registrar_add_pin(er->wps->registrar, NULL, uuid, pin, pin_len, 0); 1911*42669be3Schristos er->skip_set_sel_reg = 0; 1912*42669be3Schristos 1913*42669be3Schristos return 0; 1914*42669be3Schristos } 1915*42669be3Schristos 1916*42669be3Schristos 1917*42669be3Schristos int wps_er_set_config(struct wps_er *er, const u8 *uuid, 1918*42669be3Schristos const struct wps_credential *cred) 1919*42669be3Schristos { 1920*42669be3Schristos struct wps_er_ap *ap; 1921*42669be3Schristos 1922*42669be3Schristos if (er == NULL) 1923*42669be3Schristos return -1; 1924*42669be3Schristos 1925*42669be3Schristos ap = wps_er_ap_get(er, NULL, uuid); 1926*42669be3Schristos if (ap == NULL) { 1927*42669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: AP not found for set config " 1928*42669be3Schristos "request"); 1929*42669be3Schristos return -1; 1930*42669be3Schristos } 1931*42669be3Schristos 1932*42669be3Schristos os_free(ap->ap_settings); 1933*42669be3Schristos ap->ap_settings = os_malloc(sizeof(*cred)); 1934*42669be3Schristos if (ap->ap_settings == NULL) 1935*42669be3Schristos return -1; 1936*42669be3Schristos os_memcpy(ap->ap_settings, cred, sizeof(*cred)); 1937*42669be3Schristos ap->ap_settings->cred_attr = NULL; 1938*42669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: Updated local AP settings based set " 1939*42669be3Schristos "config request"); 1940*42669be3Schristos 1941*42669be3Schristos return 0; 1942*42669be3Schristos } 1943*42669be3Schristos 1944*42669be3Schristos 1945*42669be3Schristos static void wps_er_ap_config_m1(struct wps_er_ap *ap, struct wpabuf *m1) 1946*42669be3Schristos { 1947*42669be3Schristos struct wps_config cfg; 1948*42669be3Schristos 1949*42669be3Schristos if (ap->wps) { 1950*42669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: Protocol run already in " 1951*42669be3Schristos "progress with this AP"); 1952*42669be3Schristos return; 1953*42669be3Schristos } 1954*42669be3Schristos 1955*42669be3Schristos os_memset(&cfg, 0, sizeof(cfg)); 1956*42669be3Schristos cfg.wps = ap->er->wps; 1957*42669be3Schristos cfg.registrar = 1; 1958*42669be3Schristos cfg.new_ap_settings = ap->ap_settings; 1959*42669be3Schristos ap->wps = wps_init(&cfg); 1960*42669be3Schristos if (ap->wps == NULL) 1961*42669be3Schristos return; 1962*42669be3Schristos ap->wps->ap_settings_cb = NULL; 1963*42669be3Schristos ap->wps->ap_settings_cb_ctx = NULL; 1964*42669be3Schristos 1965*42669be3Schristos wps_er_ap_process(ap, m1); 1966*42669be3Schristos } 1967*42669be3Schristos 1968*42669be3Schristos 1969*42669be3Schristos int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin, 1970*42669be3Schristos size_t pin_len, const struct wps_credential *cred) 1971*42669be3Schristos { 1972*42669be3Schristos struct wps_er_ap *ap; 1973*42669be3Schristos 1974*42669be3Schristos if (er == NULL) 1975*42669be3Schristos return -1; 1976*42669be3Schristos 1977*42669be3Schristos ap = wps_er_ap_get(er, NULL, uuid); 1978*42669be3Schristos if (ap == NULL) { 1979*42669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: AP not found for config " 1980*42669be3Schristos "request"); 1981*42669be3Schristos return -1; 1982*42669be3Schristos } 1983*42669be3Schristos if (ap->wps) { 1984*42669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing " 1985*42669be3Schristos "with the AP - cannot start config"); 1986*42669be3Schristos return -1; 1987*42669be3Schristos } 1988*42669be3Schristos 1989*42669be3Schristos os_free(ap->ap_settings); 1990*42669be3Schristos ap->ap_settings = os_malloc(sizeof(*cred)); 1991*42669be3Schristos if (ap->ap_settings == NULL) 1992*42669be3Schristos return -1; 1993*42669be3Schristos os_memcpy(ap->ap_settings, cred, sizeof(*cred)); 1994*42669be3Schristos ap->ap_settings->cred_attr = NULL; 1995*42669be3Schristos 1996*42669be3Schristos if (wps_er_send_get_device_info(ap, wps_er_ap_config_m1) < 0) 1997*42669be3Schristos return -1; 1998*42669be3Schristos 1999*42669be3Schristos er->skip_set_sel_reg = 1; 2000*42669be3Schristos wps_registrar_add_pin(er->wps->registrar, NULL, uuid, pin, pin_len, 0); 2001*42669be3Schristos er->skip_set_sel_reg = 0; 20028dbcf02cSchristos 20038dbcf02cSchristos return 0; 20048dbcf02cSchristos } 2005