18dbcf02cSchristos /*
28dbcf02cSchristos * Wi-Fi Protected Setup - External Registrar
336d97821Schristos * Copyright (c) 2009-2013, Jouni Malinen <j@w1.fi>
48dbcf02cSchristos *
562a52023Schristos * This software may be distributed under the terms of the BSD license.
662a52023Schristos * See README for more details.
78dbcf02cSchristos */
88dbcf02cSchristos
98dbcf02cSchristos #include "includes.h"
108dbcf02cSchristos
118dbcf02cSchristos #include "common.h"
128dbcf02cSchristos #include "base64.h"
138dbcf02cSchristos #include "uuid.h"
148dbcf02cSchristos #include "eloop.h"
158dbcf02cSchristos #include "httpread.h"
168dbcf02cSchristos #include "http_client.h"
178dbcf02cSchristos #include "http_server.h"
188dbcf02cSchristos #include "upnp_xml.h"
198dbcf02cSchristos #include "wps_i.h"
208dbcf02cSchristos #include "wps_upnp.h"
218dbcf02cSchristos #include "wps_upnp_i.h"
228dbcf02cSchristos #include "wps_er.h"
238dbcf02cSchristos
248dbcf02cSchristos
258dbcf02cSchristos static void wps_er_deinit_finish(void *eloop_data, void *user_ctx);
268dbcf02cSchristos static void wps_er_ap_timeout(void *eloop_data, void *user_ctx);
278dbcf02cSchristos static void wps_er_sta_timeout(void *eloop_data, void *user_ctx);
288dbcf02cSchristos static void wps_er_ap_process(struct wps_er_ap *ap, struct wpabuf *msg);
298dbcf02cSchristos static int wps_er_send_get_device_info(struct wps_er_ap *ap,
308dbcf02cSchristos void (*m1_handler)(struct wps_er_ap *ap,
318dbcf02cSchristos struct wpabuf *m1));
328dbcf02cSchristos
338dbcf02cSchristos
wps_er_sta_event(struct wps_context * wps,struct wps_er_sta * sta,enum wps_event event)348dbcf02cSchristos static void wps_er_sta_event(struct wps_context *wps, struct wps_er_sta *sta,
358dbcf02cSchristos enum wps_event event)
368dbcf02cSchristos {
378dbcf02cSchristos union wps_event_data data;
388dbcf02cSchristos struct wps_event_er_enrollee *ev = &data.enrollee;
398dbcf02cSchristos
408dbcf02cSchristos if (wps->event_cb == NULL)
418dbcf02cSchristos return;
428dbcf02cSchristos
438dbcf02cSchristos os_memset(&data, 0, sizeof(data));
448dbcf02cSchristos ev->uuid = sta->uuid;
458dbcf02cSchristos ev->mac_addr = sta->addr;
468dbcf02cSchristos ev->m1_received = sta->m1_received;
478dbcf02cSchristos ev->config_methods = sta->config_methods;
488dbcf02cSchristos ev->dev_passwd_id = sta->dev_passwd_id;
498dbcf02cSchristos ev->pri_dev_type = sta->pri_dev_type;
508dbcf02cSchristos ev->dev_name = sta->dev_name;
518dbcf02cSchristos ev->manufacturer = sta->manufacturer;
528dbcf02cSchristos ev->model_name = sta->model_name;
538dbcf02cSchristos ev->model_number = sta->model_number;
548dbcf02cSchristos ev->serial_number = sta->serial_number;
558dbcf02cSchristos wps->event_cb(wps->cb_ctx, event, &data);
568dbcf02cSchristos }
578dbcf02cSchristos
588dbcf02cSchristos
wps_er_sta_get(struct wps_er_ap * ap,const u8 * addr,const u8 * uuid)5942669be3Schristos static struct wps_er_sta * wps_er_sta_get(struct wps_er_ap *ap, const u8 *addr,
6042669be3Schristos const u8 *uuid)
618dbcf02cSchristos {
628dbcf02cSchristos struct wps_er_sta *sta;
638dbcf02cSchristos dl_list_for_each(sta, &ap->sta, struct wps_er_sta, list) {
6442669be3Schristos if ((addr == NULL ||
6542669be3Schristos os_memcmp(sta->addr, addr, ETH_ALEN) == 0) &&
6642669be3Schristos (uuid == NULL ||
6742669be3Schristos os_memcmp(uuid, sta->uuid, WPS_UUID_LEN) == 0))
688dbcf02cSchristos return sta;
698dbcf02cSchristos }
708dbcf02cSchristos return NULL;
718dbcf02cSchristos }
728dbcf02cSchristos
738dbcf02cSchristos
wps_er_sta_free(struct wps_er_sta * sta)748dbcf02cSchristos static void wps_er_sta_free(struct wps_er_sta *sta)
758dbcf02cSchristos {
768dbcf02cSchristos wps_er_sta_event(sta->ap->er->wps, sta, WPS_EV_ER_ENROLLEE_REMOVE);
778dbcf02cSchristos if (sta->wps)
788dbcf02cSchristos wps_deinit(sta->wps);
798dbcf02cSchristos os_free(sta->manufacturer);
808dbcf02cSchristos os_free(sta->model_name);
818dbcf02cSchristos os_free(sta->model_number);
828dbcf02cSchristos os_free(sta->serial_number);
838dbcf02cSchristos os_free(sta->dev_name);
848dbcf02cSchristos http_client_free(sta->http);
858dbcf02cSchristos eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL);
861b7205bfSchristos os_free(sta->cred);
878dbcf02cSchristos os_free(sta);
888dbcf02cSchristos }
898dbcf02cSchristos
908dbcf02cSchristos
wps_er_sta_remove_all(struct wps_er_ap * ap)918dbcf02cSchristos static void wps_er_sta_remove_all(struct wps_er_ap *ap)
928dbcf02cSchristos {
938dbcf02cSchristos struct wps_er_sta *prev, *sta;
948dbcf02cSchristos dl_list_for_each_safe(sta, prev, &ap->sta, struct wps_er_sta, list)
958dbcf02cSchristos wps_er_sta_free(sta);
968dbcf02cSchristos }
978dbcf02cSchristos
988dbcf02cSchristos
wps_er_ap_get(struct wps_er * er,struct in_addr * addr,const u8 * uuid,const u8 * mac_addr)998dbcf02cSchristos static struct wps_er_ap * wps_er_ap_get(struct wps_er *er,
10036d97821Schristos struct in_addr *addr, const u8 *uuid,
10136d97821Schristos const u8 *mac_addr)
1028dbcf02cSchristos {
1038dbcf02cSchristos struct wps_er_ap *ap;
1048dbcf02cSchristos dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
1058dbcf02cSchristos if ((addr == NULL || ap->addr.s_addr == addr->s_addr) &&
1068dbcf02cSchristos (uuid == NULL ||
10736d97821Schristos os_memcmp(uuid, ap->uuid, WPS_UUID_LEN) == 0) &&
10836d97821Schristos (mac_addr == NULL ||
10936d97821Schristos os_memcmp(mac_addr, ap->mac_addr, ETH_ALEN) == 0))
1108dbcf02cSchristos return ap;
1118dbcf02cSchristos }
1128dbcf02cSchristos return NULL;
1138dbcf02cSchristos }
1148dbcf02cSchristos
1158dbcf02cSchristos
wps_er_ap_get_id(struct wps_er * er,unsigned int id)1168dbcf02cSchristos static struct wps_er_ap * wps_er_ap_get_id(struct wps_er *er, unsigned int id)
1178dbcf02cSchristos {
1188dbcf02cSchristos struct wps_er_ap *ap;
1198dbcf02cSchristos dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
1208dbcf02cSchristos if (ap->id == id)
1218dbcf02cSchristos return ap;
1228dbcf02cSchristos }
1238dbcf02cSchristos return NULL;
1248dbcf02cSchristos }
1258dbcf02cSchristos
1268dbcf02cSchristos
wps_er_ap_event(struct wps_context * wps,struct wps_er_ap * ap,enum wps_event event)1278dbcf02cSchristos static void wps_er_ap_event(struct wps_context *wps, struct wps_er_ap *ap,
1288dbcf02cSchristos enum wps_event event)
1298dbcf02cSchristos {
1308dbcf02cSchristos union wps_event_data data;
1318dbcf02cSchristos struct wps_event_er_ap *evap = &data.ap;
1328dbcf02cSchristos
1338dbcf02cSchristos if (wps->event_cb == NULL)
1348dbcf02cSchristos return;
1358dbcf02cSchristos
1368dbcf02cSchristos os_memset(&data, 0, sizeof(data));
1378dbcf02cSchristos evap->uuid = ap->uuid;
1388dbcf02cSchristos evap->friendly_name = ap->friendly_name;
1398dbcf02cSchristos evap->manufacturer = ap->manufacturer;
1408dbcf02cSchristos evap->manufacturer_url = ap->manufacturer_url;
1418dbcf02cSchristos evap->model_description = ap->model_description;
1428dbcf02cSchristos evap->model_name = ap->model_name;
1438dbcf02cSchristos evap->model_number = ap->model_number;
1448dbcf02cSchristos evap->model_url = ap->model_url;
1458dbcf02cSchristos evap->serial_number = ap->serial_number;
1468dbcf02cSchristos evap->upc = ap->upc;
1478dbcf02cSchristos evap->pri_dev_type = ap->pri_dev_type;
1488dbcf02cSchristos evap->wps_state = ap->wps_state;
1498dbcf02cSchristos evap->mac_addr = ap->mac_addr;
1508dbcf02cSchristos wps->event_cb(wps->cb_ctx, event, &data);
1518dbcf02cSchristos }
1528dbcf02cSchristos
1538dbcf02cSchristos
wps_er_ap_free(struct wps_er_ap * ap)1548dbcf02cSchristos static void wps_er_ap_free(struct wps_er_ap *ap)
1558dbcf02cSchristos {
1568dbcf02cSchristos http_client_free(ap->http);
1578dbcf02cSchristos ap->http = NULL;
1588dbcf02cSchristos
1598dbcf02cSchristos os_free(ap->location);
1608dbcf02cSchristos os_free(ap->friendly_name);
1618dbcf02cSchristos os_free(ap->manufacturer);
1628dbcf02cSchristos os_free(ap->manufacturer_url);
1638dbcf02cSchristos os_free(ap->model_description);
1648dbcf02cSchristos os_free(ap->model_name);
1658dbcf02cSchristos os_free(ap->model_number);
1668dbcf02cSchristos os_free(ap->model_url);
1678dbcf02cSchristos os_free(ap->serial_number);
1688dbcf02cSchristos os_free(ap->udn);
1698dbcf02cSchristos os_free(ap->upc);
1708dbcf02cSchristos
1718dbcf02cSchristos os_free(ap->scpd_url);
1728dbcf02cSchristos os_free(ap->control_url);
1738dbcf02cSchristos os_free(ap->event_sub_url);
1748dbcf02cSchristos
1758dbcf02cSchristos os_free(ap->ap_settings);
1768dbcf02cSchristos
1778dbcf02cSchristos os_free(ap);
1788dbcf02cSchristos }
1798dbcf02cSchristos
1808dbcf02cSchristos
wps_er_ap_unsubscribed(struct wps_er * er,struct wps_er_ap * ap)1818dbcf02cSchristos static void wps_er_ap_unsubscribed(struct wps_er *er, struct wps_er_ap *ap)
1828dbcf02cSchristos {
1838dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Unsubscribed from AP %s (%s)",
1848dbcf02cSchristos inet_ntoa(ap->addr), ap->location);
1858dbcf02cSchristos dl_list_del(&ap->list);
1868dbcf02cSchristos wps_er_ap_free(ap);
1878dbcf02cSchristos
18836d97821Schristos if (er->deinitializing && dl_list_empty(&er->ap_unsubscribing))
1898dbcf02cSchristos wps_er_deinit_finish(er, NULL);
1908dbcf02cSchristos }
1918dbcf02cSchristos
1928dbcf02cSchristos
wps_er_http_unsubscribe_cb(void * ctx,struct http_client * c,enum http_client_event event)1938dbcf02cSchristos static void wps_er_http_unsubscribe_cb(void *ctx, struct http_client *c,
1948dbcf02cSchristos enum http_client_event event)
1958dbcf02cSchristos {
1968dbcf02cSchristos struct wps_er_ap *ap = ctx;
1978dbcf02cSchristos
1988dbcf02cSchristos switch (event) {
1998dbcf02cSchristos case HTTP_CLIENT_OK:
2008dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Unsubscribed from events");
2018dbcf02cSchristos ap->subscribed = 0;
2028dbcf02cSchristos break;
2038dbcf02cSchristos case HTTP_CLIENT_FAILED:
2048dbcf02cSchristos case HTTP_CLIENT_INVALID_REPLY:
2058dbcf02cSchristos case HTTP_CLIENT_TIMEOUT:
2068dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to unsubscribe from "
2078dbcf02cSchristos "events");
2088dbcf02cSchristos break;
2098dbcf02cSchristos }
2108dbcf02cSchristos http_client_free(ap->http);
2118dbcf02cSchristos ap->http = NULL;
2128dbcf02cSchristos
2138dbcf02cSchristos /*
2148dbcf02cSchristos * Need to get rid of the AP entry regardless of whether we managed to
2158dbcf02cSchristos * unsubscribe cleanly or not.
2168dbcf02cSchristos */
2178dbcf02cSchristos wps_er_ap_unsubscribed(ap->er, ap);
2188dbcf02cSchristos }
2198dbcf02cSchristos
2208dbcf02cSchristos
wps_er_ap_unsubscribe(struct wps_er * er,struct wps_er_ap * ap)2218dbcf02cSchristos static void wps_er_ap_unsubscribe(struct wps_er *er, struct wps_er_ap *ap)
2228dbcf02cSchristos {
2238dbcf02cSchristos struct wpabuf *req;
2248dbcf02cSchristos struct sockaddr_in dst;
2258dbcf02cSchristos char *url, *path;
2268dbcf02cSchristos char sid[100];
2278dbcf02cSchristos
2288dbcf02cSchristos if (ap->event_sub_url == NULL) {
2298dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: No eventSubURL - cannot "
2308dbcf02cSchristos "subscribe");
2318dbcf02cSchristos goto fail;
2328dbcf02cSchristos }
2338dbcf02cSchristos if (ap->http) {
2348dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request - cannot "
2358dbcf02cSchristos "send subscribe request");
2368dbcf02cSchristos goto fail;
2378dbcf02cSchristos }
2388dbcf02cSchristos
2398dbcf02cSchristos url = http_client_url_parse(ap->event_sub_url, &dst, &path);
2408dbcf02cSchristos if (url == NULL) {
2418dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse eventSubURL");
2428dbcf02cSchristos goto fail;
2438dbcf02cSchristos }
2448dbcf02cSchristos
2458dbcf02cSchristos req = wpabuf_alloc(os_strlen(ap->event_sub_url) + 1000);
2468dbcf02cSchristos if (req == NULL) {
2478dbcf02cSchristos os_free(url);
2488dbcf02cSchristos goto fail;
2498dbcf02cSchristos }
2508dbcf02cSchristos uuid_bin2str(ap->sid, sid, sizeof(sid));
2518dbcf02cSchristos wpabuf_printf(req,
2528dbcf02cSchristos "UNSUBSCRIBE %s HTTP/1.1\r\n"
2538dbcf02cSchristos "HOST: %s:%d\r\n"
2548dbcf02cSchristos "SID: uuid:%s\r\n"
2558dbcf02cSchristos "\r\n",
2568dbcf02cSchristos path, inet_ntoa(dst.sin_addr), ntohs(dst.sin_port), sid);
2578dbcf02cSchristos os_free(url);
2588dbcf02cSchristos wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Unsubscription request",
2598dbcf02cSchristos wpabuf_head(req), wpabuf_len(req));
2608dbcf02cSchristos
2618dbcf02cSchristos ap->http = http_client_addr(&dst, req, 1000,
2628dbcf02cSchristos wps_er_http_unsubscribe_cb, ap);
2638dbcf02cSchristos if (ap->http == NULL) {
2648dbcf02cSchristos wpabuf_free(req);
2658dbcf02cSchristos goto fail;
2668dbcf02cSchristos }
2678dbcf02cSchristos return;
2688dbcf02cSchristos
2698dbcf02cSchristos fail:
2708dbcf02cSchristos /*
2718dbcf02cSchristos * Need to get rid of the AP entry even when we fail to unsubscribe
2728dbcf02cSchristos * cleanly.
2738dbcf02cSchristos */
2748dbcf02cSchristos wps_er_ap_unsubscribed(ap->er, ap);
2758dbcf02cSchristos }
2768dbcf02cSchristos
27742669be3Schristos
wps_er_ap_get_settings(struct wps_er * er,const u8 * uuid)27842669be3Schristos static struct wps_er_ap_settings * wps_er_ap_get_settings(struct wps_er *er,
27942669be3Schristos const u8 *uuid)
28042669be3Schristos {
28142669be3Schristos struct wps_er_ap_settings *s;
28242669be3Schristos dl_list_for_each(s, &er->ap_settings, struct wps_er_ap_settings, list)
28342669be3Schristos if (os_memcmp(uuid, s->uuid, WPS_UUID_LEN) == 0)
28442669be3Schristos return s;
28542669be3Schristos return NULL;
28642669be3Schristos }
28742669be3Schristos
28842669be3Schristos
wps_er_ap_cache_settings(struct wps_er * er,struct in_addr * addr)28942669be3Schristos int wps_er_ap_cache_settings(struct wps_er *er, struct in_addr *addr)
29042669be3Schristos {
29142669be3Schristos struct wps_er_ap *ap;
29242669be3Schristos struct wps_er_ap_settings *settings;
29342669be3Schristos
29436d97821Schristos ap = wps_er_ap_get(er, addr, NULL, NULL);
29542669be3Schristos if (ap == NULL || ap->ap_settings == NULL)
29642669be3Schristos return -1;
29742669be3Schristos
29842669be3Schristos settings = wps_er_ap_get_settings(er, ap->uuid);
29942669be3Schristos if (!settings) {
30042669be3Schristos settings = os_zalloc(sizeof(*settings));
30142669be3Schristos if (settings == NULL)
30242669be3Schristos return -1;
30342669be3Schristos os_memcpy(settings->uuid, ap->uuid, WPS_UUID_LEN);
30442669be3Schristos dl_list_add(&er->ap_settings, &settings->list);
30542669be3Schristos }
30642669be3Schristos os_memcpy(&settings->ap_settings, ap->ap_settings,
30742669be3Schristos sizeof(struct wps_credential));
30842669be3Schristos
30942669be3Schristos return 0;
31042669be3Schristos }
31142669be3Schristos
31242669be3Schristos
wps_er_ap_use_cached_settings(struct wps_er * er,struct wps_er_ap * ap)31342669be3Schristos static int wps_er_ap_use_cached_settings(struct wps_er *er,
31442669be3Schristos struct wps_er_ap *ap)
31542669be3Schristos {
31642669be3Schristos struct wps_er_ap_settings *s;
31742669be3Schristos
31842669be3Schristos if (ap->ap_settings)
31942669be3Schristos return 0;
32042669be3Schristos
32142669be3Schristos s = wps_er_ap_get_settings(ap->er, ap->uuid);
32242669be3Schristos if (!s)
32342669be3Schristos return -1;
32442669be3Schristos
325ebb5671cSchristos ap->ap_settings = os_memdup(&s->ap_settings, sizeof(*ap->ap_settings));
32642669be3Schristos if (ap->ap_settings == NULL)
32742669be3Schristos return -1;
32842669be3Schristos
32942669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: Use cached AP settings");
33042669be3Schristos return 0;
33142669be3Schristos }
33242669be3Schristos
33342669be3Schristos
wps_er_ap_remove_entry(struct wps_er * er,struct wps_er_ap * ap)3348dbcf02cSchristos static void wps_er_ap_remove_entry(struct wps_er *er, struct wps_er_ap *ap)
3358dbcf02cSchristos {
3368dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Removing AP entry for %s (%s)",
3378dbcf02cSchristos inet_ntoa(ap->addr), ap->location);
3388dbcf02cSchristos eloop_cancel_timeout(wps_er_ap_timeout, er, ap);
3398dbcf02cSchristos wps_er_sta_remove_all(ap);
3408dbcf02cSchristos wps_er_ap_event(er->wps, ap, WPS_EV_ER_AP_REMOVE);
3418dbcf02cSchristos http_client_free(ap->http);
3428dbcf02cSchristos ap->http = NULL;
3438dbcf02cSchristos if (ap->wps) {
3448dbcf02cSchristos wps_deinit(ap->wps);
3458dbcf02cSchristos ap->wps = NULL;
3468dbcf02cSchristos }
3478dbcf02cSchristos
3488dbcf02cSchristos dl_list_del(&ap->list);
3498dbcf02cSchristos if (ap->subscribed) {
3508dbcf02cSchristos dl_list_add(&er->ap_unsubscribing, &ap->list);
3518dbcf02cSchristos wps_er_ap_unsubscribe(er, ap);
3528dbcf02cSchristos } else
3538dbcf02cSchristos wps_er_ap_free(ap);
3548dbcf02cSchristos }
3558dbcf02cSchristos
3568dbcf02cSchristos
wps_er_ap_timeout(void * eloop_data,void * user_ctx)3578dbcf02cSchristos static void wps_er_ap_timeout(void *eloop_data, void *user_ctx)
3588dbcf02cSchristos {
3598dbcf02cSchristos struct wps_er *er = eloop_data;
3608dbcf02cSchristos struct wps_er_ap *ap = user_ctx;
3618dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: AP advertisement timed out");
3628dbcf02cSchristos wps_er_ap_remove_entry(er, ap);
3638dbcf02cSchristos }
3648dbcf02cSchristos
3658dbcf02cSchristos
wps_er_get_sid(struct wps_er_ap * ap,char * sid)3668dbcf02cSchristos static int wps_er_get_sid(struct wps_er_ap *ap, char *sid)
3678dbcf02cSchristos {
3688dbcf02cSchristos char *pos;
3698dbcf02cSchristos char txt[100];
3708dbcf02cSchristos
3718dbcf02cSchristos if (!sid) {
3728dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: No SID received from %s (%s)",
3738dbcf02cSchristos inet_ntoa(ap->addr), ap->location);
3748dbcf02cSchristos return -1;
3758dbcf02cSchristos }
3768dbcf02cSchristos
3778dbcf02cSchristos pos = os_strstr(sid, "uuid:");
3788dbcf02cSchristos if (!pos) {
3798dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Invalid SID received from "
3808dbcf02cSchristos "%s (%s): '%s'", inet_ntoa(ap->addr), ap->location,
3818dbcf02cSchristos sid);
3828dbcf02cSchristos return -1;
3838dbcf02cSchristos }
3848dbcf02cSchristos
3858dbcf02cSchristos pos += 5;
3868dbcf02cSchristos if (uuid_str2bin(pos, ap->sid) < 0) {
3878dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Invalid SID received from "
3888dbcf02cSchristos "%s (%s): '%s'", inet_ntoa(ap->addr), ap->location,
3898dbcf02cSchristos sid);
3908dbcf02cSchristos return -1;
3918dbcf02cSchristos }
3928dbcf02cSchristos
3938dbcf02cSchristos uuid_bin2str(ap->sid, txt, sizeof(txt));
3948dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: SID for subscription with %s (%s): %s",
3958dbcf02cSchristos inet_ntoa(ap->addr), ap->location, txt);
3968dbcf02cSchristos
3978dbcf02cSchristos return 0;
3988dbcf02cSchristos }
3998dbcf02cSchristos
4008dbcf02cSchristos
wps_er_http_subscribe_cb(void * ctx,struct http_client * c,enum http_client_event event)4018dbcf02cSchristos static void wps_er_http_subscribe_cb(void *ctx, struct http_client *c,
4028dbcf02cSchristos enum http_client_event event)
4038dbcf02cSchristos {
4048dbcf02cSchristos struct wps_er_ap *ap = ctx;
4058dbcf02cSchristos
4068dbcf02cSchristos switch (event) {
4078dbcf02cSchristos case HTTP_CLIENT_OK:
4088dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Subscribed to events");
4098dbcf02cSchristos ap->subscribed = 1;
4108dbcf02cSchristos wps_er_get_sid(ap, http_client_get_hdr_line(c, "SID"));
41142669be3Schristos wps_er_ap_use_cached_settings(ap->er, ap);
4128dbcf02cSchristos wps_er_ap_event(ap->er->wps, ap, WPS_EV_ER_AP_ADD);
4138dbcf02cSchristos break;
4148dbcf02cSchristos case HTTP_CLIENT_FAILED:
4158dbcf02cSchristos case HTTP_CLIENT_INVALID_REPLY:
4168dbcf02cSchristos case HTTP_CLIENT_TIMEOUT:
4178dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to subscribe to events");
4188dbcf02cSchristos break;
4198dbcf02cSchristos }
4208dbcf02cSchristos http_client_free(ap->http);
4218dbcf02cSchristos ap->http = NULL;
4228dbcf02cSchristos }
4238dbcf02cSchristos
4248dbcf02cSchristos
wps_er_subscribe(struct wps_er_ap * ap)4258dbcf02cSchristos static void wps_er_subscribe(struct wps_er_ap *ap)
4268dbcf02cSchristos {
4278dbcf02cSchristos struct wpabuf *req;
4288dbcf02cSchristos struct sockaddr_in dst;
4298dbcf02cSchristos char *url, *path;
4308dbcf02cSchristos
4318dbcf02cSchristos if (ap->event_sub_url == NULL) {
4328dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: No eventSubURL - cannot "
4338dbcf02cSchristos "subscribe");
4348dbcf02cSchristos return;
4358dbcf02cSchristos }
4368dbcf02cSchristos if (ap->http) {
4378dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request - cannot "
4388dbcf02cSchristos "send subscribe request");
4398dbcf02cSchristos return;
4408dbcf02cSchristos }
4418dbcf02cSchristos
4428dbcf02cSchristos url = http_client_url_parse(ap->event_sub_url, &dst, &path);
4438dbcf02cSchristos if (url == NULL) {
4448dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse eventSubURL");
4458dbcf02cSchristos return;
4468dbcf02cSchristos }
4478dbcf02cSchristos
4488dbcf02cSchristos req = wpabuf_alloc(os_strlen(ap->event_sub_url) + 1000);
4498dbcf02cSchristos if (req == NULL) {
4508dbcf02cSchristos os_free(url);
4518dbcf02cSchristos return;
4528dbcf02cSchristos }
4538dbcf02cSchristos wpabuf_printf(req,
4548dbcf02cSchristos "SUBSCRIBE %s HTTP/1.1\r\n"
4558dbcf02cSchristos "HOST: %s:%d\r\n"
4568dbcf02cSchristos "CALLBACK: <http://%s:%d/event/%u/%u>\r\n"
4578dbcf02cSchristos "NT: upnp:event\r\n"
4588dbcf02cSchristos "TIMEOUT: Second-%d\r\n"
4598dbcf02cSchristos "\r\n",
4608dbcf02cSchristos path, inet_ntoa(dst.sin_addr), ntohs(dst.sin_port),
4618dbcf02cSchristos ap->er->ip_addr_text, ap->er->http_port,
4628dbcf02cSchristos ap->er->event_id, ap->id, 1800);
4638dbcf02cSchristos os_free(url);
4648dbcf02cSchristos wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Subscription request",
4658dbcf02cSchristos wpabuf_head(req), wpabuf_len(req));
4668dbcf02cSchristos
4678dbcf02cSchristos ap->http = http_client_addr(&dst, req, 1000, wps_er_http_subscribe_cb,
4688dbcf02cSchristos ap);
4698dbcf02cSchristos if (ap->http == NULL)
4708dbcf02cSchristos wpabuf_free(req);
4718dbcf02cSchristos }
4728dbcf02cSchristos
4738dbcf02cSchristos
wps_er_ap_get_m1(struct wps_er_ap * ap,struct wpabuf * m1)4748dbcf02cSchristos static void wps_er_ap_get_m1(struct wps_er_ap *ap, struct wpabuf *m1)
4758dbcf02cSchristos {
4768dbcf02cSchristos struct wps_parse_attr attr;
4778dbcf02cSchristos
4788dbcf02cSchristos if (wps_parse_msg(m1, &attr) < 0) {
4798dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse M1");
4808dbcf02cSchristos return;
4818dbcf02cSchristos }
4828dbcf02cSchristos if (attr.primary_dev_type)
4838dbcf02cSchristos os_memcpy(ap->pri_dev_type, attr.primary_dev_type, 8);
4848dbcf02cSchristos if (attr.wps_state)
4858dbcf02cSchristos ap->wps_state = *attr.wps_state;
4868dbcf02cSchristos if (attr.mac_addr)
4878dbcf02cSchristos os_memcpy(ap->mac_addr, attr.mac_addr, ETH_ALEN);
4888dbcf02cSchristos
4898dbcf02cSchristos wps_er_subscribe(ap);
4908dbcf02cSchristos }
4918dbcf02cSchristos
4928dbcf02cSchristos
wps_er_get_device_info(struct wps_er_ap * ap)4938dbcf02cSchristos static void wps_er_get_device_info(struct wps_er_ap *ap)
4948dbcf02cSchristos {
4958dbcf02cSchristos wps_er_send_get_device_info(ap, wps_er_ap_get_m1);
4968dbcf02cSchristos }
4978dbcf02cSchristos
4988dbcf02cSchristos
wps_er_find_wfadevice(const char * data)49942669be3Schristos static const char * wps_er_find_wfadevice(const char *data)
50042669be3Schristos {
50142669be3Schristos const char *tag, *tagname, *end;
50242669be3Schristos char *val;
50342669be3Schristos int found = 0;
50442669be3Schristos
50542669be3Schristos while (!found) {
50642669be3Schristos /* Find next <device> */
50742669be3Schristos for (;;) {
50842669be3Schristos if (xml_next_tag(data, &tag, &tagname, &end))
50942669be3Schristos return NULL;
51042669be3Schristos data = end;
51142669be3Schristos if (!os_strncasecmp(tagname, "device", 6) &&
51242669be3Schristos *tag != '/' &&
51342669be3Schristos (tagname[6] == '>' || !isgraph(tagname[6]))) {
51442669be3Schristos break;
51542669be3Schristos }
51642669be3Schristos }
51742669be3Schristos
51842669be3Schristos /* Check whether deviceType is WFADevice */
51942669be3Schristos val = xml_get_first_item(data, "deviceType");
52042669be3Schristos if (val == NULL)
52142669be3Schristos return NULL;
52242669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: Found deviceType '%s'", val);
52342669be3Schristos found = os_strcasecmp(val, "urn:schemas-wifialliance-org:"
52442669be3Schristos "device:WFADevice:1") == 0;
52542669be3Schristos os_free(val);
52642669be3Schristos }
52742669be3Schristos
52842669be3Schristos return data;
52942669be3Schristos }
53042669be3Schristos
53142669be3Schristos
wps_er_parse_device_description(struct wps_er_ap * ap,struct wpabuf * reply)5328dbcf02cSchristos static void wps_er_parse_device_description(struct wps_er_ap *ap,
5338dbcf02cSchristos struct wpabuf *reply)
5348dbcf02cSchristos {
5358dbcf02cSchristos /* Note: reply includes null termination after the buffer data */
53642669be3Schristos const char *tmp, *data = wpabuf_head(reply);
5378dbcf02cSchristos char *pos;
5388dbcf02cSchristos
5398dbcf02cSchristos wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Device info",
5408dbcf02cSchristos wpabuf_head(reply), wpabuf_len(reply));
5418dbcf02cSchristos
54242669be3Schristos /*
54342669be3Schristos * The root device description may include multiple devices, so first
54442669be3Schristos * find the beginning of the WFADevice description to allow the
54542669be3Schristos * simplistic parser to pick the correct entries.
54642669be3Schristos */
54742669be3Schristos tmp = wps_er_find_wfadevice(data);
54842669be3Schristos if (tmp == NULL) {
54942669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: WFADevice:1 device not found - "
55042669be3Schristos "trying to parse invalid data");
55142669be3Schristos } else
55242669be3Schristos data = tmp;
55342669be3Schristos
5548dbcf02cSchristos ap->friendly_name = xml_get_first_item(data, "friendlyName");
5558dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: friendlyName='%s'", ap->friendly_name);
5568dbcf02cSchristos
5578dbcf02cSchristos ap->manufacturer = xml_get_first_item(data, "manufacturer");
5588dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: manufacturer='%s'", ap->manufacturer);
5598dbcf02cSchristos
5608dbcf02cSchristos ap->manufacturer_url = xml_get_first_item(data, "manufacturerURL");
5618dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: manufacturerURL='%s'",
5628dbcf02cSchristos ap->manufacturer_url);
5638dbcf02cSchristos
5648dbcf02cSchristos ap->model_description = xml_get_first_item(data, "modelDescription");
5658dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: modelDescription='%s'",
5668dbcf02cSchristos ap->model_description);
5678dbcf02cSchristos
5688dbcf02cSchristos ap->model_name = xml_get_first_item(data, "modelName");
5698dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: modelName='%s'", ap->model_name);
5708dbcf02cSchristos
5718dbcf02cSchristos ap->model_number = xml_get_first_item(data, "modelNumber");
5728dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: modelNumber='%s'", ap->model_number);
5738dbcf02cSchristos
5748dbcf02cSchristos ap->model_url = xml_get_first_item(data, "modelURL");
5758dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: modelURL='%s'", ap->model_url);
5768dbcf02cSchristos
5778dbcf02cSchristos ap->serial_number = xml_get_first_item(data, "serialNumber");
5788dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: serialNumber='%s'", ap->serial_number);
5798dbcf02cSchristos
5808dbcf02cSchristos ap->udn = xml_get_first_item(data, "UDN");
58136d97821Schristos if (ap->udn) {
5828dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: UDN='%s'", ap->udn);
5838dbcf02cSchristos pos = os_strstr(ap->udn, "uuid:");
5848dbcf02cSchristos if (pos) {
5858dbcf02cSchristos pos += 5;
5868dbcf02cSchristos if (uuid_str2bin(pos, ap->uuid) < 0)
58736d97821Schristos wpa_printf(MSG_DEBUG,
58836d97821Schristos "WPS ER: Invalid UUID in UDN");
58936d97821Schristos }
5908dbcf02cSchristos }
5918dbcf02cSchristos
5928dbcf02cSchristos ap->upc = xml_get_first_item(data, "UPC");
5938dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: UPC='%s'", ap->upc);
5948dbcf02cSchristos
5958dbcf02cSchristos ap->scpd_url = http_link_update(
5968dbcf02cSchristos xml_get_first_item(data, "SCPDURL"), ap->location);
5978dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: SCPDURL='%s'", ap->scpd_url);
5988dbcf02cSchristos
5998dbcf02cSchristos ap->control_url = http_link_update(
6008dbcf02cSchristos xml_get_first_item(data, "controlURL"), ap->location);
6018dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: controlURL='%s'", ap->control_url);
6028dbcf02cSchristos
6038dbcf02cSchristos ap->event_sub_url = http_link_update(
6048dbcf02cSchristos xml_get_first_item(data, "eventSubURL"), ap->location);
6058dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: eventSubURL='%s'", ap->event_sub_url);
6068dbcf02cSchristos }
6078dbcf02cSchristos
6088dbcf02cSchristos
wps_er_http_dev_desc_cb(void * ctx,struct http_client * c,enum http_client_event event)6098dbcf02cSchristos static void wps_er_http_dev_desc_cb(void *ctx, struct http_client *c,
6108dbcf02cSchristos enum http_client_event event)
6118dbcf02cSchristos {
6128dbcf02cSchristos struct wps_er_ap *ap = ctx;
6138dbcf02cSchristos struct wpabuf *reply;
6148dbcf02cSchristos int ok = 0;
6158dbcf02cSchristos
6168dbcf02cSchristos switch (event) {
6178dbcf02cSchristos case HTTP_CLIENT_OK:
6188dbcf02cSchristos reply = http_client_get_body(c);
6198dbcf02cSchristos if (reply == NULL)
6208dbcf02cSchristos break;
6218dbcf02cSchristos wps_er_parse_device_description(ap, reply);
6228dbcf02cSchristos ok = 1;
6238dbcf02cSchristos break;
6248dbcf02cSchristos case HTTP_CLIENT_FAILED:
6258dbcf02cSchristos case HTTP_CLIENT_INVALID_REPLY:
6268dbcf02cSchristos case HTTP_CLIENT_TIMEOUT:
6278dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to fetch device info");
6288dbcf02cSchristos break;
6298dbcf02cSchristos }
6308dbcf02cSchristos http_client_free(ap->http);
6318dbcf02cSchristos ap->http = NULL;
6328dbcf02cSchristos if (ok)
6338dbcf02cSchristos wps_er_get_device_info(ap);
6348dbcf02cSchristos }
6358dbcf02cSchristos
6368dbcf02cSchristos
wps_er_ap_add(struct wps_er * er,const u8 * uuid,struct in_addr * addr,const char * location,int max_age)6378dbcf02cSchristos void wps_er_ap_add(struct wps_er *er, const u8 *uuid, struct in_addr *addr,
6388dbcf02cSchristos const char *location, int max_age)
6398dbcf02cSchristos {
6408dbcf02cSchristos struct wps_er_ap *ap;
6418dbcf02cSchristos
64236d97821Schristos ap = wps_er_ap_get(er, addr, uuid, NULL);
6438dbcf02cSchristos if (ap) {
6448dbcf02cSchristos /* Update advertisement timeout */
6458dbcf02cSchristos eloop_cancel_timeout(wps_er_ap_timeout, er, ap);
6468dbcf02cSchristos eloop_register_timeout(max_age, 0, wps_er_ap_timeout, er, ap);
6478dbcf02cSchristos return;
6488dbcf02cSchristos }
6498dbcf02cSchristos
6508dbcf02cSchristos ap = os_zalloc(sizeof(*ap));
6518dbcf02cSchristos if (ap == NULL)
6528dbcf02cSchristos return;
6538dbcf02cSchristos dl_list_init(&ap->sta);
6548dbcf02cSchristos ap->er = er;
6558dbcf02cSchristos ap->id = ++er->next_ap_id;
6568dbcf02cSchristos ap->location = os_strdup(location);
6578dbcf02cSchristos if (ap->location == NULL) {
6588dbcf02cSchristos os_free(ap);
6598dbcf02cSchristos return;
6608dbcf02cSchristos }
6618dbcf02cSchristos dl_list_add(&er->ap, &ap->list);
6628dbcf02cSchristos
6638dbcf02cSchristos ap->addr.s_addr = addr->s_addr;
6648dbcf02cSchristos os_memcpy(ap->uuid, uuid, WPS_UUID_LEN);
6658dbcf02cSchristos eloop_register_timeout(max_age, 0, wps_er_ap_timeout, er, ap);
6668dbcf02cSchristos
6678dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Added AP entry for %s (%s)",
6688dbcf02cSchristos inet_ntoa(ap->addr), ap->location);
6698dbcf02cSchristos
6708dbcf02cSchristos /* Fetch device description */
6718dbcf02cSchristos ap->http = http_client_url(ap->location, NULL, 10000,
6728dbcf02cSchristos wps_er_http_dev_desc_cb, ap);
6738dbcf02cSchristos }
6748dbcf02cSchristos
6758dbcf02cSchristos
wps_er_ap_remove(struct wps_er * er,struct in_addr * addr)6768dbcf02cSchristos void wps_er_ap_remove(struct wps_er *er, struct in_addr *addr)
6778dbcf02cSchristos {
6788dbcf02cSchristos struct wps_er_ap *ap;
6798dbcf02cSchristos dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
6808dbcf02cSchristos if (ap->addr.s_addr == addr->s_addr) {
6818dbcf02cSchristos wps_er_ap_remove_entry(er, ap);
6828dbcf02cSchristos return;
6838dbcf02cSchristos }
6848dbcf02cSchristos }
6858dbcf02cSchristos }
6868dbcf02cSchristos
6878dbcf02cSchristos
wps_er_ap_remove_all(struct wps_er * er)6888dbcf02cSchristos static void wps_er_ap_remove_all(struct wps_er *er)
6898dbcf02cSchristos {
6908dbcf02cSchristos struct wps_er_ap *prev, *ap;
69142669be3Schristos struct wps_er_ap_settings *prev_s, *s;
6928dbcf02cSchristos dl_list_for_each_safe(ap, prev, &er->ap, struct wps_er_ap, list)
6938dbcf02cSchristos wps_er_ap_remove_entry(er, ap);
69442669be3Schristos dl_list_for_each_safe(s, prev_s, &er->ap_settings,
69542669be3Schristos struct wps_er_ap_settings, list)
69642669be3Schristos os_free(s);
6978dbcf02cSchristos }
6988dbcf02cSchristos
6998dbcf02cSchristos
http_put_date(struct wpabuf * buf)7008dbcf02cSchristos static void http_put_date(struct wpabuf *buf)
7018dbcf02cSchristos {
7028dbcf02cSchristos wpabuf_put_str(buf, "Date: ");
7038dbcf02cSchristos format_date(buf);
7048dbcf02cSchristos wpabuf_put_str(buf, "\r\n");
7058dbcf02cSchristos }
7068dbcf02cSchristos
7078dbcf02cSchristos
wps_er_http_resp_not_found(struct http_request * req)7088dbcf02cSchristos static void wps_er_http_resp_not_found(struct http_request *req)
7098dbcf02cSchristos {
7108dbcf02cSchristos struct wpabuf *buf;
7118dbcf02cSchristos buf = wpabuf_alloc(200);
7128dbcf02cSchristos if (buf == NULL) {
7138dbcf02cSchristos http_request_deinit(req);
7148dbcf02cSchristos return;
7158dbcf02cSchristos }
7168dbcf02cSchristos
7178dbcf02cSchristos wpabuf_put_str(buf,
7188dbcf02cSchristos "HTTP/1.1 404 Not Found\r\n"
7198dbcf02cSchristos "Server: unspecified, UPnP/1.0, unspecified\r\n"
7208dbcf02cSchristos "Connection: close\r\n");
7218dbcf02cSchristos http_put_date(buf);
7228dbcf02cSchristos wpabuf_put_str(buf, "\r\n");
7238dbcf02cSchristos http_request_send_and_deinit(req, buf);
7248dbcf02cSchristos }
7258dbcf02cSchristos
7268dbcf02cSchristos
wps_er_http_resp_ok(struct http_request * req)7278dbcf02cSchristos static void wps_er_http_resp_ok(struct http_request *req)
7288dbcf02cSchristos {
7298dbcf02cSchristos struct wpabuf *buf;
7308dbcf02cSchristos buf = wpabuf_alloc(200);
7318dbcf02cSchristos if (buf == NULL) {
7328dbcf02cSchristos http_request_deinit(req);
7338dbcf02cSchristos return;
7348dbcf02cSchristos }
7358dbcf02cSchristos
7368dbcf02cSchristos wpabuf_put_str(buf,
7378dbcf02cSchristos "HTTP/1.1 200 OK\r\n"
7388dbcf02cSchristos "Server: unspecified, UPnP/1.0, unspecified\r\n"
7398dbcf02cSchristos "Connection: close\r\n"
7408dbcf02cSchristos "Content-Length: 0\r\n");
7418dbcf02cSchristos http_put_date(buf);
7428dbcf02cSchristos wpabuf_put_str(buf, "\r\n");
7438dbcf02cSchristos http_request_send_and_deinit(req, buf);
7448dbcf02cSchristos }
7458dbcf02cSchristos
7468dbcf02cSchristos
wps_er_sta_timeout(void * eloop_data,void * user_ctx)7478dbcf02cSchristos static void wps_er_sta_timeout(void *eloop_data, void *user_ctx)
7488dbcf02cSchristos {
7498dbcf02cSchristos struct wps_er_sta *sta = eloop_data;
7508dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: STA entry timed out");
7518dbcf02cSchristos dl_list_del(&sta->list);
7528dbcf02cSchristos wps_er_sta_free(sta);
7538dbcf02cSchristos }
7548dbcf02cSchristos
7558dbcf02cSchristos
wps_er_add_sta_data(struct wps_er_ap * ap,const u8 * addr,struct wps_parse_attr * attr,int probe_req)7568dbcf02cSchristos static struct wps_er_sta * wps_er_add_sta_data(struct wps_er_ap *ap,
7578dbcf02cSchristos const u8 *addr,
7588dbcf02cSchristos struct wps_parse_attr *attr,
7598dbcf02cSchristos int probe_req)
7608dbcf02cSchristos {
76142669be3Schristos struct wps_er_sta *sta = wps_er_sta_get(ap, addr, NULL);
7628dbcf02cSchristos int new_sta = 0;
7638dbcf02cSchristos int m1;
7648dbcf02cSchristos
7658dbcf02cSchristos m1 = !probe_req && attr->msg_type && *attr->msg_type == WPS_M1;
7668dbcf02cSchristos
7678dbcf02cSchristos if (sta == NULL) {
7688dbcf02cSchristos /*
7698dbcf02cSchristos * Only allow new STA entry to be added based on Probe Request
7708dbcf02cSchristos * or M1. This will filter out bogus events and anything that
7718dbcf02cSchristos * may have been ongoing at the time ER subscribed for events.
7728dbcf02cSchristos */
7738dbcf02cSchristos if (!probe_req && !m1)
7748dbcf02cSchristos return NULL;
7758dbcf02cSchristos
7768dbcf02cSchristos sta = os_zalloc(sizeof(*sta));
7778dbcf02cSchristos if (sta == NULL)
7788dbcf02cSchristos return NULL;
7798dbcf02cSchristos os_memcpy(sta->addr, addr, ETH_ALEN);
7808dbcf02cSchristos sta->ap = ap;
7818dbcf02cSchristos dl_list_add(&ap->sta, &sta->list);
7828dbcf02cSchristos new_sta = 1;
7838dbcf02cSchristos }
7848dbcf02cSchristos
7858dbcf02cSchristos if (m1)
7868dbcf02cSchristos sta->m1_received = 1;
7878dbcf02cSchristos
7888dbcf02cSchristos if (attr->config_methods && (!probe_req || !sta->m1_received))
7898dbcf02cSchristos sta->config_methods = WPA_GET_BE16(attr->config_methods);
7908dbcf02cSchristos if (attr->uuid_e && (!probe_req || !sta->m1_received))
7918dbcf02cSchristos os_memcpy(sta->uuid, attr->uuid_e, WPS_UUID_LEN);
7928dbcf02cSchristos if (attr->primary_dev_type && (!probe_req || !sta->m1_received))
7938dbcf02cSchristos os_memcpy(sta->pri_dev_type, attr->primary_dev_type, 8);
7948dbcf02cSchristos if (attr->dev_password_id && (!probe_req || !sta->m1_received))
7958dbcf02cSchristos sta->dev_passwd_id = WPA_GET_BE16(attr->dev_password_id);
7968dbcf02cSchristos
7978dbcf02cSchristos if (attr->manufacturer) {
7988dbcf02cSchristos os_free(sta->manufacturer);
79936d97821Schristos sta->manufacturer = dup_binstr(attr->manufacturer,
8008dbcf02cSchristos attr->manufacturer_len);
8018dbcf02cSchristos }
8028dbcf02cSchristos
8038dbcf02cSchristos if (attr->model_name) {
8048dbcf02cSchristos os_free(sta->model_name);
80536d97821Schristos sta->model_name = dup_binstr(attr->model_name,
8068dbcf02cSchristos attr->model_name_len);
8078dbcf02cSchristos }
8088dbcf02cSchristos
8098dbcf02cSchristos if (attr->model_number) {
8108dbcf02cSchristos os_free(sta->model_number);
81136d97821Schristos sta->model_number = dup_binstr(attr->model_number,
8128dbcf02cSchristos attr->model_number_len);
8138dbcf02cSchristos }
8148dbcf02cSchristos
8158dbcf02cSchristos if (attr->serial_number) {
8168dbcf02cSchristos os_free(sta->serial_number);
81736d97821Schristos sta->serial_number = dup_binstr(attr->serial_number,
8188dbcf02cSchristos attr->serial_number_len);
8198dbcf02cSchristos }
8208dbcf02cSchristos
8218dbcf02cSchristos if (attr->dev_name) {
8228dbcf02cSchristos os_free(sta->dev_name);
82336d97821Schristos sta->dev_name = dup_binstr(attr->dev_name, attr->dev_name_len);
8248dbcf02cSchristos }
8258dbcf02cSchristos
8268dbcf02cSchristos eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL);
8278dbcf02cSchristos eloop_register_timeout(300, 0, wps_er_sta_timeout, sta, NULL);
8288dbcf02cSchristos
8298dbcf02cSchristos if (m1 || new_sta)
8308dbcf02cSchristos wps_er_sta_event(ap->er->wps, sta, WPS_EV_ER_ENROLLEE_ADD);
8318dbcf02cSchristos
8328dbcf02cSchristos return sta;
8338dbcf02cSchristos }
8348dbcf02cSchristos
8358dbcf02cSchristos
wps_er_process_wlanevent_probe_req(struct wps_er_ap * ap,const u8 * addr,struct wpabuf * msg)8368dbcf02cSchristos static void wps_er_process_wlanevent_probe_req(struct wps_er_ap *ap,
8378dbcf02cSchristos const u8 *addr,
8388dbcf02cSchristos struct wpabuf *msg)
8398dbcf02cSchristos {
8408dbcf02cSchristos struct wps_parse_attr attr;
8418dbcf02cSchristos
8428dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: WLANEvent - Probe Request - from "
8438dbcf02cSchristos MACSTR, MAC2STR(addr));
8448dbcf02cSchristos wpa_hexdump_buf(MSG_MSGDUMP, "WPS ER: WLANEvent - Enrollee's message "
8458dbcf02cSchristos "(TLVs from Probe Request)", msg);
8468dbcf02cSchristos
84742669be3Schristos if (wps_validate_probe_req(msg, addr) < 0) {
84842669be3Schristos wpa_printf(MSG_INFO, "WPS-STRICT: ER: Ignore invalid proxied "
84942669be3Schristos "Probe Request frame from " MACSTR, MAC2STR(addr));
85042669be3Schristos return;
85142669be3Schristos }
85242669be3Schristos
8538dbcf02cSchristos if (wps_parse_msg(msg, &attr) < 0) {
8548dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse TLVs in "
8558dbcf02cSchristos "WLANEvent message");
8568dbcf02cSchristos return;
8578dbcf02cSchristos }
8588dbcf02cSchristos
8598dbcf02cSchristos wps_er_add_sta_data(ap, addr, &attr, 1);
86042669be3Schristos wps_registrar_probe_req_rx(ap->er->wps->registrar, addr, msg, 0);
8618dbcf02cSchristos }
8628dbcf02cSchristos
8638dbcf02cSchristos
wps_er_http_put_wlan_response_cb(void * ctx,struct http_client * c,enum http_client_event event)8648dbcf02cSchristos static void wps_er_http_put_wlan_response_cb(void *ctx, struct http_client *c,
8658dbcf02cSchristos enum http_client_event event)
8668dbcf02cSchristos {
8678dbcf02cSchristos struct wps_er_sta *sta = ctx;
8688dbcf02cSchristos
8698dbcf02cSchristos switch (event) {
8708dbcf02cSchristos case HTTP_CLIENT_OK:
8718dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: PutWLANResponse OK");
8728dbcf02cSchristos break;
8738dbcf02cSchristos case HTTP_CLIENT_FAILED:
8748dbcf02cSchristos case HTTP_CLIENT_INVALID_REPLY:
8758dbcf02cSchristos case HTTP_CLIENT_TIMEOUT:
8768dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: PutWLANResponse failed");
8778dbcf02cSchristos break;
8788dbcf02cSchristos }
8798dbcf02cSchristos http_client_free(sta->http);
8808dbcf02cSchristos sta->http = NULL;
8818dbcf02cSchristos }
8828dbcf02cSchristos
8838dbcf02cSchristos
8848dbcf02cSchristos static const char *soap_prefix =
8858dbcf02cSchristos "<?xml version=\"1.0\"?>\n"
8868dbcf02cSchristos "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
8878dbcf02cSchristos "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
8888dbcf02cSchristos "<s:Body>\n";
8898dbcf02cSchristos static const char *soap_postfix =
8908dbcf02cSchristos "</s:Body>\n</s:Envelope>\n";
8918dbcf02cSchristos static const char *urn_wfawlanconfig =
8928dbcf02cSchristos "urn:schemas-wifialliance-org:service:WFAWLANConfig:1";
8938dbcf02cSchristos
wps_er_soap_hdr(const struct wpabuf * msg,const char * name,const char * arg_name,const char * path,const struct sockaddr_in * dst,char ** len_ptr,char ** body_ptr)8948dbcf02cSchristos static struct wpabuf * wps_er_soap_hdr(const struct wpabuf *msg,
8958dbcf02cSchristos const char *name, const char *arg_name,
8968dbcf02cSchristos const char *path,
8978dbcf02cSchristos const struct sockaddr_in *dst,
8988dbcf02cSchristos char **len_ptr, char **body_ptr)
8998dbcf02cSchristos {
9008dbcf02cSchristos unsigned char *encoded;
9018dbcf02cSchristos size_t encoded_len;
9028dbcf02cSchristos struct wpabuf *buf;
9038dbcf02cSchristos
9048dbcf02cSchristos if (msg) {
9058dbcf02cSchristos encoded = base64_encode(wpabuf_head(msg), wpabuf_len(msg),
9068dbcf02cSchristos &encoded_len);
9078dbcf02cSchristos if (encoded == NULL)
9088dbcf02cSchristos return NULL;
9098dbcf02cSchristos } else {
9108dbcf02cSchristos encoded = NULL;
9118dbcf02cSchristos encoded_len = 0;
9128dbcf02cSchristos }
9138dbcf02cSchristos
9148dbcf02cSchristos buf = wpabuf_alloc(1000 + encoded_len);
9158dbcf02cSchristos if (buf == NULL) {
9168dbcf02cSchristos os_free(encoded);
9178dbcf02cSchristos return NULL;
9188dbcf02cSchristos }
9198dbcf02cSchristos
9208dbcf02cSchristos wpabuf_printf(buf,
9218dbcf02cSchristos "POST %s HTTP/1.1\r\n"
9228dbcf02cSchristos "Host: %s:%d\r\n"
9238dbcf02cSchristos "Content-Type: text/xml; charset=\"utf-8\"\r\n"
9248dbcf02cSchristos "Content-Length: ",
9258dbcf02cSchristos path, inet_ntoa(dst->sin_addr), ntohs(dst->sin_port));
9268dbcf02cSchristos
9278dbcf02cSchristos *len_ptr = wpabuf_put(buf, 0);
9288dbcf02cSchristos wpabuf_printf(buf,
9298dbcf02cSchristos " \r\n"
9308dbcf02cSchristos "SOAPACTION: \"%s#%s\"\r\n"
9318dbcf02cSchristos "\r\n",
9328dbcf02cSchristos urn_wfawlanconfig, name);
9338dbcf02cSchristos
9348dbcf02cSchristos *body_ptr = wpabuf_put(buf, 0);
9358dbcf02cSchristos
9368dbcf02cSchristos wpabuf_put_str(buf, soap_prefix);
9378dbcf02cSchristos wpabuf_printf(buf, "<u:%s xmlns:u=\"", name);
9388dbcf02cSchristos wpabuf_put_str(buf, urn_wfawlanconfig);
9398dbcf02cSchristos wpabuf_put_str(buf, "\">\n");
9408dbcf02cSchristos if (encoded) {
9418dbcf02cSchristos wpabuf_printf(buf, "<%s>%s</%s>\n",
9428dbcf02cSchristos arg_name, (char *) encoded, arg_name);
9438dbcf02cSchristos os_free(encoded);
9448dbcf02cSchristos }
9458dbcf02cSchristos
9468dbcf02cSchristos return buf;
9478dbcf02cSchristos }
9488dbcf02cSchristos
9498dbcf02cSchristos
wps_er_soap_end(struct wpabuf * buf,const char * name,char * len_ptr,char * body_ptr)9508dbcf02cSchristos static void wps_er_soap_end(struct wpabuf *buf, const char *name,
9518dbcf02cSchristos char *len_ptr, char *body_ptr)
9528dbcf02cSchristos {
9538dbcf02cSchristos char len_buf[10];
9548dbcf02cSchristos wpabuf_printf(buf, "</u:%s>\n", name);
9558dbcf02cSchristos wpabuf_put_str(buf, soap_postfix);
9568dbcf02cSchristos os_snprintf(len_buf, sizeof(len_buf), "%d",
9578dbcf02cSchristos (int) ((char *) wpabuf_put(buf, 0) - body_ptr));
9588dbcf02cSchristos os_memcpy(len_ptr, len_buf, os_strlen(len_buf));
9598dbcf02cSchristos }
9608dbcf02cSchristos
9618dbcf02cSchristos
wps_er_sta_send_msg(struct wps_er_sta * sta,struct wpabuf * msg)9628dbcf02cSchristos static void wps_er_sta_send_msg(struct wps_er_sta *sta, struct wpabuf *msg)
9638dbcf02cSchristos {
9648dbcf02cSchristos struct wpabuf *buf;
9658dbcf02cSchristos char *len_ptr, *body_ptr;
9668dbcf02cSchristos struct sockaddr_in dst;
9678dbcf02cSchristos char *url, *path;
9688dbcf02cSchristos
9698dbcf02cSchristos if (sta->http) {
9708dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request for STA - "
9718dbcf02cSchristos "ignore new request");
9728dbcf02cSchristos wpabuf_free(msg);
9738dbcf02cSchristos return;
9748dbcf02cSchristos }
9758dbcf02cSchristos
9768dbcf02cSchristos if (sta->ap->control_url == NULL) {
9778dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
9788dbcf02cSchristos wpabuf_free(msg);
9798dbcf02cSchristos return;
9808dbcf02cSchristos }
9818dbcf02cSchristos
9828dbcf02cSchristos url = http_client_url_parse(sta->ap->control_url, &dst, &path);
9838dbcf02cSchristos if (url == NULL) {
9848dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
9858dbcf02cSchristos wpabuf_free(msg);
9868dbcf02cSchristos return;
9878dbcf02cSchristos }
9888dbcf02cSchristos
9898dbcf02cSchristos buf = wps_er_soap_hdr(msg, "PutWLANResponse", "NewMessage", path, &dst,
9908dbcf02cSchristos &len_ptr, &body_ptr);
9918dbcf02cSchristos wpabuf_free(msg);
9928dbcf02cSchristos os_free(url);
9938dbcf02cSchristos if (buf == NULL)
9948dbcf02cSchristos return;
9958dbcf02cSchristos wpabuf_printf(buf, "<NewWLANEventType>%d</NewWLANEventType>\n",
9968dbcf02cSchristos UPNP_WPS_WLANEVENT_TYPE_EAP);
9978dbcf02cSchristos wpabuf_printf(buf, "<NewWLANEventMAC>" MACSTR "</NewWLANEventMAC>\n",
9988dbcf02cSchristos MAC2STR(sta->addr));
9998dbcf02cSchristos
10008dbcf02cSchristos wps_er_soap_end(buf, "PutWLANResponse", len_ptr, body_ptr);
10018dbcf02cSchristos
10028dbcf02cSchristos sta->http = http_client_addr(&dst, buf, 1000,
10038dbcf02cSchristos wps_er_http_put_wlan_response_cb, sta);
10048dbcf02cSchristos if (sta->http == NULL)
10058dbcf02cSchristos wpabuf_free(buf);
10068dbcf02cSchristos }
10078dbcf02cSchristos
10088dbcf02cSchristos
wps_er_sta_process(struct wps_er_sta * sta,struct wpabuf * msg,enum wsc_op_code op_code)10098dbcf02cSchristos static void wps_er_sta_process(struct wps_er_sta *sta, struct wpabuf *msg,
10108dbcf02cSchristos enum wsc_op_code op_code)
10118dbcf02cSchristos {
10128dbcf02cSchristos enum wps_process_res res;
10138dbcf02cSchristos
10148dbcf02cSchristos res = wps_process_msg(sta->wps, op_code, msg);
10158dbcf02cSchristos if (res == WPS_CONTINUE) {
10168dbcf02cSchristos struct wpabuf *next = wps_get_msg(sta->wps, &op_code);
10178dbcf02cSchristos if (next)
10188dbcf02cSchristos wps_er_sta_send_msg(sta, next);
10198dbcf02cSchristos } else {
10208dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Protocol run %s with the "
10218dbcf02cSchristos "enrollee (res=%d)",
10228dbcf02cSchristos res == WPS_DONE ? "succeeded" : "failed", res);
10238dbcf02cSchristos wps_deinit(sta->wps);
10248dbcf02cSchristos sta->wps = NULL;
10258dbcf02cSchristos if (res == WPS_DONE) {
10268dbcf02cSchristos /* Remove the STA entry after short timeout */
10278dbcf02cSchristos eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL);
10288dbcf02cSchristos eloop_register_timeout(10, 0, wps_er_sta_timeout, sta,
10298dbcf02cSchristos NULL);
10308dbcf02cSchristos }
10318dbcf02cSchristos }
10328dbcf02cSchristos }
10338dbcf02cSchristos
10348dbcf02cSchristos
wps_er_sta_start(struct wps_er_sta * sta,struct wpabuf * msg)10358dbcf02cSchristos static void wps_er_sta_start(struct wps_er_sta *sta, struct wpabuf *msg)
10368dbcf02cSchristos {
10378dbcf02cSchristos struct wps_config cfg;
10388dbcf02cSchristos
10398dbcf02cSchristos if (sta->wps)
10408dbcf02cSchristos wps_deinit(sta->wps);
10418dbcf02cSchristos
10428dbcf02cSchristos os_memset(&cfg, 0, sizeof(cfg));
10438dbcf02cSchristos cfg.wps = sta->ap->er->wps;
10448dbcf02cSchristos cfg.registrar = 1;
10458dbcf02cSchristos cfg.peer_addr = sta->addr;
10468dbcf02cSchristos
10478dbcf02cSchristos sta->wps = wps_init(&cfg);
10488dbcf02cSchristos if (sta->wps == NULL)
10498dbcf02cSchristos return;
10508dbcf02cSchristos sta->wps->er = 1;
10518dbcf02cSchristos sta->wps->use_cred = sta->ap->ap_settings;
10521b7205bfSchristos if (sta->ap->ap_settings) {
10531b7205bfSchristos os_free(sta->cred);
10541b7205bfSchristos sta->cred = os_malloc(sizeof(*sta->cred));
10551b7205bfSchristos if (sta->cred) {
10561b7205bfSchristos os_memcpy(sta->cred, sta->ap->ap_settings,
10571b7205bfSchristos sizeof(*sta->cred));
10581b7205bfSchristos sta->cred->cred_attr = NULL;
10591b7205bfSchristos os_memcpy(sta->cred->mac_addr, sta->addr, ETH_ALEN);
10601b7205bfSchristos sta->wps->use_cred = sta->cred;
10611b7205bfSchristos }
10621b7205bfSchristos }
10638dbcf02cSchristos
10648dbcf02cSchristos wps_er_sta_process(sta, msg, WSC_MSG);
10658dbcf02cSchristos }
10668dbcf02cSchristos
10678dbcf02cSchristos
wps_er_process_wlanevent_eap(struct wps_er_ap * ap,const u8 * addr,struct wpabuf * msg)10688dbcf02cSchristos static void wps_er_process_wlanevent_eap(struct wps_er_ap *ap, const u8 *addr,
10698dbcf02cSchristos struct wpabuf *msg)
10708dbcf02cSchristos {
10718dbcf02cSchristos struct wps_parse_attr attr;
10728dbcf02cSchristos struct wps_er_sta *sta;
10738dbcf02cSchristos
10748dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: WLANEvent - EAP - from " MACSTR,
10758dbcf02cSchristos MAC2STR(addr));
10768dbcf02cSchristos wpa_hexdump_buf(MSG_MSGDUMP, "WPS ER: WLANEvent - Enrollee's message "
10778dbcf02cSchristos "(TLVs from EAP-WSC)", msg);
10788dbcf02cSchristos
10798dbcf02cSchristos if (wps_parse_msg(msg, &attr) < 0) {
10808dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse TLVs in "
10818dbcf02cSchristos "WLANEvent message");
10828dbcf02cSchristos return;
10838dbcf02cSchristos }
10848dbcf02cSchristos
10858dbcf02cSchristos sta = wps_er_add_sta_data(ap, addr, &attr, 0);
10868dbcf02cSchristos if (sta == NULL)
10878dbcf02cSchristos return;
10888dbcf02cSchristos
10898dbcf02cSchristos if (attr.msg_type && *attr.msg_type == WPS_M1)
10908dbcf02cSchristos wps_er_sta_start(sta, msg);
10918dbcf02cSchristos else if (sta->wps) {
10928dbcf02cSchristos enum wsc_op_code op_code = WSC_MSG;
10938dbcf02cSchristos if (attr.msg_type) {
10948dbcf02cSchristos switch (*attr.msg_type) {
10958dbcf02cSchristos case WPS_WSC_ACK:
10968dbcf02cSchristos op_code = WSC_ACK;
10978dbcf02cSchristos break;
10988dbcf02cSchristos case WPS_WSC_NACK:
10998dbcf02cSchristos op_code = WSC_NACK;
11008dbcf02cSchristos break;
11018dbcf02cSchristos case WPS_WSC_DONE:
11028dbcf02cSchristos op_code = WSC_Done;
11038dbcf02cSchristos break;
11048dbcf02cSchristos }
11058dbcf02cSchristos }
11068dbcf02cSchristos wps_er_sta_process(sta, msg, op_code);
11078dbcf02cSchristos }
11088dbcf02cSchristos }
11098dbcf02cSchristos
11108dbcf02cSchristos
wps_er_process_wlanevent(struct wps_er_ap * ap,struct wpabuf * event)11118dbcf02cSchristos static void wps_er_process_wlanevent(struct wps_er_ap *ap,
11128dbcf02cSchristos struct wpabuf *event)
11138dbcf02cSchristos {
11148dbcf02cSchristos u8 *data;
11158dbcf02cSchristos u8 wlan_event_type;
11168dbcf02cSchristos u8 wlan_event_mac[ETH_ALEN];
11178dbcf02cSchristos struct wpabuf msg;
11188dbcf02cSchristos
11198dbcf02cSchristos wpa_hexdump(MSG_MSGDUMP, "WPS ER: Received WLANEvent",
11208dbcf02cSchristos wpabuf_head(event), wpabuf_len(event));
11218dbcf02cSchristos if (wpabuf_len(event) < 1 + 17) {
11228dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Too short WLANEvent");
11238dbcf02cSchristos return;
11248dbcf02cSchristos }
11258dbcf02cSchristos
11268dbcf02cSchristos data = wpabuf_mhead(event);
11278dbcf02cSchristos wlan_event_type = data[0];
11288dbcf02cSchristos if (hwaddr_aton((char *) data + 1, wlan_event_mac) < 0) {
11298dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Invalid WLANEventMAC in "
11308dbcf02cSchristos "WLANEvent");
11318dbcf02cSchristos return;
11328dbcf02cSchristos }
11338dbcf02cSchristos
11348dbcf02cSchristos wpabuf_set(&msg, data + 1 + 17, wpabuf_len(event) - (1 + 17));
11358dbcf02cSchristos
11368dbcf02cSchristos switch (wlan_event_type) {
11378dbcf02cSchristos case 1:
11388dbcf02cSchristos wps_er_process_wlanevent_probe_req(ap, wlan_event_mac, &msg);
11398dbcf02cSchristos break;
11408dbcf02cSchristos case 2:
11418dbcf02cSchristos wps_er_process_wlanevent_eap(ap, wlan_event_mac, &msg);
11428dbcf02cSchristos break;
11438dbcf02cSchristos default:
11448dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Unknown WLANEventType %d",
11458dbcf02cSchristos wlan_event_type);
11468dbcf02cSchristos break;
11478dbcf02cSchristos }
11488dbcf02cSchristos }
11498dbcf02cSchristos
11508dbcf02cSchristos
wps_er_http_event(struct wps_er * er,struct http_request * req,unsigned int ap_id)11518dbcf02cSchristos static void wps_er_http_event(struct wps_er *er, struct http_request *req,
11528dbcf02cSchristos unsigned int ap_id)
11538dbcf02cSchristos {
11548dbcf02cSchristos struct wps_er_ap *ap = wps_er_ap_get_id(er, ap_id);
11558dbcf02cSchristos struct wpabuf *event;
11568dbcf02cSchristos enum http_reply_code ret;
11578dbcf02cSchristos
11588dbcf02cSchristos if (ap == NULL) {
11598dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: HTTP event from unknown AP id "
11608dbcf02cSchristos "%u", ap_id);
11618dbcf02cSchristos wps_er_http_resp_not_found(req);
11628dbcf02cSchristos return;
11638dbcf02cSchristos }
11648dbcf02cSchristos wpa_printf(MSG_MSGDUMP, "WPS ER: HTTP event from AP id %u: %s",
11658dbcf02cSchristos ap_id, http_request_get_data(req));
11668dbcf02cSchristos
11678dbcf02cSchristos event = xml_get_base64_item(http_request_get_data(req), "WLANEvent",
11688dbcf02cSchristos &ret);
11698dbcf02cSchristos if (event == NULL) {
11708dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Could not extract WLANEvent "
11718dbcf02cSchristos "from the event notification");
11728dbcf02cSchristos /*
11738dbcf02cSchristos * Reply with OK anyway to avoid getting unregistered from
11748dbcf02cSchristos * events.
11758dbcf02cSchristos */
11768dbcf02cSchristos wps_er_http_resp_ok(req);
11778dbcf02cSchristos return;
11788dbcf02cSchristos }
11798dbcf02cSchristos
11808dbcf02cSchristos wps_er_process_wlanevent(ap, event);
11818dbcf02cSchristos
11828dbcf02cSchristos wpabuf_free(event);
11838dbcf02cSchristos wps_er_http_resp_ok(req);
11848dbcf02cSchristos }
11858dbcf02cSchristos
11868dbcf02cSchristos
wps_er_http_notify(struct wps_er * er,struct http_request * req)11878dbcf02cSchristos static void wps_er_http_notify(struct wps_er *er, struct http_request *req)
11888dbcf02cSchristos {
11898dbcf02cSchristos char *uri = http_request_get_uri(req);
11908dbcf02cSchristos
11918dbcf02cSchristos if (os_strncmp(uri, "/event/", 7) == 0) {
11928dbcf02cSchristos unsigned int event_id;
11938dbcf02cSchristos char *pos;
11948dbcf02cSchristos event_id = atoi(uri + 7);
11958dbcf02cSchristos if (event_id != er->event_id) {
11968dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: HTTP event for an "
11978dbcf02cSchristos "unknown event id %u", event_id);
11988dbcf02cSchristos return;
11998dbcf02cSchristos }
12008dbcf02cSchristos pos = os_strchr(uri + 7, '/');
12018dbcf02cSchristos if (pos == NULL)
12028dbcf02cSchristos return;
12038dbcf02cSchristos pos++;
12048dbcf02cSchristos wps_er_http_event(er, req, atoi(pos));
12058dbcf02cSchristos } else {
12068dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Unknown HTTP NOTIFY for '%s'",
12078dbcf02cSchristos uri);
12088dbcf02cSchristos wps_er_http_resp_not_found(req);
12098dbcf02cSchristos }
12108dbcf02cSchristos }
12118dbcf02cSchristos
12128dbcf02cSchristos
wps_er_http_req(void * ctx,struct http_request * req)12138dbcf02cSchristos static void wps_er_http_req(void *ctx, struct http_request *req)
12148dbcf02cSchristos {
12158dbcf02cSchristos struct wps_er *er = ctx;
12168dbcf02cSchristos struct sockaddr_in *cli = http_request_get_cli_addr(req);
12178dbcf02cSchristos enum httpread_hdr_type type = http_request_get_type(req);
12188dbcf02cSchristos struct wpabuf *buf;
12198dbcf02cSchristos
12208dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: HTTP request: '%s' (type %d) from "
12218dbcf02cSchristos "%s:%d",
12228dbcf02cSchristos http_request_get_uri(req), type,
12238dbcf02cSchristos inet_ntoa(cli->sin_addr), ntohs(cli->sin_port));
12248dbcf02cSchristos
12258dbcf02cSchristos switch (type) {
12268dbcf02cSchristos case HTTPREAD_HDR_TYPE_NOTIFY:
12278dbcf02cSchristos wps_er_http_notify(er, req);
12288dbcf02cSchristos break;
12298dbcf02cSchristos default:
12308dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Unsupported HTTP request type "
12318dbcf02cSchristos "%d", type);
12328dbcf02cSchristos buf = wpabuf_alloc(200);
12338dbcf02cSchristos if (buf == NULL) {
12348dbcf02cSchristos http_request_deinit(req);
12358dbcf02cSchristos return;
12368dbcf02cSchristos }
12378dbcf02cSchristos wpabuf_put_str(buf,
12388dbcf02cSchristos "HTTP/1.1 501 Unimplemented\r\n"
12398dbcf02cSchristos "Connection: close\r\n");
12408dbcf02cSchristos http_put_date(buf);
12418dbcf02cSchristos wpabuf_put_str(buf, "\r\n");
12428dbcf02cSchristos http_request_send_and_deinit(req, buf);
12438dbcf02cSchristos break;
12448dbcf02cSchristos }
12458dbcf02cSchristos }
12468dbcf02cSchristos
12478dbcf02cSchristos
12488dbcf02cSchristos struct wps_er *
wps_er_init(struct wps_context * wps,const char * ifname,const char * filter)124942669be3Schristos wps_er_init(struct wps_context *wps, const char *ifname, const char *filter)
12508dbcf02cSchristos {
12518dbcf02cSchristos struct wps_er *er;
12528dbcf02cSchristos struct in_addr addr;
12538dbcf02cSchristos
12548dbcf02cSchristos er = os_zalloc(sizeof(*er));
12558dbcf02cSchristos if (er == NULL)
12568dbcf02cSchristos return NULL;
12578dbcf02cSchristos dl_list_init(&er->ap);
12588dbcf02cSchristos dl_list_init(&er->ap_unsubscribing);
125942669be3Schristos dl_list_init(&er->ap_settings);
12608dbcf02cSchristos
12618dbcf02cSchristos er->multicast_sd = -1;
12628dbcf02cSchristos er->ssdp_sd = -1;
12638dbcf02cSchristos
12648dbcf02cSchristos os_strlcpy(er->ifname, ifname, sizeof(er->ifname));
12658dbcf02cSchristos er->wps = wps;
12668dbcf02cSchristos if (os_get_random((unsigned char *) &er->event_id,
12678dbcf02cSchristos sizeof(er->event_id)) < 0) {
12688dbcf02cSchristos wps_er_deinit(er, NULL, NULL);
12698dbcf02cSchristos return NULL;
12708dbcf02cSchristos }
12711b7205bfSchristos /* Limit event_id to < 32 bits to avoid issues with atoi() */
12721b7205bfSchristos er->event_id &= 0x0fffffff;
12738dbcf02cSchristos
127436d97821Schristos if (filter && os_strncmp(filter, "ifname=", 7) == 0) {
127536d97821Schristos const char *pos, *end;
127636d97821Schristos pos = filter + 7;
127736d97821Schristos end = os_strchr(pos, ' ');
127836d97821Schristos if (end) {
127936d97821Schristos size_t len = end - pos;
128036d97821Schristos os_strlcpy(er->ifname, pos, len < sizeof(er->ifname) ?
128136d97821Schristos len + 1 : sizeof(er->ifname));
128236d97821Schristos filter = end + 1;
128336d97821Schristos } else {
128436d97821Schristos os_strlcpy(er->ifname, pos, sizeof(er->ifname));
128536d97821Schristos filter = NULL;
128636d97821Schristos }
128736d97821Schristos er->forced_ifname = 1;
128836d97821Schristos }
128936d97821Schristos
129042669be3Schristos if (filter) {
129142669be3Schristos if (inet_aton(filter, &er->filter_addr) == 0) {
129242669be3Schristos wpa_printf(MSG_INFO, "WPS UPnP: Invalid filter "
129342669be3Schristos "address %s", filter);
129442669be3Schristos wps_er_deinit(er, NULL, NULL);
129542669be3Schristos return NULL;
129642669be3Schristos }
129742669be3Schristos wpa_printf(MSG_DEBUG, "WPS UPnP: Only accepting connections "
129842669be3Schristos "with %s", filter);
129942669be3Schristos }
130036d97821Schristos if (get_netif_info(er->ifname, &er->ip_addr, &er->ip_addr_text,
13018dbcf02cSchristos er->mac_addr)) {
13028dbcf02cSchristos wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address "
130336d97821Schristos "for %s. Does it have IP address?", er->ifname);
13048dbcf02cSchristos wps_er_deinit(er, NULL, NULL);
13058dbcf02cSchristos return NULL;
13068dbcf02cSchristos }
13078dbcf02cSchristos
13088dbcf02cSchristos if (wps_er_ssdp_init(er) < 0) {
130942669be3Schristos wpa_printf(MSG_INFO, "WPS UPnP: SSDP initialization failed");
13108dbcf02cSchristos wps_er_deinit(er, NULL, NULL);
13118dbcf02cSchristos return NULL;
13128dbcf02cSchristos }
13138dbcf02cSchristos
13148dbcf02cSchristos addr.s_addr = er->ip_addr;
13158dbcf02cSchristos er->http_srv = http_server_init(&addr, -1, wps_er_http_req, er);
13168dbcf02cSchristos if (er->http_srv == NULL) {
131742669be3Schristos wpa_printf(MSG_INFO, "WPS UPnP: HTTP initialization failed");
13188dbcf02cSchristos wps_er_deinit(er, NULL, NULL);
13198dbcf02cSchristos return NULL;
13208dbcf02cSchristos }
13218dbcf02cSchristos er->http_port = http_server_get_port(er->http_srv);
13228dbcf02cSchristos
13238dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Start (ifname=%s ip_addr=%s)",
13248dbcf02cSchristos er->ifname, er->ip_addr_text);
13258dbcf02cSchristos
13268dbcf02cSchristos return er;
13278dbcf02cSchristos }
13288dbcf02cSchristos
13298dbcf02cSchristos
wps_er_refresh(struct wps_er * er)13308dbcf02cSchristos void wps_er_refresh(struct wps_er *er)
13318dbcf02cSchristos {
13328dbcf02cSchristos struct wps_er_ap *ap;
13338dbcf02cSchristos struct wps_er_sta *sta;
13348dbcf02cSchristos
13358dbcf02cSchristos dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
13368dbcf02cSchristos wps_er_ap_event(er->wps, ap, WPS_EV_ER_AP_ADD);
13378dbcf02cSchristos dl_list_for_each(sta, &ap->sta, struct wps_er_sta, list)
13388dbcf02cSchristos wps_er_sta_event(er->wps, sta, WPS_EV_ER_ENROLLEE_ADD);
13398dbcf02cSchristos }
13408dbcf02cSchristos
13418dbcf02cSchristos wps_er_send_ssdp_msearch(er);
13428dbcf02cSchristos }
13438dbcf02cSchristos
13448dbcf02cSchristos
wps_er_deinit_finish(void * eloop_data,void * user_ctx)13458dbcf02cSchristos static void wps_er_deinit_finish(void *eloop_data, void *user_ctx)
13468dbcf02cSchristos {
13478dbcf02cSchristos struct wps_er *er = eloop_data;
13488dbcf02cSchristos void (*deinit_done_cb)(void *ctx);
13498dbcf02cSchristos void *deinit_done_ctx;
135036d97821Schristos struct wps_er_ap *ap, *tmp;
13518dbcf02cSchristos
13528dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Finishing deinit");
13538dbcf02cSchristos
135436d97821Schristos dl_list_for_each_safe(ap, tmp, &er->ap_unsubscribing, struct wps_er_ap,
135536d97821Schristos list) {
135636d97821Schristos wpa_printf(MSG_DEBUG, "WPS ER: AP entry for %s (%s) still in ap_unsubscribing list - free it",
135736d97821Schristos inet_ntoa(ap->addr), ap->location);
135836d97821Schristos dl_list_del(&ap->list);
135936d97821Schristos wps_er_ap_free(ap);
136036d97821Schristos }
136136d97821Schristos
136236d97821Schristos eloop_cancel_timeout(wps_er_deinit_finish, er, NULL);
13638dbcf02cSchristos deinit_done_cb = er->deinit_done_cb;
13648dbcf02cSchristos deinit_done_ctx = er->deinit_done_ctx;
13658dbcf02cSchristos os_free(er->ip_addr_text);
13668dbcf02cSchristos os_free(er);
13678dbcf02cSchristos
13688dbcf02cSchristos if (deinit_done_cb)
13698dbcf02cSchristos deinit_done_cb(deinit_done_ctx);
13708dbcf02cSchristos }
13718dbcf02cSchristos
13728dbcf02cSchristos
wps_er_deinit(struct wps_er * er,void (* cb)(void * ctx),void * ctx)13738dbcf02cSchristos void wps_er_deinit(struct wps_er *er, void (*cb)(void *ctx), void *ctx)
13748dbcf02cSchristos {
13758dbcf02cSchristos if (er == NULL)
13768dbcf02cSchristos return;
13778dbcf02cSchristos http_server_deinit(er->http_srv);
13788dbcf02cSchristos wps_er_ap_remove_all(er);
13798dbcf02cSchristos wps_er_ssdp_deinit(er);
13808dbcf02cSchristos eloop_register_timeout(dl_list_empty(&er->ap_unsubscribing) ? 0 : 5, 0,
13818dbcf02cSchristos wps_er_deinit_finish, er, NULL);
13828dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Finish deinit from timeout");
13838dbcf02cSchristos er->deinitializing = 1;
13848dbcf02cSchristos er->deinit_done_cb = cb;
13858dbcf02cSchristos er->deinit_done_ctx = ctx;
13868dbcf02cSchristos }
13878dbcf02cSchristos
13888dbcf02cSchristos
wps_er_http_set_sel_reg_cb(void * ctx,struct http_client * c,enum http_client_event event)13898dbcf02cSchristos static void wps_er_http_set_sel_reg_cb(void *ctx, struct http_client *c,
13908dbcf02cSchristos enum http_client_event event)
13918dbcf02cSchristos {
13928dbcf02cSchristos struct wps_er_ap *ap = ctx;
139342669be3Schristos union wps_event_data data;
139442669be3Schristos
139542669be3Schristos os_memset(&data, 0, sizeof(data));
13968dbcf02cSchristos
13978dbcf02cSchristos switch (event) {
13988dbcf02cSchristos case HTTP_CLIENT_OK:
13998dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar OK");
140042669be3Schristos data.set_sel_reg.state = WPS_ER_SET_SEL_REG_DONE;
140142669be3Schristos data.set_sel_reg.uuid = ap->uuid;
14028dbcf02cSchristos break;
14038dbcf02cSchristos case HTTP_CLIENT_FAILED:
14048dbcf02cSchristos case HTTP_CLIENT_INVALID_REPLY:
14058dbcf02cSchristos case HTTP_CLIENT_TIMEOUT:
14068dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar failed");
140742669be3Schristos data.set_sel_reg.state = WPS_ER_SET_SEL_REG_FAILED;
140842669be3Schristos data.set_sel_reg.uuid = ap->uuid;
14098dbcf02cSchristos break;
14108dbcf02cSchristos }
14118dbcf02cSchristos http_client_free(ap->http);
14128dbcf02cSchristos ap->http = NULL;
141342669be3Schristos
141442669be3Schristos if (data.set_sel_reg.uuid)
141542669be3Schristos ap->er->wps->event_cb(ap->er->wps->cb_ctx,
141642669be3Schristos WPS_EV_ER_SET_SELECTED_REGISTRAR, &data);
14178dbcf02cSchristos }
14188dbcf02cSchristos
14198dbcf02cSchristos
wps_er_send_set_sel_reg(struct wps_er_ap * ap,struct wpabuf * msg)14208dbcf02cSchristos static void wps_er_send_set_sel_reg(struct wps_er_ap *ap, struct wpabuf *msg)
14218dbcf02cSchristos {
14228dbcf02cSchristos struct wpabuf *buf;
14238dbcf02cSchristos char *len_ptr, *body_ptr;
14248dbcf02cSchristos struct sockaddr_in dst;
14258dbcf02cSchristos char *url, *path;
14268dbcf02cSchristos
14278dbcf02cSchristos if (ap->control_url == NULL) {
14288dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
14298dbcf02cSchristos return;
14308dbcf02cSchristos }
14318dbcf02cSchristos
14328dbcf02cSchristos if (ap->http) {
14338dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request for AP - "
14348dbcf02cSchristos "ignore new request");
14358dbcf02cSchristos return;
14368dbcf02cSchristos }
14378dbcf02cSchristos
143842669be3Schristos if (ap->wps) {
143942669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: Pending WPS operation for AP - "
144042669be3Schristos "skip SetSelectedRegistrar");
144142669be3Schristos return;
144242669be3Schristos }
144342669be3Schristos
14448dbcf02cSchristos url = http_client_url_parse(ap->control_url, &dst, &path);
14458dbcf02cSchristos if (url == NULL) {
14468dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
14478dbcf02cSchristos return;
14488dbcf02cSchristos }
14498dbcf02cSchristos
14508dbcf02cSchristos buf = wps_er_soap_hdr(msg, "SetSelectedRegistrar", "NewMessage", path,
14518dbcf02cSchristos &dst, &len_ptr, &body_ptr);
14528dbcf02cSchristos os_free(url);
14538dbcf02cSchristos if (buf == NULL)
14548dbcf02cSchristos return;
14558dbcf02cSchristos
14568dbcf02cSchristos wps_er_soap_end(buf, "SetSelectedRegistrar", len_ptr, body_ptr);
14578dbcf02cSchristos
14588dbcf02cSchristos ap->http = http_client_addr(&dst, buf, 1000,
14598dbcf02cSchristos wps_er_http_set_sel_reg_cb, ap);
14608dbcf02cSchristos if (ap->http == NULL)
14618dbcf02cSchristos wpabuf_free(buf);
14628dbcf02cSchristos }
14638dbcf02cSchristos
14648dbcf02cSchristos
wps_er_build_selected_registrar(struct wpabuf * msg,int sel_reg)14658dbcf02cSchristos static int wps_er_build_selected_registrar(struct wpabuf *msg, int sel_reg)
14668dbcf02cSchristos {
14678dbcf02cSchristos wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR);
14688dbcf02cSchristos wpabuf_put_be16(msg, 1);
14698dbcf02cSchristos wpabuf_put_u8(msg, !!sel_reg);
14708dbcf02cSchristos return 0;
14718dbcf02cSchristos }
14728dbcf02cSchristos
14738dbcf02cSchristos
wps_er_build_dev_password_id(struct wpabuf * msg,u16 dev_passwd_id)14748dbcf02cSchristos static int wps_er_build_dev_password_id(struct wpabuf *msg, u16 dev_passwd_id)
14758dbcf02cSchristos {
14768dbcf02cSchristos wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID);
14778dbcf02cSchristos wpabuf_put_be16(msg, 2);
14788dbcf02cSchristos wpabuf_put_be16(msg, dev_passwd_id);
14798dbcf02cSchristos return 0;
14808dbcf02cSchristos }
14818dbcf02cSchristos
14828dbcf02cSchristos
wps_er_build_sel_reg_config_methods(struct wpabuf * msg,u16 sel_reg_config_methods)14838dbcf02cSchristos static int wps_er_build_sel_reg_config_methods(struct wpabuf *msg,
14848dbcf02cSchristos u16 sel_reg_config_methods)
14858dbcf02cSchristos {
14868dbcf02cSchristos wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR_CONFIG_METHODS);
14878dbcf02cSchristos wpabuf_put_be16(msg, 2);
14888dbcf02cSchristos wpabuf_put_be16(msg, sel_reg_config_methods);
14898dbcf02cSchristos return 0;
14908dbcf02cSchristos }
14918dbcf02cSchristos
14928dbcf02cSchristos
wps_er_build_uuid_r(struct wpabuf * msg,const u8 * uuid_r)149342669be3Schristos static int wps_er_build_uuid_r(struct wpabuf *msg, const u8 *uuid_r)
149442669be3Schristos {
149542669be3Schristos wpabuf_put_be16(msg, ATTR_UUID_R);
149642669be3Schristos wpabuf_put_be16(msg, WPS_UUID_LEN);
149742669be3Schristos wpabuf_put_data(msg, uuid_r, WPS_UUID_LEN);
149842669be3Schristos return 0;
149942669be3Schristos }
150042669be3Schristos
150142669be3Schristos
wps_er_set_sel_reg(struct wps_er * er,int sel_reg,u16 dev_passwd_id,u16 sel_reg_config_methods)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;
150742669be3Schristos struct wps_registrar *reg = er->wps->registrar;
150842669be3Schristos const u8 *auth_macs;
150942669be3Schristos u8 bcast[ETH_ALEN];
151042669be3Schristos size_t count;
151142669be3Schristos union wps_event_data data;
151242669be3Schristos
151342669be3Schristos if (er->skip_set_sel_reg) {
151442669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: Skip SetSelectedRegistrar");
151542669be3Schristos return;
151642669be3Schristos }
15178dbcf02cSchristos
15188dbcf02cSchristos msg = wpabuf_alloc(500);
15198dbcf02cSchristos if (msg == NULL)
15208dbcf02cSchristos return;
15218dbcf02cSchristos
152242669be3Schristos auth_macs = wps_authorized_macs(reg, &count);
152342669be3Schristos if (count == 0) {
152442669be3Schristos os_memset(bcast, 0xff, ETH_ALEN);
152542669be3Schristos auth_macs = bcast;
152642669be3Schristos count = 1;
152742669be3Schristos }
152842669be3Schristos
15298dbcf02cSchristos if (wps_build_version(msg) ||
15308dbcf02cSchristos wps_er_build_selected_registrar(msg, sel_reg) ||
15318dbcf02cSchristos wps_er_build_dev_password_id(msg, dev_passwd_id) ||
153242669be3Schristos wps_er_build_sel_reg_config_methods(msg, sel_reg_config_methods) ||
1533*0d69f216Schristos wps_build_wfa_ext(msg, 0, auth_macs, count, 0) ||
153442669be3Schristos wps_er_build_uuid_r(msg, er->wps->uuid)) {
15358dbcf02cSchristos wpabuf_free(msg);
15368dbcf02cSchristos return;
15378dbcf02cSchristos }
15388dbcf02cSchristos
153942669be3Schristos os_memset(&data, 0, sizeof(data));
154042669be3Schristos data.set_sel_reg.sel_reg = sel_reg;
154142669be3Schristos data.set_sel_reg.dev_passwd_id = dev_passwd_id;
154242669be3Schristos data.set_sel_reg.sel_reg_config_methods = sel_reg_config_methods;
154342669be3Schristos data.set_sel_reg.state = WPS_ER_SET_SEL_REG_START;
154442669be3Schristos
154542669be3Schristos dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
154642669be3Schristos if (er->set_sel_reg_uuid_filter &&
154742669be3Schristos os_memcmp(ap->uuid, er->set_sel_reg_uuid_filter,
154842669be3Schristos WPS_UUID_LEN) != 0)
154942669be3Schristos continue;
155042669be3Schristos data.set_sel_reg.uuid = ap->uuid;
155142669be3Schristos er->wps->event_cb(er->wps->cb_ctx,
155242669be3Schristos WPS_EV_ER_SET_SELECTED_REGISTRAR, &data);
15538dbcf02cSchristos wps_er_send_set_sel_reg(ap, msg);
155442669be3Schristos }
15558dbcf02cSchristos
15568dbcf02cSchristos wpabuf_free(msg);
15578dbcf02cSchristos }
15588dbcf02cSchristos
15598dbcf02cSchristos
wps_er_pbc(struct wps_er * er,const u8 * uuid,const u8 * addr)156036d97821Schristos int wps_er_pbc(struct wps_er *er, const u8 *uuid, const u8 *addr)
15618dbcf02cSchristos {
156242669be3Schristos int res;
156342669be3Schristos struct wps_er_ap *ap;
156442669be3Schristos
15658dbcf02cSchristos if (er == NULL || er->wps == NULL)
15668dbcf02cSchristos return -1;
15678dbcf02cSchristos
156842669be3Schristos if (wps_registrar_pbc_overlap(er->wps->registrar, NULL, NULL)) {
156942669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: PBC overlap - do not start PBC "
157042669be3Schristos "mode");
157142669be3Schristos return -2;
157242669be3Schristos }
157342669be3Schristos
157436d97821Schristos if (uuid)
157536d97821Schristos ap = wps_er_ap_get(er, NULL, uuid, NULL);
157636d97821Schristos else
157736d97821Schristos ap = NULL;
157842669be3Schristos if (ap == NULL) {
157942669be3Schristos struct wps_er_sta *sta = NULL;
158042669be3Schristos dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
158136d97821Schristos sta = wps_er_sta_get(ap, addr, uuid);
158242669be3Schristos if (sta) {
158342669be3Schristos uuid = ap->uuid;
158442669be3Schristos break;
158542669be3Schristos }
158642669be3Schristos }
158742669be3Schristos if (sta == NULL)
158842669be3Schristos return -3; /* Unknown UUID */
158942669be3Schristos }
159042669be3Schristos
159142669be3Schristos if (ap->ap_settings == NULL) {
159242669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: AP settings not known");
159342669be3Schristos return -4;
159442669be3Schristos }
159542669be3Schristos
159642669be3Schristos er->set_sel_reg_uuid_filter = uuid;
159742669be3Schristos res = wps_registrar_button_pushed(er->wps->registrar, NULL);
159842669be3Schristos er->set_sel_reg_uuid_filter = NULL;
159942669be3Schristos if (res)
16008dbcf02cSchristos return -1;
16018dbcf02cSchristos
16028dbcf02cSchristos return 0;
16038dbcf02cSchristos }
16048dbcf02cSchristos
16058dbcf02cSchristos
wps_er_ap_settings_cb(void * ctx,const struct wps_credential * cred)16068dbcf02cSchristos static void wps_er_ap_settings_cb(void *ctx, const struct wps_credential *cred)
16078dbcf02cSchristos {
16088dbcf02cSchristos struct wps_er_ap *ap = ctx;
160942669be3Schristos union wps_event_data data;
161042669be3Schristos
16118dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: AP Settings received");
16128dbcf02cSchristos os_free(ap->ap_settings);
16138dbcf02cSchristos ap->ap_settings = os_malloc(sizeof(*cred));
16148dbcf02cSchristos if (ap->ap_settings) {
16158dbcf02cSchristos os_memcpy(ap->ap_settings, cred, sizeof(*cred));
16168dbcf02cSchristos ap->ap_settings->cred_attr = NULL;
16178dbcf02cSchristos }
16188dbcf02cSchristos
161942669be3Schristos os_memset(&data, 0, sizeof(data));
162042669be3Schristos data.ap_settings.uuid = ap->uuid;
162142669be3Schristos data.ap_settings.cred = cred;
162242669be3Schristos ap->er->wps->event_cb(ap->er->wps->cb_ctx, WPS_EV_ER_AP_SETTINGS,
162342669be3Schristos &data);
16248dbcf02cSchristos }
16258dbcf02cSchristos
16268dbcf02cSchristos
wps_er_get_sta_uuid(struct wps_er * er,const u8 * addr)162736d97821Schristos const u8 * wps_er_get_sta_uuid(struct wps_er *er, const u8 *addr)
162836d97821Schristos {
162936d97821Schristos struct wps_er_ap *ap;
163036d97821Schristos dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
163136d97821Schristos struct wps_er_sta *sta;
163236d97821Schristos sta = wps_er_sta_get(ap, addr, NULL);
163336d97821Schristos if (sta)
163436d97821Schristos return sta->uuid;
163536d97821Schristos }
163636d97821Schristos return NULL;
163736d97821Schristos }
163836d97821Schristos
163936d97821Schristos
wps_er_http_put_message_cb(void * ctx,struct http_client * c,enum http_client_event event)16408dbcf02cSchristos static void wps_er_http_put_message_cb(void *ctx, struct http_client *c,
16418dbcf02cSchristos enum http_client_event event)
16428dbcf02cSchristos {
16438dbcf02cSchristos struct wps_er_ap *ap = ctx;
16448dbcf02cSchristos struct wpabuf *reply;
16458dbcf02cSchristos char *msg = NULL;
16468dbcf02cSchristos
16478dbcf02cSchristos switch (event) {
16488dbcf02cSchristos case HTTP_CLIENT_OK:
16498dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: PutMessage OK");
16508dbcf02cSchristos reply = http_client_get_body(c);
1651928750b6Schristos if (reply)
16528dbcf02cSchristos msg = os_zalloc(wpabuf_len(reply) + 1);
1653928750b6Schristos if (msg == NULL) {
1654928750b6Schristos if (ap->wps) {
1655928750b6Schristos wps_deinit(ap->wps);
1656928750b6Schristos ap->wps = NULL;
1657928750b6Schristos }
16588dbcf02cSchristos break;
1659928750b6Schristos }
16608dbcf02cSchristos os_memcpy(msg, wpabuf_head(reply), wpabuf_len(reply));
16618dbcf02cSchristos break;
16628dbcf02cSchristos case HTTP_CLIENT_FAILED:
16638dbcf02cSchristos case HTTP_CLIENT_INVALID_REPLY:
16648dbcf02cSchristos case HTTP_CLIENT_TIMEOUT:
16658dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: PutMessage failed");
16668dbcf02cSchristos if (ap->wps) {
16678dbcf02cSchristos wps_deinit(ap->wps);
16688dbcf02cSchristos ap->wps = NULL;
16698dbcf02cSchristos }
16708dbcf02cSchristos break;
16718dbcf02cSchristos }
16728dbcf02cSchristos http_client_free(ap->http);
16738dbcf02cSchristos ap->http = NULL;
16748dbcf02cSchristos
16758dbcf02cSchristos if (msg) {
16768dbcf02cSchristos struct wpabuf *buf;
16778dbcf02cSchristos enum http_reply_code ret;
16788dbcf02cSchristos buf = xml_get_base64_item(msg, "NewOutMessage", &ret);
16798dbcf02cSchristos os_free(msg);
16808dbcf02cSchristos if (buf == NULL) {
16818dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Could not extract "
16828dbcf02cSchristos "NewOutMessage from PutMessage response");
168342669be3Schristos wps_deinit(ap->wps);
168442669be3Schristos ap->wps = NULL;
16858dbcf02cSchristos return;
16868dbcf02cSchristos }
16878dbcf02cSchristos wps_er_ap_process(ap, buf);
16888dbcf02cSchristos wpabuf_free(buf);
16898dbcf02cSchristos }
16908dbcf02cSchristos }
16918dbcf02cSchristos
16928dbcf02cSchristos
wps_er_ap_put_message(struct wps_er_ap * ap,const struct wpabuf * msg)16938dbcf02cSchristos static void wps_er_ap_put_message(struct wps_er_ap *ap,
16948dbcf02cSchristos const struct wpabuf *msg)
16958dbcf02cSchristos {
16968dbcf02cSchristos struct wpabuf *buf;
16978dbcf02cSchristos char *len_ptr, *body_ptr;
16988dbcf02cSchristos struct sockaddr_in dst;
16998dbcf02cSchristos char *url, *path;
17008dbcf02cSchristos
17018dbcf02cSchristos if (ap->http) {
17028dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP operation ongoing "
17038dbcf02cSchristos "with the AP - cannot continue learn");
17048dbcf02cSchristos return;
17058dbcf02cSchristos }
17068dbcf02cSchristos
17078dbcf02cSchristos if (ap->control_url == NULL) {
17088dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
17098dbcf02cSchristos return;
17108dbcf02cSchristos }
17118dbcf02cSchristos
17128dbcf02cSchristos url = http_client_url_parse(ap->control_url, &dst, &path);
17138dbcf02cSchristos if (url == NULL) {
17148dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
1715928750b6Schristos goto fail;
17168dbcf02cSchristos }
17178dbcf02cSchristos
17188dbcf02cSchristos buf = wps_er_soap_hdr(msg, "PutMessage", "NewInMessage", path, &dst,
17198dbcf02cSchristos &len_ptr, &body_ptr);
17208dbcf02cSchristos os_free(url);
17218dbcf02cSchristos if (buf == NULL)
1722928750b6Schristos goto fail;
17238dbcf02cSchristos
17248dbcf02cSchristos wps_er_soap_end(buf, "PutMessage", len_ptr, body_ptr);
17258dbcf02cSchristos
17268dbcf02cSchristos ap->http = http_client_addr(&dst, buf, 10000,
17278dbcf02cSchristos wps_er_http_put_message_cb, ap);
1728928750b6Schristos if (ap->http == NULL) {
17298dbcf02cSchristos wpabuf_free(buf);
1730928750b6Schristos goto fail;
1731928750b6Schristos }
1732928750b6Schristos return;
1733928750b6Schristos
1734928750b6Schristos fail:
1735928750b6Schristos if (ap->wps) {
1736928750b6Schristos wps_deinit(ap->wps);
1737928750b6Schristos ap->wps = NULL;
1738928750b6Schristos }
17398dbcf02cSchristos }
17408dbcf02cSchristos
17418dbcf02cSchristos
wps_er_ap_process(struct wps_er_ap * ap,struct wpabuf * msg)17428dbcf02cSchristos static void wps_er_ap_process(struct wps_er_ap *ap, struct wpabuf *msg)
17438dbcf02cSchristos {
17448dbcf02cSchristos enum wps_process_res res;
174542669be3Schristos struct wps_parse_attr attr;
17468dbcf02cSchristos enum wsc_op_code op_code;
174742669be3Schristos
174842669be3Schristos op_code = WSC_MSG;
174942669be3Schristos if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type) {
175042669be3Schristos switch (*attr.msg_type) {
175142669be3Schristos case WPS_WSC_ACK:
175242669be3Schristos op_code = WSC_ACK;
175342669be3Schristos break;
175442669be3Schristos case WPS_WSC_NACK:
175542669be3Schristos op_code = WSC_NACK;
175642669be3Schristos break;
175742669be3Schristos case WPS_WSC_DONE:
175842669be3Schristos op_code = WSC_Done;
175942669be3Schristos break;
176042669be3Schristos }
176142669be3Schristos }
176242669be3Schristos
176342669be3Schristos res = wps_process_msg(ap->wps, op_code, msg);
176442669be3Schristos if (res == WPS_CONTINUE) {
17658dbcf02cSchristos struct wpabuf *next = wps_get_msg(ap->wps, &op_code);
17668dbcf02cSchristos if (next) {
17678dbcf02cSchristos wps_er_ap_put_message(ap, next);
17688dbcf02cSchristos wpabuf_free(next);
17698dbcf02cSchristos } else {
17708dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to build "
17718dbcf02cSchristos "message");
17728dbcf02cSchristos wps_deinit(ap->wps);
17738dbcf02cSchristos ap->wps = NULL;
17748dbcf02cSchristos }
177542669be3Schristos } else if (res == WPS_DONE) {
177642669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: Protocol run done");
177742669be3Schristos wps_deinit(ap->wps);
177842669be3Schristos ap->wps = NULL;
17798dbcf02cSchristos } else {
17808dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to process message from "
17818dbcf02cSchristos "AP (res=%d)", res);
17828dbcf02cSchristos wps_deinit(ap->wps);
17838dbcf02cSchristos ap->wps = NULL;
17848dbcf02cSchristos }
17858dbcf02cSchristos }
17868dbcf02cSchristos
17878dbcf02cSchristos
wps_er_ap_learn_m1(struct wps_er_ap * ap,struct wpabuf * m1)17888dbcf02cSchristos static void wps_er_ap_learn_m1(struct wps_er_ap *ap, struct wpabuf *m1)
17898dbcf02cSchristos {
17908dbcf02cSchristos struct wps_config cfg;
17918dbcf02cSchristos
17928dbcf02cSchristos if (ap->wps) {
17938dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Protocol run already in "
17948dbcf02cSchristos "progress with this AP");
17958dbcf02cSchristos return;
17968dbcf02cSchristos }
17978dbcf02cSchristos
17988dbcf02cSchristos os_memset(&cfg, 0, sizeof(cfg));
17998dbcf02cSchristos cfg.wps = ap->er->wps;
18008dbcf02cSchristos cfg.registrar = 1;
18018dbcf02cSchristos ap->wps = wps_init(&cfg);
18028dbcf02cSchristos if (ap->wps == NULL)
18038dbcf02cSchristos return;
18048dbcf02cSchristos ap->wps->ap_settings_cb = wps_er_ap_settings_cb;
18058dbcf02cSchristos ap->wps->ap_settings_cb_ctx = ap;
18068dbcf02cSchristos
18078dbcf02cSchristos wps_er_ap_process(ap, m1);
18088dbcf02cSchristos }
18098dbcf02cSchristos
18108dbcf02cSchristos
wps_er_ap_learn(struct wps_er_ap * ap,const char * dev_info)18118dbcf02cSchristos static void wps_er_ap_learn(struct wps_er_ap *ap, const char *dev_info)
18128dbcf02cSchristos {
18138dbcf02cSchristos struct wpabuf *info;
18148dbcf02cSchristos enum http_reply_code ret;
18158dbcf02cSchristos
18168dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Received GetDeviceInfo response (M1) "
18178dbcf02cSchristos "from the AP");
18188dbcf02cSchristos info = xml_get_base64_item(dev_info, "NewDeviceInfo", &ret);
18198dbcf02cSchristos if (info == NULL) {
18208dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Could not extract "
18218dbcf02cSchristos "NewDeviceInfo from GetDeviceInfo response");
18228dbcf02cSchristos return;
18238dbcf02cSchristos }
18248dbcf02cSchristos
18258dbcf02cSchristos ap->m1_handler(ap, info);
18268dbcf02cSchristos wpabuf_free(info);
18278dbcf02cSchristos }
18288dbcf02cSchristos
18298dbcf02cSchristos
wps_er_http_get_dev_info_cb(void * ctx,struct http_client * c,enum http_client_event event)18308dbcf02cSchristos static void wps_er_http_get_dev_info_cb(void *ctx, struct http_client *c,
18318dbcf02cSchristos enum http_client_event event)
18328dbcf02cSchristos {
18338dbcf02cSchristos struct wps_er_ap *ap = ctx;
18348dbcf02cSchristos struct wpabuf *reply;
18358dbcf02cSchristos char *dev_info = NULL;
18368dbcf02cSchristos
18378dbcf02cSchristos switch (event) {
18388dbcf02cSchristos case HTTP_CLIENT_OK:
18398dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: GetDeviceInfo OK");
18408dbcf02cSchristos reply = http_client_get_body(c);
18418dbcf02cSchristos if (reply == NULL)
18428dbcf02cSchristos break;
18438dbcf02cSchristos dev_info = os_zalloc(wpabuf_len(reply) + 1);
18448dbcf02cSchristos if (dev_info == NULL)
18458dbcf02cSchristos break;
18468dbcf02cSchristos os_memcpy(dev_info, wpabuf_head(reply), wpabuf_len(reply));
18478dbcf02cSchristos break;
18488dbcf02cSchristos case HTTP_CLIENT_FAILED:
18498dbcf02cSchristos case HTTP_CLIENT_INVALID_REPLY:
18508dbcf02cSchristos case HTTP_CLIENT_TIMEOUT:
18518dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: GetDeviceInfo failed");
18528dbcf02cSchristos break;
18538dbcf02cSchristos }
18548dbcf02cSchristos http_client_free(ap->http);
18558dbcf02cSchristos ap->http = NULL;
18568dbcf02cSchristos
18578dbcf02cSchristos if (dev_info) {
18588dbcf02cSchristos wps_er_ap_learn(ap, dev_info);
18598dbcf02cSchristos os_free(dev_info);
18608dbcf02cSchristos }
18618dbcf02cSchristos }
18628dbcf02cSchristos
18638dbcf02cSchristos
wps_er_send_get_device_info(struct wps_er_ap * ap,void (* m1_handler)(struct wps_er_ap * ap,struct wpabuf * m1))18648dbcf02cSchristos static int wps_er_send_get_device_info(struct wps_er_ap *ap,
18658dbcf02cSchristos void (*m1_handler)(struct wps_er_ap *ap,
18668dbcf02cSchristos struct wpabuf *m1))
18678dbcf02cSchristos {
18688dbcf02cSchristos struct wpabuf *buf;
18698dbcf02cSchristos char *len_ptr, *body_ptr;
18708dbcf02cSchristos struct sockaddr_in dst;
18718dbcf02cSchristos char *url, *path;
18728dbcf02cSchristos
18738dbcf02cSchristos if (ap->http) {
18748dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP operation ongoing "
18758dbcf02cSchristos "with the AP - cannot get device info");
18768dbcf02cSchristos return -1;
18778dbcf02cSchristos }
18788dbcf02cSchristos
18798dbcf02cSchristos if (ap->control_url == NULL) {
18808dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
18818dbcf02cSchristos return -1;
18828dbcf02cSchristos }
18838dbcf02cSchristos
18848dbcf02cSchristos url = http_client_url_parse(ap->control_url, &dst, &path);
18858dbcf02cSchristos if (url == NULL) {
18868dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
18878dbcf02cSchristos return -1;
18888dbcf02cSchristos }
18898dbcf02cSchristos
18908dbcf02cSchristos buf = wps_er_soap_hdr(NULL, "GetDeviceInfo", NULL, path, &dst,
18918dbcf02cSchristos &len_ptr, &body_ptr);
18928dbcf02cSchristos os_free(url);
18938dbcf02cSchristos if (buf == NULL)
18948dbcf02cSchristos return -1;
18958dbcf02cSchristos
18968dbcf02cSchristos wps_er_soap_end(buf, "GetDeviceInfo", len_ptr, body_ptr);
18978dbcf02cSchristos
18988dbcf02cSchristos ap->http = http_client_addr(&dst, buf, 10000,
18998dbcf02cSchristos wps_er_http_get_dev_info_cb, ap);
19008dbcf02cSchristos if (ap->http == NULL) {
19018dbcf02cSchristos wpabuf_free(buf);
19028dbcf02cSchristos return -1;
19038dbcf02cSchristos }
19048dbcf02cSchristos
19058dbcf02cSchristos ap->m1_handler = m1_handler;
19068dbcf02cSchristos
19078dbcf02cSchristos return 0;
19088dbcf02cSchristos }
19098dbcf02cSchristos
19108dbcf02cSchristos
wps_er_learn(struct wps_er * er,const u8 * uuid,const u8 * addr,const u8 * pin,size_t pin_len)191136d97821Schristos int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *addr,
191236d97821Schristos const u8 *pin, size_t pin_len)
19138dbcf02cSchristos {
19148dbcf02cSchristos struct wps_er_ap *ap;
19158dbcf02cSchristos
19168dbcf02cSchristos if (er == NULL)
19178dbcf02cSchristos return -1;
19188dbcf02cSchristos
191936d97821Schristos ap = wps_er_ap_get(er, NULL, uuid, addr);
19208dbcf02cSchristos if (ap == NULL) {
19218dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: AP not found for learn "
19228dbcf02cSchristos "request");
19238dbcf02cSchristos return -1;
19248dbcf02cSchristos }
192536d97821Schristos if (uuid == NULL)
192636d97821Schristos uuid = ap->uuid;
19278dbcf02cSchristos if (ap->wps) {
19288dbcf02cSchristos wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing "
19298dbcf02cSchristos "with the AP - cannot start learn");
19308dbcf02cSchristos return -1;
19318dbcf02cSchristos }
19328dbcf02cSchristos
19338dbcf02cSchristos if (wps_er_send_get_device_info(ap, wps_er_ap_learn_m1) < 0)
19348dbcf02cSchristos return -1;
19358dbcf02cSchristos
193642669be3Schristos er->skip_set_sel_reg = 1;
193742669be3Schristos wps_registrar_add_pin(er->wps->registrar, NULL, uuid, pin, pin_len, 0);
193842669be3Schristos er->skip_set_sel_reg = 0;
193942669be3Schristos
194042669be3Schristos return 0;
194142669be3Schristos }
194242669be3Schristos
194342669be3Schristos
wps_er_set_config(struct wps_er * er,const u8 * uuid,const u8 * addr,const struct wps_credential * cred)194436d97821Schristos int wps_er_set_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
194542669be3Schristos const struct wps_credential *cred)
194642669be3Schristos {
194742669be3Schristos struct wps_er_ap *ap;
194842669be3Schristos
194942669be3Schristos if (er == NULL)
195042669be3Schristos return -1;
195142669be3Schristos
195236d97821Schristos ap = wps_er_ap_get(er, NULL, uuid, addr);
195342669be3Schristos if (ap == NULL) {
195442669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: AP not found for set config "
195542669be3Schristos "request");
195642669be3Schristos return -1;
195742669be3Schristos }
195842669be3Schristos
195942669be3Schristos os_free(ap->ap_settings);
1960ebb5671cSchristos ap->ap_settings = os_memdup(cred, sizeof(*cred));
196142669be3Schristos if (ap->ap_settings == NULL)
196242669be3Schristos return -1;
196342669be3Schristos ap->ap_settings->cred_attr = NULL;
196442669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: Updated local AP settings based set "
196542669be3Schristos "config request");
196642669be3Schristos
196742669be3Schristos return 0;
196842669be3Schristos }
196942669be3Schristos
197042669be3Schristos
wps_er_ap_config_m1(struct wps_er_ap * ap,struct wpabuf * m1)197142669be3Schristos static void wps_er_ap_config_m1(struct wps_er_ap *ap, struct wpabuf *m1)
197242669be3Schristos {
197342669be3Schristos struct wps_config cfg;
197442669be3Schristos
197542669be3Schristos if (ap->wps) {
197642669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: Protocol run already in "
197742669be3Schristos "progress with this AP");
197842669be3Schristos return;
197942669be3Schristos }
198042669be3Schristos
198142669be3Schristos os_memset(&cfg, 0, sizeof(cfg));
198242669be3Schristos cfg.wps = ap->er->wps;
198342669be3Schristos cfg.registrar = 1;
198442669be3Schristos cfg.new_ap_settings = ap->ap_settings;
198542669be3Schristos ap->wps = wps_init(&cfg);
198642669be3Schristos if (ap->wps == NULL)
198742669be3Schristos return;
198842669be3Schristos ap->wps->ap_settings_cb = NULL;
198942669be3Schristos ap->wps->ap_settings_cb_ctx = NULL;
199042669be3Schristos
199142669be3Schristos wps_er_ap_process(ap, m1);
199242669be3Schristos }
199342669be3Schristos
199442669be3Schristos
wps_er_config(struct wps_er * er,const u8 * uuid,const u8 * addr,const u8 * pin,size_t pin_len,const struct wps_credential * cred)199536d97821Schristos int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
199636d97821Schristos const u8 *pin, size_t pin_len,
199736d97821Schristos const struct wps_credential *cred)
199842669be3Schristos {
199942669be3Schristos struct wps_er_ap *ap;
200042669be3Schristos
200142669be3Schristos if (er == NULL)
200242669be3Schristos return -1;
200342669be3Schristos
200436d97821Schristos ap = wps_er_ap_get(er, NULL, uuid, addr);
200542669be3Schristos if (ap == NULL) {
200642669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: AP not found for config "
200742669be3Schristos "request");
200842669be3Schristos return -1;
200942669be3Schristos }
201036d97821Schristos if (uuid == NULL)
201136d97821Schristos uuid = ap->uuid;
201242669be3Schristos if (ap->wps) {
201342669be3Schristos wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing "
201442669be3Schristos "with the AP - cannot start config");
201542669be3Schristos return -1;
201642669be3Schristos }
201742669be3Schristos
201842669be3Schristos os_free(ap->ap_settings);
2019ebb5671cSchristos ap->ap_settings = os_memdup(cred, sizeof(*cred));
202042669be3Schristos if (ap->ap_settings == NULL)
202142669be3Schristos return -1;
202242669be3Schristos ap->ap_settings->cred_attr = NULL;
202342669be3Schristos
202442669be3Schristos if (wps_er_send_get_device_info(ap, wps_er_ap_config_m1) < 0)
202542669be3Schristos return -1;
202642669be3Schristos
202742669be3Schristos er->skip_set_sel_reg = 1;
202842669be3Schristos wps_registrar_add_pin(er->wps->registrar, NULL, uuid, pin, pin_len, 0);
202942669be3Schristos er->skip_set_sel_reg = 0;
20308dbcf02cSchristos
20318dbcf02cSchristos return 0;
20328dbcf02cSchristos }
203362a52023Schristos
203462a52023Schristos
203562a52023Schristos #ifdef CONFIG_WPS_NFC
203636d97821Schristos
wps_er_config_token_from_cred(struct wps_context * wps,struct wps_credential * cred)203736d97821Schristos struct wpabuf * wps_er_config_token_from_cred(struct wps_context *wps,
203836d97821Schristos struct wps_credential *cred)
203962a52023Schristos {
204062a52023Schristos struct wpabuf *ret;
204162a52023Schristos struct wps_data data;
204262a52023Schristos
204336d97821Schristos ret = wpabuf_alloc(500);
204436d97821Schristos if (ret == NULL)
204536d97821Schristos return NULL;
204636d97821Schristos
204736d97821Schristos os_memset(&data, 0, sizeof(data));
204836d97821Schristos data.wps = wps;
204936d97821Schristos data.use_cred = cred;
205036d97821Schristos if (wps_build_cred(&data, ret) ||
2051*0d69f216Schristos wps_build_wfa_ext(ret, 0, NULL, 0, 0)) {
205236d97821Schristos wpabuf_free(ret);
205336d97821Schristos return NULL;
205436d97821Schristos }
205536d97821Schristos
205636d97821Schristos return ret;
205736d97821Schristos }
205836d97821Schristos
205936d97821Schristos
wps_er_nfc_config_token(struct wps_er * er,const u8 * uuid,const u8 * addr)206036d97821Schristos struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid,
206136d97821Schristos const u8 *addr)
206236d97821Schristos {
206336d97821Schristos struct wps_er_ap *ap;
206436d97821Schristos
206562a52023Schristos if (er == NULL)
206662a52023Schristos return NULL;
206762a52023Schristos
206836d97821Schristos ap = wps_er_ap_get(er, NULL, uuid, addr);
206962a52023Schristos if (ap == NULL)
207062a52023Schristos return NULL;
207162a52023Schristos if (ap->ap_settings == NULL) {
207262a52023Schristos wpa_printf(MSG_DEBUG, "WPS ER: No settings known for the "
207362a52023Schristos "selected AP");
207462a52023Schristos return NULL;
207562a52023Schristos }
207662a52023Schristos
207736d97821Schristos return wps_er_config_token_from_cred(er->wps, ap->ap_settings);
207836d97821Schristos }
207936d97821Schristos
208036d97821Schristos
wps_er_nfc_handover_sel(struct wps_er * er,struct wps_context * wps,const u8 * uuid,const u8 * addr,struct wpabuf * pubkey)208136d97821Schristos struct wpabuf * wps_er_nfc_handover_sel(struct wps_er *er,
208236d97821Schristos struct wps_context *wps, const u8 *uuid,
208336d97821Schristos const u8 *addr, struct wpabuf *pubkey)
208436d97821Schristos {
208536d97821Schristos struct wps_er_ap *ap;
208636d97821Schristos
208736d97821Schristos if (er == NULL)
208862a52023Schristos return NULL;
208962a52023Schristos
209036d97821Schristos ap = wps_er_ap_get(er, NULL, uuid, addr);
209136d97821Schristos if (ap == NULL)
209236d97821Schristos return NULL;
209336d97821Schristos if (ap->ap_settings == NULL) {
209436d97821Schristos wpa_printf(MSG_DEBUG, "WPS ER: No settings known for the "
209536d97821Schristos "selected AP");
209662a52023Schristos return NULL;
209762a52023Schristos }
209862a52023Schristos
209936d97821Schristos os_memcpy(wps->ssid, ap->ap_settings->ssid, ap->ap_settings->ssid_len);
210036d97821Schristos wps->ssid_len = ap->ap_settings->ssid_len;
210136d97821Schristos
210236d97821Schristos return wps_build_nfc_handover_sel(wps, pubkey, addr, 0);
210362a52023Schristos }
210436d97821Schristos
210562a52023Schristos #endif /* CONFIG_WPS_NFC */
2106