Branch data Line data Source code
1 : : /*
2 : : * Wi-Fi Protected Setup - External Registrar
3 : : * Copyright (c) 2009-2013, Jouni Malinen <j@w1.fi>
4 : : *
5 : : * This software may be distributed under the terms of the BSD license.
6 : : * See README for more details.
7 : : */
8 : :
9 : : #include "includes.h"
10 : :
11 : : #include "common.h"
12 : : #include "base64.h"
13 : : #include "uuid.h"
14 : : #include "eloop.h"
15 : : #include "httpread.h"
16 : : #include "http_client.h"
17 : : #include "http_server.h"
18 : : #include "upnp_xml.h"
19 : : #include "wps_i.h"
20 : : #include "wps_upnp.h"
21 : : #include "wps_upnp_i.h"
22 : : #include "wps_er.h"
23 : :
24 : :
25 : : static void wps_er_deinit_finish(void *eloop_data, void *user_ctx);
26 : : static void wps_er_ap_timeout(void *eloop_data, void *user_ctx);
27 : : static void wps_er_sta_timeout(void *eloop_data, void *user_ctx);
28 : : static void wps_er_ap_process(struct wps_er_ap *ap, struct wpabuf *msg);
29 : : static int wps_er_send_get_device_info(struct wps_er_ap *ap,
30 : : void (*m1_handler)(struct wps_er_ap *ap,
31 : : struct wpabuf *m1));
32 : :
33 : :
34 : 13 : static void wps_er_sta_event(struct wps_context *wps, struct wps_er_sta *sta,
35 : : enum wps_event event)
36 : : {
37 : : union wps_event_data data;
38 : 13 : struct wps_event_er_enrollee *ev = &data.enrollee;
39 : :
40 [ - + ]: 13 : if (wps->event_cb == NULL)
41 : 13 : return;
42 : :
43 : 13 : os_memset(&data, 0, sizeof(data));
44 : 13 : ev->uuid = sta->uuid;
45 : 13 : ev->mac_addr = sta->addr;
46 : 13 : ev->m1_received = sta->m1_received;
47 : 13 : ev->config_methods = sta->config_methods;
48 : 13 : ev->dev_passwd_id = sta->dev_passwd_id;
49 : 13 : ev->pri_dev_type = sta->pri_dev_type;
50 : 13 : ev->dev_name = sta->dev_name;
51 : 13 : ev->manufacturer = sta->manufacturer;
52 : 13 : ev->model_name = sta->model_name;
53 : 13 : ev->model_number = sta->model_number;
54 : 13 : ev->serial_number = sta->serial_number;
55 : 13 : wps->event_cb(wps->cb_ctx, event, &data);
56 : : }
57 : :
58 : :
59 : 20 : static struct wps_er_sta * wps_er_sta_get(struct wps_er_ap *ap, const u8 *addr,
60 : : const u8 *uuid)
61 : : {
62 : : struct wps_er_sta *sta;
63 [ + + ]: 22 : dl_list_for_each(sta, &ap->sta, struct wps_er_sta, list) {
64 [ + - ][ + + ]: 16 : if ((addr == NULL ||
65 [ - + ]: 14 : os_memcmp(sta->addr, addr, ETH_ALEN) == 0) &&
66 [ # # ]: 0 : (uuid == NULL ||
67 : 0 : os_memcmp(uuid, sta->uuid, WPS_UUID_LEN) == 0))
68 : 14 : return sta;
69 : : }
70 : 20 : return NULL;
71 : : }
72 : :
73 : :
74 : 5 : static void wps_er_sta_free(struct wps_er_sta *sta)
75 : : {
76 : 5 : wps_er_sta_event(sta->ap->er->wps, sta, WPS_EV_ER_ENROLLEE_REMOVE);
77 [ - + ]: 5 : if (sta->wps)
78 : 0 : wps_deinit(sta->wps);
79 : 5 : os_free(sta->manufacturer);
80 : 5 : os_free(sta->model_name);
81 : 5 : os_free(sta->model_number);
82 : 5 : os_free(sta->serial_number);
83 : 5 : os_free(sta->dev_name);
84 : 5 : http_client_free(sta->http);
85 : 5 : eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL);
86 : 5 : os_free(sta->cred);
87 : 5 : os_free(sta);
88 : 5 : }
89 : :
90 : :
91 : 4 : static void wps_er_sta_remove_all(struct wps_er_ap *ap)
92 : : {
93 : : struct wps_er_sta *prev, *sta;
94 [ + + ]: 9 : dl_list_for_each_safe(sta, prev, &ap->sta, struct wps_er_sta, list)
95 : 5 : wps_er_sta_free(sta);
96 : 4 : }
97 : :
98 : :
99 : 44 : static struct wps_er_ap * wps_er_ap_get(struct wps_er *er,
100 : : struct in_addr *addr, const u8 *uuid,
101 : : const u8 *mac_addr)
102 : : {
103 : : struct wps_er_ap *ap;
104 [ + + ]: 44 : dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
105 [ + + ][ + - ]: 23 : if ((addr == NULL || ap->addr.s_addr == addr->s_addr) &&
[ + + ]
106 [ + - ]: 18 : (uuid == NULL ||
107 [ + + ]: 23 : os_memcmp(uuid, ap->uuid, WPS_UUID_LEN) == 0) &&
108 [ + - ]: 2 : (mac_addr == NULL ||
109 : 2 : os_memcmp(mac_addr, ap->mac_addr, ETH_ALEN) == 0))
110 : 23 : return ap;
111 : : }
112 : 44 : return NULL;
113 : : }
114 : :
115 : :
116 : 19 : static struct wps_er_ap * wps_er_ap_get_id(struct wps_er *er, unsigned int id)
117 : : {
118 : : struct wps_er_ap *ap;
119 [ + - ]: 19 : dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
120 [ + - ]: 19 : if (ap->id == id)
121 : 19 : return ap;
122 : : }
123 : 19 : return NULL;
124 : : }
125 : :
126 : :
127 : 8 : static void wps_er_ap_event(struct wps_context *wps, struct wps_er_ap *ap,
128 : : enum wps_event event)
129 : : {
130 : : union wps_event_data data;
131 : 8 : struct wps_event_er_ap *evap = &data.ap;
132 : :
133 [ - + ]: 8 : if (wps->event_cb == NULL)
134 : 8 : return;
135 : :
136 : 8 : os_memset(&data, 0, sizeof(data));
137 : 8 : evap->uuid = ap->uuid;
138 : 8 : evap->friendly_name = ap->friendly_name;
139 : 8 : evap->manufacturer = ap->manufacturer;
140 : 8 : evap->manufacturer_url = ap->manufacturer_url;
141 : 8 : evap->model_description = ap->model_description;
142 : 8 : evap->model_name = ap->model_name;
143 : 8 : evap->model_number = ap->model_number;
144 : 8 : evap->model_url = ap->model_url;
145 : 8 : evap->serial_number = ap->serial_number;
146 : 8 : evap->upc = ap->upc;
147 : 8 : evap->pri_dev_type = ap->pri_dev_type;
148 : 8 : evap->wps_state = ap->wps_state;
149 : 8 : evap->mac_addr = ap->mac_addr;
150 : 8 : wps->event_cb(wps->cb_ctx, event, &data);
151 : : }
152 : :
153 : :
154 : 4 : static void wps_er_ap_free(struct wps_er_ap *ap)
155 : : {
156 : 4 : http_client_free(ap->http);
157 : 4 : ap->http = NULL;
158 : :
159 : 4 : os_free(ap->location);
160 : 4 : os_free(ap->friendly_name);
161 : 4 : os_free(ap->manufacturer);
162 : 4 : os_free(ap->manufacturer_url);
163 : 4 : os_free(ap->model_description);
164 : 4 : os_free(ap->model_name);
165 : 4 : os_free(ap->model_number);
166 : 4 : os_free(ap->model_url);
167 : 4 : os_free(ap->serial_number);
168 : 4 : os_free(ap->udn);
169 : 4 : os_free(ap->upc);
170 : :
171 : 4 : os_free(ap->scpd_url);
172 : 4 : os_free(ap->control_url);
173 : 4 : os_free(ap->event_sub_url);
174 : :
175 : 4 : os_free(ap->ap_settings);
176 : :
177 : 4 : os_free(ap);
178 : 4 : }
179 : :
180 : :
181 : 3 : static void wps_er_ap_unsubscribed(struct wps_er *er, struct wps_er_ap *ap)
182 : : {
183 : 3 : wpa_printf(MSG_DEBUG, "WPS ER: Unsubscribed from AP %s (%s)",
184 : : inet_ntoa(ap->addr), ap->location);
185 : 3 : dl_list_del(&ap->list);
186 : 3 : wps_er_ap_free(ap);
187 : :
188 [ + + ][ + - ]: 3 : if (er->deinitializing && dl_list_empty(&er->ap_unsubscribing))
189 : 1 : wps_er_deinit_finish(er, NULL);
190 : 3 : }
191 : :
192 : :
193 : 3 : static void wps_er_http_unsubscribe_cb(void *ctx, struct http_client *c,
194 : : enum http_client_event event)
195 : : {
196 : 3 : struct wps_er_ap *ap = ctx;
197 : :
198 [ + + - ]: 3 : switch (event) {
199 : : case HTTP_CLIENT_OK:
200 : 1 : wpa_printf(MSG_DEBUG, "WPS ER: Unsubscribed from events");
201 : 1 : ap->subscribed = 0;
202 : 1 : break;
203 : : case HTTP_CLIENT_FAILED:
204 : : case HTTP_CLIENT_INVALID_REPLY:
205 : : case HTTP_CLIENT_TIMEOUT:
206 : 2 : wpa_printf(MSG_DEBUG, "WPS ER: Failed to unsubscribe from "
207 : : "events");
208 : 2 : break;
209 : : }
210 : 3 : http_client_free(ap->http);
211 : 3 : ap->http = NULL;
212 : :
213 : : /*
214 : : * Need to get rid of the AP entry regardless of whether we managed to
215 : : * unsubscribe cleanly or not.
216 : : */
217 : 3 : wps_er_ap_unsubscribed(ap->er, ap);
218 : 3 : }
219 : :
220 : :
221 : 3 : static void wps_er_ap_unsubscribe(struct wps_er *er, struct wps_er_ap *ap)
222 : : {
223 : : struct wpabuf *req;
224 : : struct sockaddr_in dst;
225 : : char *url, *path;
226 : : char sid[100];
227 : :
228 [ - + ]: 3 : if (ap->event_sub_url == NULL) {
229 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: No eventSubURL - cannot "
230 : : "subscribe");
231 : 0 : goto fail;
232 : : }
233 [ - + ]: 3 : if (ap->http) {
234 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request - cannot "
235 : : "send subscribe request");
236 : 0 : goto fail;
237 : : }
238 : :
239 : 3 : url = http_client_url_parse(ap->event_sub_url, &dst, &path);
240 [ - + ]: 3 : if (url == NULL) {
241 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse eventSubURL");
242 : 0 : goto fail;
243 : : }
244 : :
245 : 3 : req = wpabuf_alloc(os_strlen(ap->event_sub_url) + 1000);
246 [ - + ]: 3 : if (req == NULL) {
247 : 0 : os_free(url);
248 : 0 : goto fail;
249 : : }
250 : 3 : uuid_bin2str(ap->sid, sid, sizeof(sid));
251 : 3 : wpabuf_printf(req,
252 : : "UNSUBSCRIBE %s HTTP/1.1\r\n"
253 : : "HOST: %s:%d\r\n"
254 : : "SID: uuid:%s\r\n"
255 : : "\r\n",
256 : 3 : path, inet_ntoa(dst.sin_addr), ntohs(dst.sin_port), sid);
257 : 3 : os_free(url);
258 : 3 : wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Unsubscription request",
259 : : wpabuf_head(req), wpabuf_len(req));
260 : :
261 : 3 : ap->http = http_client_addr(&dst, req, 1000,
262 : : wps_er_http_unsubscribe_cb, ap);
263 [ - + ]: 3 : if (ap->http == NULL) {
264 : 0 : wpabuf_free(req);
265 : 0 : goto fail;
266 : : }
267 : 3 : return;
268 : :
269 : : fail:
270 : : /*
271 : : * Need to get rid of the AP entry even when we fail to unsubscribe
272 : : * cleanly.
273 : : */
274 : 0 : wps_er_ap_unsubscribed(ap->er, ap);
275 : : }
276 : :
277 : :
278 : 5 : static struct wps_er_ap_settings * wps_er_ap_get_settings(struct wps_er *er,
279 : : const u8 *uuid)
280 : : {
281 : : struct wps_er_ap_settings *s;
282 [ + + ]: 5 : dl_list_for_each(s, &er->ap_settings, struct wps_er_ap_settings, list)
283 [ + - ]: 2 : if (os_memcmp(uuid, s->uuid, WPS_UUID_LEN) == 0)
284 : 2 : return s;
285 : 5 : return NULL;
286 : : }
287 : :
288 : :
289 : 20 : int wps_er_ap_cache_settings(struct wps_er *er, struct in_addr *addr)
290 : : {
291 : : struct wps_er_ap *ap;
292 : : struct wps_er_ap_settings *settings;
293 : :
294 : 20 : ap = wps_er_ap_get(er, addr, NULL, NULL);
295 [ + + ][ + + ]: 20 : if (ap == NULL || ap->ap_settings == NULL)
296 : 18 : return -1;
297 : :
298 : 2 : settings = wps_er_ap_get_settings(er, ap->uuid);
299 [ + + ]: 2 : if (!settings) {
300 : 1 : settings = os_zalloc(sizeof(*settings));
301 [ - + ]: 1 : if (settings == NULL)
302 : 0 : return -1;
303 : 1 : os_memcpy(settings->uuid, ap->uuid, WPS_UUID_LEN);
304 : 1 : dl_list_add(&er->ap_settings, &settings->list);
305 : : }
306 : 2 : os_memcpy(&settings->ap_settings, ap->ap_settings,
307 : : sizeof(struct wps_credential));
308 : :
309 : 20 : return 0;
310 : : }
311 : :
312 : :
313 : 3 : static int wps_er_ap_use_cached_settings(struct wps_er *er,
314 : : struct wps_er_ap *ap)
315 : : {
316 : : struct wps_er_ap_settings *s;
317 : :
318 [ - + ]: 3 : if (ap->ap_settings)
319 : 0 : return 0;
320 : :
321 : 3 : s = wps_er_ap_get_settings(ap->er, ap->uuid);
322 [ + + ]: 3 : if (!s)
323 : 2 : return -1;
324 : :
325 : 1 : ap->ap_settings = os_malloc(sizeof(*ap->ap_settings));
326 [ - + ]: 1 : if (ap->ap_settings == NULL)
327 : 0 : return -1;
328 : :
329 : 1 : os_memcpy(ap->ap_settings, &s->ap_settings, sizeof(*ap->ap_settings));
330 : 1 : wpa_printf(MSG_DEBUG, "WPS ER: Use cached AP settings");
331 : 3 : return 0;
332 : : }
333 : :
334 : :
335 : 4 : static void wps_er_ap_remove_entry(struct wps_er *er, struct wps_er_ap *ap)
336 : : {
337 : 4 : wpa_printf(MSG_DEBUG, "WPS ER: Removing AP entry for %s (%s)",
338 : : inet_ntoa(ap->addr), ap->location);
339 : 4 : eloop_cancel_timeout(wps_er_ap_timeout, er, ap);
340 : 4 : wps_er_sta_remove_all(ap);
341 : 4 : wps_er_ap_event(er->wps, ap, WPS_EV_ER_AP_REMOVE);
342 : 4 : http_client_free(ap->http);
343 : 4 : ap->http = NULL;
344 [ - + ]: 4 : if (ap->wps) {
345 : 0 : wps_deinit(ap->wps);
346 : 0 : ap->wps = NULL;
347 : : }
348 : :
349 : 4 : dl_list_del(&ap->list);
350 [ + + ]: 4 : if (ap->subscribed) {
351 : 3 : dl_list_add(&er->ap_unsubscribing, &ap->list);
352 : 3 : wps_er_ap_unsubscribe(er, ap);
353 : : } else
354 : 1 : wps_er_ap_free(ap);
355 : 4 : }
356 : :
357 : :
358 : 0 : static void wps_er_ap_timeout(void *eloop_data, void *user_ctx)
359 : : {
360 : 0 : struct wps_er *er = eloop_data;
361 : 0 : struct wps_er_ap *ap = user_ctx;
362 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: AP advertisement timed out");
363 : 0 : wps_er_ap_remove_entry(er, ap);
364 : 0 : }
365 : :
366 : :
367 : 3 : static int wps_er_get_sid(struct wps_er_ap *ap, char *sid)
368 : : {
369 : : char *pos;
370 : : char txt[100];
371 : :
372 [ - + ]: 3 : if (!sid) {
373 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: No SID received from %s (%s)",
374 : : inet_ntoa(ap->addr), ap->location);
375 : 0 : return -1;
376 : : }
377 : :
378 : 3 : pos = os_strstr(sid, "uuid:");
379 [ - + ]: 3 : if (!pos) {
380 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Invalid SID received from "
381 : : "%s (%s): '%s'", inet_ntoa(ap->addr), ap->location,
382 : : sid);
383 : 0 : return -1;
384 : : }
385 : :
386 : 3 : pos += 5;
387 [ - + ]: 3 : if (uuid_str2bin(pos, ap->sid) < 0) {
388 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Invalid SID received from "
389 : : "%s (%s): '%s'", inet_ntoa(ap->addr), ap->location,
390 : : sid);
391 : 0 : return -1;
392 : : }
393 : :
394 : 3 : uuid_bin2str(ap->sid, txt, sizeof(txt));
395 : 3 : wpa_printf(MSG_DEBUG, "WPS ER: SID for subscription with %s (%s): %s",
396 : : inet_ntoa(ap->addr), ap->location, txt);
397 : :
398 : 3 : return 0;
399 : : }
400 : :
401 : :
402 : 3 : static void wps_er_http_subscribe_cb(void *ctx, struct http_client *c,
403 : : enum http_client_event event)
404 : : {
405 : 3 : struct wps_er_ap *ap = ctx;
406 : :
407 [ + - - ]: 3 : switch (event) {
408 : : case HTTP_CLIENT_OK:
409 : 3 : wpa_printf(MSG_DEBUG, "WPS ER: Subscribed to events");
410 : 3 : ap->subscribed = 1;
411 : 3 : wps_er_get_sid(ap, http_client_get_hdr_line(c, "SID"));
412 : 3 : wps_er_ap_use_cached_settings(ap->er, ap);
413 : 3 : wps_er_ap_event(ap->er->wps, ap, WPS_EV_ER_AP_ADD);
414 : 3 : break;
415 : : case HTTP_CLIENT_FAILED:
416 : : case HTTP_CLIENT_INVALID_REPLY:
417 : : case HTTP_CLIENT_TIMEOUT:
418 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Failed to subscribe to events");
419 : 0 : break;
420 : : }
421 : 3 : http_client_free(ap->http);
422 : 3 : ap->http = NULL;
423 : 3 : }
424 : :
425 : :
426 : 3 : static void wps_er_subscribe(struct wps_er_ap *ap)
427 : : {
428 : : struct wpabuf *req;
429 : : struct sockaddr_in dst;
430 : : char *url, *path;
431 : :
432 [ - + ]: 3 : if (ap->event_sub_url == NULL) {
433 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: No eventSubURL - cannot "
434 : : "subscribe");
435 : 0 : return;
436 : : }
437 [ - + ]: 3 : if (ap->http) {
438 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request - cannot "
439 : : "send subscribe request");
440 : 0 : return;
441 : : }
442 : :
443 : 3 : url = http_client_url_parse(ap->event_sub_url, &dst, &path);
444 [ - + ]: 3 : if (url == NULL) {
445 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse eventSubURL");
446 : 0 : return;
447 : : }
448 : :
449 : 3 : req = wpabuf_alloc(os_strlen(ap->event_sub_url) + 1000);
450 [ - + ]: 3 : if (req == NULL) {
451 : 0 : os_free(url);
452 : 0 : return;
453 : : }
454 : 3 : wpabuf_printf(req,
455 : : "SUBSCRIBE %s HTTP/1.1\r\n"
456 : : "HOST: %s:%d\r\n"
457 : : "CALLBACK: <http://%s:%d/event/%u/%u>\r\n"
458 : : "NT: upnp:event\r\n"
459 : : "TIMEOUT: Second-%d\r\n"
460 : : "\r\n",
461 : 3 : path, inet_ntoa(dst.sin_addr), ntohs(dst.sin_port),
462 : 6 : ap->er->ip_addr_text, ap->er->http_port,
463 : 3 : ap->er->event_id, ap->id, 1800);
464 : 3 : os_free(url);
465 : 3 : wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Subscription request",
466 : : wpabuf_head(req), wpabuf_len(req));
467 : :
468 : 3 : ap->http = http_client_addr(&dst, req, 1000, wps_er_http_subscribe_cb,
469 : : ap);
470 [ - + ]: 3 : if (ap->http == NULL)
471 : 3 : wpabuf_free(req);
472 : : }
473 : :
474 : :
475 : 3 : static void wps_er_ap_get_m1(struct wps_er_ap *ap, struct wpabuf *m1)
476 : : {
477 : : struct wps_parse_attr attr;
478 : :
479 [ - + ]: 3 : if (wps_parse_msg(m1, &attr) < 0) {
480 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse M1");
481 : 3 : return;
482 : : }
483 [ + - ]: 3 : if (attr.primary_dev_type)
484 : 3 : os_memcpy(ap->pri_dev_type, attr.primary_dev_type, 8);
485 [ + - ]: 3 : if (attr.wps_state)
486 : 3 : ap->wps_state = *attr.wps_state;
487 [ + - ]: 3 : if (attr.mac_addr)
488 : 3 : os_memcpy(ap->mac_addr, attr.mac_addr, ETH_ALEN);
489 : :
490 : 3 : wps_er_subscribe(ap);
491 : : }
492 : :
493 : :
494 : 4 : static void wps_er_get_device_info(struct wps_er_ap *ap)
495 : : {
496 : 4 : wps_er_send_get_device_info(ap, wps_er_ap_get_m1);
497 : 4 : }
498 : :
499 : :
500 : 4 : static const char * wps_er_find_wfadevice(const char *data)
501 : : {
502 : : const char *tag, *tagname, *end;
503 : : char *val;
504 : 4 : int found = 0;
505 : :
506 [ + + ]: 8 : while (!found) {
507 : : /* Find next <device> */
508 : : for (;;) {
509 [ - + ]: 36 : if (xml_next_tag(data, &tag, &tagname, &end))
510 : 0 : return NULL;
511 : 36 : data = end;
512 [ + + ][ + - ]: 36 : if (!os_strncasecmp(tagname, "device", 6) &&
513 [ - + ]: 4 : *tag != '/' &&
514 [ # # ]: 0 : (tagname[6] == '>' || !isgraph(tagname[6]))) {
515 : : break;
516 : : }
517 : 32 : }
518 : :
519 : : /* Check whether deviceType is WFADevice */
520 : 4 : val = xml_get_first_item(data, "deviceType");
521 [ - + ]: 4 : if (val == NULL)
522 : 0 : return NULL;
523 : 4 : wpa_printf(MSG_DEBUG, "WPS ER: Found deviceType '%s'", val);
524 : 4 : found = os_strcasecmp(val, "urn:schemas-wifialliance-org:"
525 : : "device:WFADevice:1") == 0;
526 : 4 : os_free(val);
527 : : }
528 : :
529 : 4 : return data;
530 : : }
531 : :
532 : :
533 : 4 : static void wps_er_parse_device_description(struct wps_er_ap *ap,
534 : : struct wpabuf *reply)
535 : : {
536 : : /* Note: reply includes null termination after the buffer data */
537 : 4 : const char *tmp, *data = wpabuf_head(reply);
538 : : char *pos;
539 : :
540 : 4 : wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Device info",
541 : : wpabuf_head(reply), wpabuf_len(reply));
542 : :
543 : : /*
544 : : * The root device description may include multiple devices, so first
545 : : * find the beginning of the WFADevice description to allow the
546 : : * simplistic parser to pick the correct entries.
547 : : */
548 : 4 : tmp = wps_er_find_wfadevice(data);
549 [ - + ]: 4 : if (tmp == NULL) {
550 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: WFADevice:1 device not found - "
551 : : "trying to parse invalid data");
552 : : } else
553 : 4 : data = tmp;
554 : :
555 : 4 : ap->friendly_name = xml_get_first_item(data, "friendlyName");
556 : 4 : wpa_printf(MSG_DEBUG, "WPS ER: friendlyName='%s'", ap->friendly_name);
557 : :
558 : 4 : ap->manufacturer = xml_get_first_item(data, "manufacturer");
559 : 4 : wpa_printf(MSG_DEBUG, "WPS ER: manufacturer='%s'", ap->manufacturer);
560 : :
561 : 4 : ap->manufacturer_url = xml_get_first_item(data, "manufacturerURL");
562 : 4 : wpa_printf(MSG_DEBUG, "WPS ER: manufacturerURL='%s'",
563 : : ap->manufacturer_url);
564 : :
565 : 4 : ap->model_description = xml_get_first_item(data, "modelDescription");
566 : 4 : wpa_printf(MSG_DEBUG, "WPS ER: modelDescription='%s'",
567 : : ap->model_description);
568 : :
569 : 4 : ap->model_name = xml_get_first_item(data, "modelName");
570 : 4 : wpa_printf(MSG_DEBUG, "WPS ER: modelName='%s'", ap->model_name);
571 : :
572 : 4 : ap->model_number = xml_get_first_item(data, "modelNumber");
573 : 4 : wpa_printf(MSG_DEBUG, "WPS ER: modelNumber='%s'", ap->model_number);
574 : :
575 : 4 : ap->model_url = xml_get_first_item(data, "modelURL");
576 : 4 : wpa_printf(MSG_DEBUG, "WPS ER: modelURL='%s'", ap->model_url);
577 : :
578 : 4 : ap->serial_number = xml_get_first_item(data, "serialNumber");
579 : 4 : wpa_printf(MSG_DEBUG, "WPS ER: serialNumber='%s'", ap->serial_number);
580 : :
581 : 4 : ap->udn = xml_get_first_item(data, "UDN");
582 : 4 : wpa_printf(MSG_DEBUG, "WPS ER: UDN='%s'", ap->udn);
583 : 4 : pos = os_strstr(ap->udn, "uuid:");
584 [ + - ]: 4 : if (pos) {
585 : 4 : pos += 5;
586 [ - + ]: 4 : if (uuid_str2bin(pos, ap->uuid) < 0)
587 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Invalid UUID in UDN");
588 : : }
589 : :
590 : 4 : ap->upc = xml_get_first_item(data, "UPC");
591 : 4 : wpa_printf(MSG_DEBUG, "WPS ER: UPC='%s'", ap->upc);
592 : :
593 : 4 : ap->scpd_url = http_link_update(
594 : 4 : xml_get_first_item(data, "SCPDURL"), ap->location);
595 : 4 : wpa_printf(MSG_DEBUG, "WPS ER: SCPDURL='%s'", ap->scpd_url);
596 : :
597 : 4 : ap->control_url = http_link_update(
598 : 4 : xml_get_first_item(data, "controlURL"), ap->location);
599 : 4 : wpa_printf(MSG_DEBUG, "WPS ER: controlURL='%s'", ap->control_url);
600 : :
601 : 4 : ap->event_sub_url = http_link_update(
602 : 4 : xml_get_first_item(data, "eventSubURL"), ap->location);
603 : 4 : wpa_printf(MSG_DEBUG, "WPS ER: eventSubURL='%s'", ap->event_sub_url);
604 : 4 : }
605 : :
606 : :
607 : 4 : static void wps_er_http_dev_desc_cb(void *ctx, struct http_client *c,
608 : : enum http_client_event event)
609 : : {
610 : 4 : struct wps_er_ap *ap = ctx;
611 : : struct wpabuf *reply;
612 : 4 : int ok = 0;
613 : :
614 [ + - - ]: 4 : switch (event) {
615 : : case HTTP_CLIENT_OK:
616 : 4 : reply = http_client_get_body(c);
617 [ - + ]: 4 : if (reply == NULL)
618 : 0 : break;
619 : 4 : wps_er_parse_device_description(ap, reply);
620 : 4 : ok = 1;
621 : 4 : break;
622 : : case HTTP_CLIENT_FAILED:
623 : : case HTTP_CLIENT_INVALID_REPLY:
624 : : case HTTP_CLIENT_TIMEOUT:
625 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Failed to fetch device info");
626 : 0 : break;
627 : : }
628 : 4 : http_client_free(ap->http);
629 : 4 : ap->http = NULL;
630 [ + - ]: 4 : if (ok)
631 : 4 : wps_er_get_device_info(ap);
632 : 4 : }
633 : :
634 : :
635 : 20 : void wps_er_ap_add(struct wps_er *er, const u8 *uuid, struct in_addr *addr,
636 : : const char *location, int max_age)
637 : : {
638 : : struct wps_er_ap *ap;
639 : :
640 : 20 : ap = wps_er_ap_get(er, addr, uuid, NULL);
641 [ + + ]: 20 : if (ap) {
642 : : /* Update advertisement timeout */
643 : 16 : eloop_cancel_timeout(wps_er_ap_timeout, er, ap);
644 : 16 : eloop_register_timeout(max_age, 0, wps_er_ap_timeout, er, ap);
645 : 16 : return;
646 : : }
647 : :
648 : 4 : ap = os_zalloc(sizeof(*ap));
649 [ - + ]: 4 : if (ap == NULL)
650 : 0 : return;
651 : 4 : dl_list_init(&ap->sta);
652 : 4 : ap->er = er;
653 : 4 : ap->id = ++er->next_ap_id;
654 : 4 : ap->location = os_strdup(location);
655 [ - + ]: 4 : if (ap->location == NULL) {
656 : 0 : os_free(ap);
657 : 0 : return;
658 : : }
659 : 4 : dl_list_add(&er->ap, &ap->list);
660 : :
661 : 4 : ap->addr.s_addr = addr->s_addr;
662 : 4 : os_memcpy(ap->uuid, uuid, WPS_UUID_LEN);
663 : 4 : eloop_register_timeout(max_age, 0, wps_er_ap_timeout, er, ap);
664 : :
665 : 4 : wpa_printf(MSG_DEBUG, "WPS ER: Added AP entry for %s (%s)",
666 : : inet_ntoa(ap->addr), ap->location);
667 : :
668 : : /* Fetch device description */
669 : 20 : ap->http = http_client_url(ap->location, NULL, 10000,
670 : : wps_er_http_dev_desc_cb, ap);
671 : : }
672 : :
673 : :
674 : 20 : void wps_er_ap_remove(struct wps_er *er, struct in_addr *addr)
675 : : {
676 : : struct wps_er_ap *ap;
677 [ + + ]: 20 : dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
678 [ + - ]: 3 : if (ap->addr.s_addr == addr->s_addr) {
679 : 3 : wps_er_ap_remove_entry(er, ap);
680 : 20 : return;
681 : : }
682 : : }
683 : : }
684 : :
685 : :
686 : 2 : static void wps_er_ap_remove_all(struct wps_er *er)
687 : : {
688 : : struct wps_er_ap *prev, *ap;
689 : : struct wps_er_ap_settings *prev_s, *s;
690 [ + + ]: 3 : dl_list_for_each_safe(ap, prev, &er->ap, struct wps_er_ap, list)
691 : 1 : wps_er_ap_remove_entry(er, ap);
692 [ + + ]: 3 : dl_list_for_each_safe(s, prev_s, &er->ap_settings,
693 : : struct wps_er_ap_settings, list)
694 : 1 : os_free(s);
695 : 2 : }
696 : :
697 : :
698 : 19 : static void http_put_date(struct wpabuf *buf)
699 : : {
700 : 19 : wpabuf_put_str(buf, "Date: ");
701 : 19 : format_date(buf);
702 : 19 : wpabuf_put_str(buf, "\r\n");
703 : 19 : }
704 : :
705 : :
706 : 0 : static void wps_er_http_resp_not_found(struct http_request *req)
707 : : {
708 : : struct wpabuf *buf;
709 : 0 : buf = wpabuf_alloc(200);
710 [ # # ]: 0 : if (buf == NULL) {
711 : 0 : http_request_deinit(req);
712 : 0 : return;
713 : : }
714 : :
715 : 0 : wpabuf_put_str(buf,
716 : : "HTTP/1.1 404 Not Found\r\n"
717 : : "Server: unspecified, UPnP/1.0, unspecified\r\n"
718 : : "Connection: close\r\n");
719 : 0 : http_put_date(buf);
720 : 0 : wpabuf_put_str(buf, "\r\n");
721 : 0 : http_request_send_and_deinit(req, buf);
722 : : }
723 : :
724 : :
725 : 19 : static void wps_er_http_resp_ok(struct http_request *req)
726 : : {
727 : : struct wpabuf *buf;
728 : 19 : buf = wpabuf_alloc(200);
729 [ - + ]: 19 : if (buf == NULL) {
730 : 0 : http_request_deinit(req);
731 : 19 : return;
732 : : }
733 : :
734 : 19 : wpabuf_put_str(buf,
735 : : "HTTP/1.1 200 OK\r\n"
736 : : "Server: unspecified, UPnP/1.0, unspecified\r\n"
737 : : "Connection: close\r\n"
738 : : "Content-Length: 0\r\n");
739 : 19 : http_put_date(buf);
740 : 19 : wpabuf_put_str(buf, "\r\n");
741 : 19 : http_request_send_and_deinit(req, buf);
742 : : }
743 : :
744 : :
745 : 0 : static void wps_er_sta_timeout(void *eloop_data, void *user_ctx)
746 : : {
747 : 0 : struct wps_er_sta *sta = eloop_data;
748 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: STA entry timed out");
749 : 0 : dl_list_del(&sta->list);
750 : 0 : wps_er_sta_free(sta);
751 : 0 : }
752 : :
753 : :
754 : 19 : static struct wps_er_sta * wps_er_add_sta_data(struct wps_er_ap *ap,
755 : : const u8 *addr,
756 : : struct wps_parse_attr *attr,
757 : : int probe_req)
758 : : {
759 : 19 : struct wps_er_sta *sta = wps_er_sta_get(ap, addr, NULL);
760 : 19 : int new_sta = 0;
761 : : int m1;
762 : :
763 [ + + ][ + - ]: 19 : m1 = !probe_req && attr->msg_type && *attr->msg_type == WPS_M1;
[ + + ]
764 : :
765 [ + + ]: 19 : if (sta == NULL) {
766 : : /*
767 : : * Only allow new STA entry to be added based on Probe Request
768 : : * or M1. This will filter out bogus events and anything that
769 : : * may have been ongoing at the time ER subscribed for events.
770 : : */
771 [ + + ][ + - ]: 6 : if (!probe_req && !m1)
772 : 1 : return NULL;
773 : :
774 : 5 : sta = os_zalloc(sizeof(*sta));
775 [ - + ]: 5 : if (sta == NULL)
776 : 0 : return NULL;
777 : 5 : os_memcpy(sta->addr, addr, ETH_ALEN);
778 : 5 : sta->ap = ap;
779 : 5 : dl_list_add(&ap->sta, &sta->list);
780 : 5 : new_sta = 1;
781 : : }
782 : :
783 [ + + ]: 18 : if (m1)
784 : 2 : sta->m1_received = 1;
785 : :
786 [ + + ][ + + ]: 18 : if (attr->config_methods && (!probe_req || !sta->m1_received))
[ + - ]
787 : 10 : sta->config_methods = WPA_GET_BE16(attr->config_methods);
788 [ + + ][ + + ]: 18 : if (attr->uuid_e && (!probe_req || !sta->m1_received))
[ + - ]
789 : 10 : os_memcpy(sta->uuid, attr->uuid_e, WPS_UUID_LEN);
790 [ + + ][ + + ]: 18 : if (attr->primary_dev_type && (!probe_req || !sta->m1_received))
[ + - ]
791 : 10 : os_memcpy(sta->pri_dev_type, attr->primary_dev_type, 8);
792 [ + + ][ + + ]: 18 : if (attr->dev_password_id && (!probe_req || !sta->m1_received))
[ + - ]
793 : 10 : sta->dev_passwd_id = WPA_GET_BE16(attr->dev_password_id);
794 : :
795 [ + + ]: 18 : if (attr->manufacturer) {
796 : 10 : os_free(sta->manufacturer);
797 : 10 : sta->manufacturer = dup_binstr(attr->manufacturer,
798 : : attr->manufacturer_len);
799 : : }
800 : :
801 [ + + ]: 18 : if (attr->model_name) {
802 : 10 : os_free(sta->model_name);
803 : 10 : sta->model_name = dup_binstr(attr->model_name,
804 : : attr->model_name_len);
805 : : }
806 : :
807 [ + + ]: 18 : if (attr->model_number) {
808 : 10 : os_free(sta->model_number);
809 : 10 : sta->model_number = dup_binstr(attr->model_number,
810 : : attr->model_number_len);
811 : : }
812 : :
813 [ + + ]: 18 : if (attr->serial_number) {
814 : 2 : os_free(sta->serial_number);
815 : 2 : sta->serial_number = dup_binstr(attr->serial_number,
816 : : attr->serial_number_len);
817 : : }
818 : :
819 [ + + ]: 18 : if (attr->dev_name) {
820 : 10 : os_free(sta->dev_name);
821 : 10 : sta->dev_name = dup_binstr(attr->dev_name, attr->dev_name_len);
822 : : }
823 : :
824 : 18 : eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL);
825 : 18 : eloop_register_timeout(300, 0, wps_er_sta_timeout, sta, NULL);
826 : :
827 [ + + ][ + + ]: 18 : if (m1 || new_sta)
828 : 7 : wps_er_sta_event(ap->er->wps, sta, WPS_EV_ER_ENROLLEE_ADD);
829 : :
830 : 19 : return sta;
831 : : }
832 : :
833 : :
834 : 8 : static void wps_er_process_wlanevent_probe_req(struct wps_er_ap *ap,
835 : : const u8 *addr,
836 : : struct wpabuf *msg)
837 : : {
838 : : struct wps_parse_attr attr;
839 : :
840 : 8 : wpa_printf(MSG_DEBUG, "WPS ER: WLANEvent - Probe Request - from "
841 : 48 : MACSTR, MAC2STR(addr));
842 : 8 : wpa_hexdump_buf(MSG_MSGDUMP, "WPS ER: WLANEvent - Enrollee's message "
843 : : "(TLVs from Probe Request)", msg);
844 : :
845 [ - + ]: 8 : if (wps_validate_probe_req(msg, addr) < 0) {
846 : 0 : wpa_printf(MSG_INFO, "WPS-STRICT: ER: Ignore invalid proxied "
847 : 0 : "Probe Request frame from " MACSTR, MAC2STR(addr));
848 : 0 : return;
849 : : }
850 : :
851 [ - + ]: 8 : if (wps_parse_msg(msg, &attr) < 0) {
852 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse TLVs in "
853 : : "WLANEvent message");
854 : 0 : return;
855 : : }
856 : :
857 : 8 : wps_er_add_sta_data(ap, addr, &attr, 1);
858 : 8 : wps_registrar_probe_req_rx(ap->er->wps->registrar, addr, msg, 0);
859 : : }
860 : :
861 : :
862 : 8 : static void wps_er_http_put_wlan_response_cb(void *ctx, struct http_client *c,
863 : : enum http_client_event event)
864 : : {
865 : 8 : struct wps_er_sta *sta = ctx;
866 : :
867 [ + - - ]: 8 : switch (event) {
868 : : case HTTP_CLIENT_OK:
869 : 8 : wpa_printf(MSG_DEBUG, "WPS ER: PutWLANResponse OK");
870 : 8 : break;
871 : : case HTTP_CLIENT_FAILED:
872 : : case HTTP_CLIENT_INVALID_REPLY:
873 : : case HTTP_CLIENT_TIMEOUT:
874 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: PutWLANResponse failed");
875 : 0 : break;
876 : : }
877 : 8 : http_client_free(sta->http);
878 : 8 : sta->http = NULL;
879 : 8 : }
880 : :
881 : :
882 : : static const char *soap_prefix =
883 : : "<?xml version=\"1.0\"?>\n"
884 : : "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
885 : : "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
886 : : "<s:Body>\n";
887 : : static const char *soap_postfix =
888 : : "</s:Body>\n</s:Envelope>\n";
889 : : static const char *urn_wfawlanconfig =
890 : : "urn:schemas-wifialliance-org:service:WFAWLANConfig:1";
891 : :
892 : 31 : static struct wpabuf * wps_er_soap_hdr(const struct wpabuf *msg,
893 : : const char *name, const char *arg_name,
894 : : const char *path,
895 : : const struct sockaddr_in *dst,
896 : : char **len_ptr, char **body_ptr)
897 : : {
898 : : unsigned char *encoded;
899 : : size_t encoded_len;
900 : : struct wpabuf *buf;
901 : :
902 [ + + ]: 31 : if (msg) {
903 : 25 : encoded = base64_encode(wpabuf_head(msg), wpabuf_len(msg),
904 : : &encoded_len);
905 [ - + ]: 25 : if (encoded == NULL)
906 : 0 : return NULL;
907 : : } else {
908 : 6 : encoded = NULL;
909 : 6 : encoded_len = 0;
910 : : }
911 : :
912 : 31 : buf = wpabuf_alloc(1000 + encoded_len);
913 [ - + ]: 31 : if (buf == NULL) {
914 : 0 : os_free(encoded);
915 : 0 : return NULL;
916 : : }
917 : :
918 : 31 : wpabuf_printf(buf,
919 : : "POST %s HTTP/1.1\r\n"
920 : : "Host: %s:%d\r\n"
921 : : "Content-Type: text/xml; charset=\"utf-8\"\r\n"
922 : : "Content-Length: ",
923 : 31 : path, inet_ntoa(dst->sin_addr), ntohs(dst->sin_port));
924 : :
925 : 31 : *len_ptr = wpabuf_put(buf, 0);
926 : 31 : wpabuf_printf(buf,
927 : : " \r\n"
928 : : "SOAPACTION: \"%s#%s\"\r\n"
929 : : "\r\n",
930 : : urn_wfawlanconfig, name);
931 : :
932 : 31 : *body_ptr = wpabuf_put(buf, 0);
933 : :
934 : 31 : wpabuf_put_str(buf, soap_prefix);
935 : 31 : wpabuf_printf(buf, "<u:%s xmlns:u=\"", name);
936 : 31 : wpabuf_put_str(buf, urn_wfawlanconfig);
937 : 31 : wpabuf_put_str(buf, "\">\n");
938 [ + + ]: 31 : if (encoded) {
939 : 25 : wpabuf_printf(buf, "<%s>%s</%s>\n",
940 : : arg_name, (char *) encoded, arg_name);
941 : 25 : os_free(encoded);
942 : : }
943 : :
944 : 31 : return buf;
945 : : }
946 : :
947 : :
948 : 31 : static void wps_er_soap_end(struct wpabuf *buf, const char *name,
949 : : char *len_ptr, char *body_ptr)
950 : : {
951 : : char len_buf[10];
952 : 31 : wpabuf_printf(buf, "</u:%s>\n", name);
953 : 31 : wpabuf_put_str(buf, soap_postfix);
954 : 31 : os_snprintf(len_buf, sizeof(len_buf), "%d",
955 : 31 : (int) ((char *) wpabuf_put(buf, 0) - body_ptr));
956 : 31 : os_memcpy(len_ptr, len_buf, os_strlen(len_buf));
957 : 31 : }
958 : :
959 : :
960 : 8 : static void wps_er_sta_send_msg(struct wps_er_sta *sta, struct wpabuf *msg)
961 : : {
962 : : struct wpabuf *buf;
963 : : char *len_ptr, *body_ptr;
964 : : struct sockaddr_in dst;
965 : : char *url, *path;
966 : :
967 [ - + ]: 8 : if (sta->http) {
968 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request for STA - "
969 : : "ignore new request");
970 : 0 : wpabuf_free(msg);
971 : 0 : return;
972 : : }
973 : :
974 [ - + ]: 8 : if (sta->ap->control_url == NULL) {
975 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
976 : 0 : wpabuf_free(msg);
977 : 0 : return;
978 : : }
979 : :
980 : 8 : url = http_client_url_parse(sta->ap->control_url, &dst, &path);
981 [ - + ]: 8 : if (url == NULL) {
982 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
983 : 0 : wpabuf_free(msg);
984 : 0 : return;
985 : : }
986 : :
987 : 8 : buf = wps_er_soap_hdr(msg, "PutWLANResponse", "NewMessage", path, &dst,
988 : : &len_ptr, &body_ptr);
989 : 8 : wpabuf_free(msg);
990 : 8 : os_free(url);
991 [ - + ]: 8 : if (buf == NULL)
992 : 0 : return;
993 : 8 : wpabuf_printf(buf, "<NewWLANEventType>%d</NewWLANEventType>\n",
994 : : UPNP_WPS_WLANEVENT_TYPE_EAP);
995 : 8 : wpabuf_printf(buf, "<NewWLANEventMAC>" MACSTR "</NewWLANEventMAC>\n",
996 : 48 : MAC2STR(sta->addr));
997 : :
998 : 8 : wps_er_soap_end(buf, "PutWLANResponse", len_ptr, body_ptr);
999 : :
1000 : 8 : sta->http = http_client_addr(&dst, buf, 1000,
1001 : : wps_er_http_put_wlan_response_cb, sta);
1002 [ - + ]: 8 : if (sta->http == NULL)
1003 : 8 : wpabuf_free(buf);
1004 : : }
1005 : :
1006 : :
1007 : 10 : static void wps_er_sta_process(struct wps_er_sta *sta, struct wpabuf *msg,
1008 : : enum wsc_op_code op_code)
1009 : : {
1010 : : enum wps_process_res res;
1011 : :
1012 : 10 : res = wps_process_msg(sta->wps, op_code, msg);
1013 [ + + ]: 10 : if (res == WPS_CONTINUE) {
1014 : 8 : struct wpabuf *next = wps_get_msg(sta->wps, &op_code);
1015 [ + - ]: 8 : if (next)
1016 : 8 : wps_er_sta_send_msg(sta, next);
1017 : : } else {
1018 [ + - ]: 2 : wpa_printf(MSG_DEBUG, "WPS ER: Protocol run %s with the "
1019 : : "enrollee (res=%d)",
1020 : : res == WPS_DONE ? "succeeded" : "failed", res);
1021 : 2 : wps_deinit(sta->wps);
1022 : 2 : sta->wps = NULL;
1023 [ + - ]: 2 : if (res == WPS_DONE) {
1024 : : /* Remove the STA entry after short timeout */
1025 : 2 : eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL);
1026 : 2 : eloop_register_timeout(10, 0, wps_er_sta_timeout, sta,
1027 : : NULL);
1028 : : }
1029 : : }
1030 : 10 : }
1031 : :
1032 : :
1033 : 2 : static void wps_er_sta_start(struct wps_er_sta *sta, struct wpabuf *msg)
1034 : : {
1035 : : struct wps_config cfg;
1036 : :
1037 [ - + ]: 2 : if (sta->wps)
1038 : 0 : wps_deinit(sta->wps);
1039 : :
1040 : 2 : os_memset(&cfg, 0, sizeof(cfg));
1041 : 2 : cfg.wps = sta->ap->er->wps;
1042 : 2 : cfg.registrar = 1;
1043 : 2 : cfg.peer_addr = sta->addr;
1044 : :
1045 : 2 : sta->wps = wps_init(&cfg);
1046 [ - + ]: 2 : if (sta->wps == NULL)
1047 : 2 : return;
1048 : 2 : sta->wps->er = 1;
1049 : 2 : sta->wps->use_cred = sta->ap->ap_settings;
1050 [ + - ]: 2 : if (sta->ap->ap_settings) {
1051 : 2 : os_free(sta->cred);
1052 : 2 : sta->cred = os_malloc(sizeof(*sta->cred));
1053 [ + - ]: 2 : if (sta->cred) {
1054 : 2 : os_memcpy(sta->cred, sta->ap->ap_settings,
1055 : : sizeof(*sta->cred));
1056 : 2 : sta->cred->cred_attr = NULL;
1057 : 2 : os_memcpy(sta->cred->mac_addr, sta->addr, ETH_ALEN);
1058 : 2 : sta->wps->use_cred = sta->cred;
1059 : : }
1060 : : }
1061 : :
1062 : 2 : wps_er_sta_process(sta, msg, WSC_MSG);
1063 : : }
1064 : :
1065 : :
1066 : 11 : static void wps_er_process_wlanevent_eap(struct wps_er_ap *ap, const u8 *addr,
1067 : : struct wpabuf *msg)
1068 : : {
1069 : : struct wps_parse_attr attr;
1070 : : struct wps_er_sta *sta;
1071 : :
1072 : 11 : wpa_printf(MSG_DEBUG, "WPS ER: WLANEvent - EAP - from " MACSTR,
1073 : 66 : MAC2STR(addr));
1074 : 11 : wpa_hexdump_buf(MSG_MSGDUMP, "WPS ER: WLANEvent - Enrollee's message "
1075 : : "(TLVs from EAP-WSC)", msg);
1076 : :
1077 [ - + ]: 11 : if (wps_parse_msg(msg, &attr) < 0) {
1078 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse TLVs in "
1079 : : "WLANEvent message");
1080 : 0 : return;
1081 : : }
1082 : :
1083 : 11 : sta = wps_er_add_sta_data(ap, addr, &attr, 0);
1084 [ + + ]: 11 : if (sta == NULL)
1085 : 1 : return;
1086 : :
1087 [ + - ][ + + ]: 10 : if (attr.msg_type && *attr.msg_type == WPS_M1)
1088 : 2 : wps_er_sta_start(sta, msg);
1089 [ + - ]: 8 : else if (sta->wps) {
1090 : 8 : enum wsc_op_code op_code = WSC_MSG;
1091 [ + - ]: 8 : if (attr.msg_type) {
1092 [ - - + + ]: 8 : switch (*attr.msg_type) {
1093 : : case WPS_WSC_ACK:
1094 : 0 : op_code = WSC_ACK;
1095 : 0 : break;
1096 : : case WPS_WSC_NACK:
1097 : 0 : op_code = WSC_NACK;
1098 : 0 : break;
1099 : : case WPS_WSC_DONE:
1100 : 2 : op_code = WSC_Done;
1101 : 2 : break;
1102 : : }
1103 : : }
1104 : 11 : wps_er_sta_process(sta, msg, op_code);
1105 : : }
1106 : : }
1107 : :
1108 : :
1109 : 19 : static void wps_er_process_wlanevent(struct wps_er_ap *ap,
1110 : : struct wpabuf *event)
1111 : : {
1112 : : u8 *data;
1113 : : u8 wlan_event_type;
1114 : : u8 wlan_event_mac[ETH_ALEN];
1115 : : struct wpabuf msg;
1116 : :
1117 : 19 : wpa_hexdump(MSG_MSGDUMP, "WPS ER: Received WLANEvent",
1118 : : wpabuf_head(event), wpabuf_len(event));
1119 [ - + ]: 19 : if (wpabuf_len(event) < 1 + 17) {
1120 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Too short WLANEvent");
1121 : 0 : return;
1122 : : }
1123 : :
1124 : 19 : data = wpabuf_mhead(event);
1125 : 19 : wlan_event_type = data[0];
1126 [ - + ]: 19 : if (hwaddr_aton((char *) data + 1, wlan_event_mac) < 0) {
1127 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Invalid WLANEventMAC in "
1128 : : "WLANEvent");
1129 : 0 : return;
1130 : : }
1131 : :
1132 : 19 : wpabuf_set(&msg, data + 1 + 17, wpabuf_len(event) - (1 + 17));
1133 : :
1134 [ + + - ]: 19 : switch (wlan_event_type) {
1135 : : case 1:
1136 : 8 : wps_er_process_wlanevent_probe_req(ap, wlan_event_mac, &msg);
1137 : 8 : break;
1138 : : case 2:
1139 : 11 : wps_er_process_wlanevent_eap(ap, wlan_event_mac, &msg);
1140 : 11 : break;
1141 : : default:
1142 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Unknown WLANEventType %d",
1143 : : wlan_event_type);
1144 : 19 : break;
1145 : : }
1146 : : }
1147 : :
1148 : :
1149 : 19 : static void wps_er_http_event(struct wps_er *er, struct http_request *req,
1150 : : unsigned int ap_id)
1151 : : {
1152 : 19 : struct wps_er_ap *ap = wps_er_ap_get_id(er, ap_id);
1153 : : struct wpabuf *event;
1154 : : enum http_reply_code ret;
1155 : :
1156 [ - + ]: 19 : if (ap == NULL) {
1157 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: HTTP event from unknown AP id "
1158 : : "%u", ap_id);
1159 : 0 : wps_er_http_resp_not_found(req);
1160 : 0 : return;
1161 : : }
1162 : 19 : wpa_printf(MSG_MSGDUMP, "WPS ER: HTTP event from AP id %u: %s",
1163 : : ap_id, http_request_get_data(req));
1164 : :
1165 : 19 : event = xml_get_base64_item(http_request_get_data(req), "WLANEvent",
1166 : : &ret);
1167 [ - + ]: 19 : if (event == NULL) {
1168 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Could not extract WLANEvent "
1169 : : "from the event notification");
1170 : : /*
1171 : : * Reply with OK anyway to avoid getting unregistered from
1172 : : * events.
1173 : : */
1174 : 0 : wps_er_http_resp_ok(req);
1175 : 0 : return;
1176 : : }
1177 : :
1178 : 19 : wps_er_process_wlanevent(ap, event);
1179 : :
1180 : 19 : wpabuf_free(event);
1181 : 19 : wps_er_http_resp_ok(req);
1182 : : }
1183 : :
1184 : :
1185 : 19 : static void wps_er_http_notify(struct wps_er *er, struct http_request *req)
1186 : : {
1187 : 19 : char *uri = http_request_get_uri(req);
1188 : :
1189 [ + - ]: 19 : if (os_strncmp(uri, "/event/", 7) == 0) {
1190 : : unsigned int event_id;
1191 : : char *pos;
1192 : 19 : event_id = atoi(uri + 7);
1193 [ - + ]: 19 : if (event_id != er->event_id) {
1194 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: HTTP event for an "
1195 : : "unknown event id %u", event_id);
1196 : 0 : return;
1197 : : }
1198 : 19 : pos = os_strchr(uri + 7, '/');
1199 [ - + ]: 19 : if (pos == NULL)
1200 : 0 : return;
1201 : 19 : pos++;
1202 : 19 : wps_er_http_event(er, req, atoi(pos));
1203 : : } else {
1204 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Unknown HTTP NOTIFY for '%s'",
1205 : : uri);
1206 : 19 : wps_er_http_resp_not_found(req);
1207 : : }
1208 : : }
1209 : :
1210 : :
1211 : 19 : static void wps_er_http_req(void *ctx, struct http_request *req)
1212 : : {
1213 : 19 : struct wps_er *er = ctx;
1214 : 19 : struct sockaddr_in *cli = http_request_get_cli_addr(req);
1215 : 19 : enum httpread_hdr_type type = http_request_get_type(req);
1216 : : struct wpabuf *buf;
1217 : :
1218 : 19 : wpa_printf(MSG_DEBUG, "WPS ER: HTTP request: '%s' (type %d) from "
1219 : : "%s:%d",
1220 : : http_request_get_uri(req), type,
1221 : 19 : inet_ntoa(cli->sin_addr), ntohs(cli->sin_port));
1222 : :
1223 [ + - ]: 19 : switch (type) {
1224 : : case HTTPREAD_HDR_TYPE_NOTIFY:
1225 : 19 : wps_er_http_notify(er, req);
1226 : 19 : break;
1227 : : default:
1228 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Unsupported HTTP request type "
1229 : : "%d", type);
1230 : 0 : buf = wpabuf_alloc(200);
1231 [ # # ]: 0 : if (buf == NULL) {
1232 : 0 : http_request_deinit(req);
1233 : 19 : return;
1234 : : }
1235 : 0 : wpabuf_put_str(buf,
1236 : : "HTTP/1.1 501 Unimplemented\r\n"
1237 : : "Connection: close\r\n");
1238 : 0 : http_put_date(buf);
1239 : 0 : wpabuf_put_str(buf, "\r\n");
1240 : 0 : http_request_send_and_deinit(req, buf);
1241 : 0 : break;
1242 : : }
1243 : : }
1244 : :
1245 : :
1246 : : struct wps_er *
1247 : 2 : wps_er_init(struct wps_context *wps, const char *ifname, const char *filter)
1248 : : {
1249 : : struct wps_er *er;
1250 : : struct in_addr addr;
1251 : :
1252 : 2 : er = os_zalloc(sizeof(*er));
1253 [ - + ]: 2 : if (er == NULL)
1254 : 0 : return NULL;
1255 : 2 : dl_list_init(&er->ap);
1256 : 2 : dl_list_init(&er->ap_unsubscribing);
1257 : 2 : dl_list_init(&er->ap_settings);
1258 : :
1259 : 2 : er->multicast_sd = -1;
1260 : 2 : er->ssdp_sd = -1;
1261 : :
1262 : 2 : os_strlcpy(er->ifname, ifname, sizeof(er->ifname));
1263 : 2 : er->wps = wps;
1264 [ - + ]: 2 : if (os_get_random((unsigned char *) &er->event_id,
1265 : : sizeof(er->event_id)) < 0) {
1266 : 0 : wps_er_deinit(er, NULL, NULL);
1267 : 0 : return NULL;
1268 : : }
1269 : : /* Limit event_id to < 32 bits to avoid issues with atoi() */
1270 : 2 : er->event_id &= 0x0fffffff;
1271 : :
1272 [ + - ][ + - ]: 2 : if (filter && os_strncmp(filter, "ifname=", 7) == 0) {
1273 : : const char *pos, *end;
1274 : 2 : pos = filter + 7;
1275 : 2 : end = os_strchr(pos, ' ');
1276 [ - + ]: 2 : if (end) {
1277 : 0 : size_t len = end - pos;
1278 [ # # ]: 0 : os_strlcpy(er->ifname, pos, len < sizeof(er->ifname) ?
1279 : : len + 1 : sizeof(er->ifname));
1280 : 0 : filter = end + 1;
1281 : : } else {
1282 : 2 : os_strlcpy(er->ifname, pos, sizeof(er->ifname));
1283 : 2 : filter = NULL;
1284 : : }
1285 : 2 : er->forced_ifname = 1;
1286 : : }
1287 : :
1288 [ - + ]: 2 : if (filter) {
1289 [ # # ]: 0 : if (inet_aton(filter, &er->filter_addr) == 0) {
1290 : 0 : wpa_printf(MSG_INFO, "WPS UPnP: Invalid filter "
1291 : : "address %s", filter);
1292 : 0 : wps_er_deinit(er, NULL, NULL);
1293 : 0 : return NULL;
1294 : : }
1295 : 0 : wpa_printf(MSG_DEBUG, "WPS UPnP: Only accepting connections "
1296 : : "with %s", filter);
1297 : : }
1298 [ - + ]: 2 : if (get_netif_info(er->ifname, &er->ip_addr, &er->ip_addr_text,
1299 : 2 : er->mac_addr)) {
1300 : 0 : wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address "
1301 : 0 : "for %s. Does it have IP address?", er->ifname);
1302 : 0 : wps_er_deinit(er, NULL, NULL);
1303 : 0 : return NULL;
1304 : : }
1305 : :
1306 [ - + ]: 2 : if (wps_er_ssdp_init(er) < 0) {
1307 : 0 : wpa_printf(MSG_INFO, "WPS UPnP: SSDP initialization failed");
1308 : 0 : wps_er_deinit(er, NULL, NULL);
1309 : 0 : return NULL;
1310 : : }
1311 : :
1312 : 2 : addr.s_addr = er->ip_addr;
1313 : 2 : er->http_srv = http_server_init(&addr, -1, wps_er_http_req, er);
1314 [ - + ]: 2 : if (er->http_srv == NULL) {
1315 : 0 : wpa_printf(MSG_INFO, "WPS UPnP: HTTP initialization failed");
1316 : 0 : wps_er_deinit(er, NULL, NULL);
1317 : 0 : return NULL;
1318 : : }
1319 : 2 : er->http_port = http_server_get_port(er->http_srv);
1320 : :
1321 : 2 : wpa_printf(MSG_DEBUG, "WPS ER: Start (ifname=%s ip_addr=%s)",
1322 : 2 : er->ifname, er->ip_addr_text);
1323 : :
1324 : 2 : return er;
1325 : : }
1326 : :
1327 : :
1328 : 1 : void wps_er_refresh(struct wps_er *er)
1329 : : {
1330 : : struct wps_er_ap *ap;
1331 : : struct wps_er_sta *sta;
1332 : :
1333 [ + + ]: 2 : dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
1334 : 1 : wps_er_ap_event(er->wps, ap, WPS_EV_ER_AP_ADD);
1335 [ + + ]: 2 : dl_list_for_each(sta, &ap->sta, struct wps_er_sta, list)
1336 : 1 : wps_er_sta_event(er->wps, sta, WPS_EV_ER_ENROLLEE_ADD);
1337 : : }
1338 : :
1339 : 1 : wps_er_send_ssdp_msearch(er);
1340 : 1 : }
1341 : :
1342 : :
1343 : 2 : static void wps_er_deinit_finish(void *eloop_data, void *user_ctx)
1344 : : {
1345 : 2 : struct wps_er *er = eloop_data;
1346 : : void (*deinit_done_cb)(void *ctx);
1347 : : void *deinit_done_ctx;
1348 : : struct wps_er_ap *ap, *tmp;
1349 : :
1350 : 2 : wpa_printf(MSG_DEBUG, "WPS ER: Finishing deinit");
1351 : :
1352 [ - + ]: 2 : dl_list_for_each_safe(ap, tmp, &er->ap_unsubscribing, struct wps_er_ap,
1353 : : list) {
1354 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: AP entry for %s (%s) still in ap_unsubscribing list - free it",
1355 : : inet_ntoa(ap->addr), ap->location);
1356 : 0 : dl_list_del(&ap->list);
1357 : 0 : wps_er_ap_free(ap);
1358 : : }
1359 : :
1360 : 2 : eloop_cancel_timeout(wps_er_deinit_finish, er, NULL);
1361 : 2 : deinit_done_cb = er->deinit_done_cb;
1362 : 2 : deinit_done_ctx = er->deinit_done_ctx;
1363 : 2 : os_free(er->ip_addr_text);
1364 : 2 : os_free(er);
1365 : :
1366 [ + + ]: 2 : if (deinit_done_cb)
1367 : 1 : deinit_done_cb(deinit_done_ctx);
1368 : 2 : }
1369 : :
1370 : :
1371 : 33 : void wps_er_deinit(struct wps_er *er, void (*cb)(void *ctx), void *ctx)
1372 : : {
1373 [ + + ]: 33 : if (er == NULL)
1374 : 33 : return;
1375 : 2 : http_server_deinit(er->http_srv);
1376 : 2 : wps_er_ap_remove_all(er);
1377 : 2 : wps_er_ssdp_deinit(er);
1378 [ + + ]: 2 : eloop_register_timeout(dl_list_empty(&er->ap_unsubscribing) ? 0 : 5, 0,
1379 : : wps_er_deinit_finish, er, NULL);
1380 : 2 : wpa_printf(MSG_DEBUG, "WPS ER: Finish deinit from timeout");
1381 : 2 : er->deinitializing = 1;
1382 : 2 : er->deinit_done_cb = cb;
1383 : 2 : er->deinit_done_ctx = ctx;
1384 : : }
1385 : :
1386 : :
1387 : 9 : static void wps_er_http_set_sel_reg_cb(void *ctx, struct http_client *c,
1388 : : enum http_client_event event)
1389 : : {
1390 : 9 : struct wps_er_ap *ap = ctx;
1391 : : union wps_event_data data;
1392 : :
1393 : 9 : os_memset(&data, 0, sizeof(data));
1394 : :
1395 [ + + - ]: 9 : switch (event) {
1396 : : case HTTP_CLIENT_OK:
1397 : 6 : wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar OK");
1398 : 6 : data.set_sel_reg.state = WPS_ER_SET_SEL_REG_DONE;
1399 : 6 : data.set_sel_reg.uuid = ap->uuid;
1400 : 6 : break;
1401 : : case HTTP_CLIENT_FAILED:
1402 : : case HTTP_CLIENT_INVALID_REPLY:
1403 : : case HTTP_CLIENT_TIMEOUT:
1404 : 3 : wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar failed");
1405 : 3 : data.set_sel_reg.state = WPS_ER_SET_SEL_REG_FAILED;
1406 : 3 : data.set_sel_reg.uuid = ap->uuid;
1407 : 3 : break;
1408 : : }
1409 : 9 : http_client_free(ap->http);
1410 : 9 : ap->http = NULL;
1411 : :
1412 [ + - ]: 9 : if (data.set_sel_reg.uuid)
1413 : 9 : ap->er->wps->event_cb(ap->er->wps->cb_ctx,
1414 : : WPS_EV_ER_SET_SELECTED_REGISTRAR, &data);
1415 : 9 : }
1416 : :
1417 : :
1418 : 14 : static void wps_er_send_set_sel_reg(struct wps_er_ap *ap, struct wpabuf *msg)
1419 : : {
1420 : : struct wpabuf *buf;
1421 : : char *len_ptr, *body_ptr;
1422 : : struct sockaddr_in dst;
1423 : : char *url, *path;
1424 : :
1425 [ - + ]: 14 : if (ap->control_url == NULL) {
1426 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
1427 : 0 : return;
1428 : : }
1429 : :
1430 [ + + ]: 14 : if (ap->http) {
1431 : 1 : wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request for AP - "
1432 : : "ignore new request");
1433 : 1 : return;
1434 : : }
1435 : :
1436 [ + + ]: 13 : if (ap->wps) {
1437 : 4 : wpa_printf(MSG_DEBUG, "WPS ER: Pending WPS operation for AP - "
1438 : : "skip SetSelectedRegistrar");
1439 : 4 : return;
1440 : : }
1441 : :
1442 : 9 : url = http_client_url_parse(ap->control_url, &dst, &path);
1443 [ - + ]: 9 : if (url == NULL) {
1444 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
1445 : 0 : return;
1446 : : }
1447 : :
1448 : 9 : buf = wps_er_soap_hdr(msg, "SetSelectedRegistrar", "NewMessage", path,
1449 : : &dst, &len_ptr, &body_ptr);
1450 : 9 : os_free(url);
1451 [ - + ]: 9 : if (buf == NULL)
1452 : 0 : return;
1453 : :
1454 : 9 : wps_er_soap_end(buf, "SetSelectedRegistrar", len_ptr, body_ptr);
1455 : :
1456 : 9 : ap->http = http_client_addr(&dst, buf, 1000,
1457 : : wps_er_http_set_sel_reg_cb, ap);
1458 [ - + ]: 9 : if (ap->http == NULL)
1459 : 14 : wpabuf_free(buf);
1460 : : }
1461 : :
1462 : :
1463 : 30 : static int wps_er_build_selected_registrar(struct wpabuf *msg, int sel_reg)
1464 : : {
1465 : 30 : wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR);
1466 : 30 : wpabuf_put_be16(msg, 1);
1467 : 30 : wpabuf_put_u8(msg, !!sel_reg);
1468 : 30 : return 0;
1469 : : }
1470 : :
1471 : :
1472 : 30 : static int wps_er_build_dev_password_id(struct wpabuf *msg, u16 dev_passwd_id)
1473 : : {
1474 : 30 : wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID);
1475 : 30 : wpabuf_put_be16(msg, 2);
1476 : 30 : wpabuf_put_be16(msg, dev_passwd_id);
1477 : 30 : return 0;
1478 : : }
1479 : :
1480 : :
1481 : 30 : static int wps_er_build_sel_reg_config_methods(struct wpabuf *msg,
1482 : : u16 sel_reg_config_methods)
1483 : : {
1484 : 30 : wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR_CONFIG_METHODS);
1485 : 30 : wpabuf_put_be16(msg, 2);
1486 : 30 : wpabuf_put_be16(msg, sel_reg_config_methods);
1487 : 30 : return 0;
1488 : : }
1489 : :
1490 : :
1491 : 30 : static int wps_er_build_uuid_r(struct wpabuf *msg, const u8 *uuid_r)
1492 : : {
1493 : : #ifdef CONFIG_WPS2
1494 : 30 : wpabuf_put_be16(msg, ATTR_UUID_R);
1495 : 30 : wpabuf_put_be16(msg, WPS_UUID_LEN);
1496 : 30 : wpabuf_put_data(msg, uuid_r, WPS_UUID_LEN);
1497 : : #endif /* CONFIG_WPS2 */
1498 : 30 : return 0;
1499 : : }
1500 : :
1501 : :
1502 : 32 : void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id,
1503 : : u16 sel_reg_config_methods)
1504 : : {
1505 : : struct wpabuf *msg;
1506 : : struct wps_er_ap *ap;
1507 : 32 : struct wps_registrar *reg = er->wps->registrar;
1508 : : const u8 *auth_macs;
1509 : : #ifdef CONFIG_WPS2
1510 : : u8 bcast[ETH_ALEN];
1511 : : #endif /* CONFIG_WPS2 */
1512 : : size_t count;
1513 : : union wps_event_data data;
1514 : :
1515 [ + + ]: 32 : if (er->skip_set_sel_reg) {
1516 : 2 : wpa_printf(MSG_DEBUG, "WPS ER: Skip SetSelectedRegistrar");
1517 : 2 : return;
1518 : : }
1519 : :
1520 : 30 : msg = wpabuf_alloc(500);
1521 [ - + ]: 30 : if (msg == NULL)
1522 : 0 : return;
1523 : :
1524 : 30 : auth_macs = wps_authorized_macs(reg, &count);
1525 : : #ifdef CONFIG_WPS2
1526 [ + + ]: 30 : if (count == 0) {
1527 : 16 : os_memset(bcast, 0xff, ETH_ALEN);
1528 : 16 : auth_macs = bcast;
1529 : 16 : count = 1;
1530 : : }
1531 : : #endif /* CONFIG_WPS2 */
1532 : :
1533 [ + - + - ]: 60 : if (wps_build_version(msg) ||
1534 [ + - ]: 60 : wps_er_build_selected_registrar(msg, sel_reg) ||
1535 [ + - ]: 60 : wps_er_build_dev_password_id(msg, dev_passwd_id) ||
1536 [ + - ]: 60 : wps_er_build_sel_reg_config_methods(msg, sel_reg_config_methods) ||
1537 [ - + ]: 60 : wps_build_wfa_ext(msg, 0, auth_macs, count) ||
1538 : 30 : wps_er_build_uuid_r(msg, er->wps->uuid)) {
1539 : 0 : wpabuf_free(msg);
1540 : 0 : return;
1541 : : }
1542 : :
1543 : 30 : os_memset(&data, 0, sizeof(data));
1544 : 30 : data.set_sel_reg.sel_reg = sel_reg;
1545 : 30 : data.set_sel_reg.dev_passwd_id = dev_passwd_id;
1546 : 30 : data.set_sel_reg.sel_reg_config_methods = sel_reg_config_methods;
1547 : 30 : data.set_sel_reg.state = WPS_ER_SET_SEL_REG_START;
1548 : :
1549 [ + + ]: 44 : dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
1550 [ + + ][ - + ]: 14 : if (er->set_sel_reg_uuid_filter &&
1551 : 1 : os_memcmp(ap->uuid, er->set_sel_reg_uuid_filter,
1552 : : WPS_UUID_LEN) != 0)
1553 : 0 : continue;
1554 : 14 : data.set_sel_reg.uuid = ap->uuid;
1555 : 14 : er->wps->event_cb(er->wps->cb_ctx,
1556 : : WPS_EV_ER_SET_SELECTED_REGISTRAR, &data);
1557 : 14 : wps_er_send_set_sel_reg(ap, msg);
1558 : : }
1559 : :
1560 : 32 : wpabuf_free(msg);
1561 : : }
1562 : :
1563 : :
1564 : 1 : int wps_er_pbc(struct wps_er *er, const u8 *uuid, const u8 *addr)
1565 : : {
1566 : : int res;
1567 : : struct wps_er_ap *ap;
1568 : :
1569 [ + - ][ - + ]: 1 : if (er == NULL || er->wps == NULL)
1570 : 0 : return -1;
1571 : :
1572 [ - + ]: 1 : if (wps_registrar_pbc_overlap(er->wps->registrar, NULL, NULL)) {
1573 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: PBC overlap - do not start PBC "
1574 : : "mode");
1575 : 0 : return -2;
1576 : : }
1577 : :
1578 [ - + ]: 1 : if (uuid)
1579 : 0 : ap = wps_er_ap_get(er, NULL, uuid, NULL);
1580 : : else
1581 : 1 : ap = NULL;
1582 [ + - ]: 1 : if (ap == NULL) {
1583 : 1 : struct wps_er_sta *sta = NULL;
1584 [ + - ]: 1 : dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
1585 : 1 : sta = wps_er_sta_get(ap, addr, uuid);
1586 [ + - ]: 1 : if (sta) {
1587 : 1 : uuid = ap->uuid;
1588 : 1 : break;
1589 : : }
1590 : : }
1591 [ - + ]: 1 : if (sta == NULL)
1592 : 0 : return -3; /* Unknown UUID */
1593 : : }
1594 : :
1595 [ - + ]: 1 : if (ap->ap_settings == NULL) {
1596 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: AP settings not known");
1597 : 0 : return -4;
1598 : : }
1599 : :
1600 : 1 : er->set_sel_reg_uuid_filter = uuid;
1601 : 1 : res = wps_registrar_button_pushed(er->wps->registrar, NULL);
1602 : 1 : er->set_sel_reg_uuid_filter = NULL;
1603 [ - + ]: 1 : if (res)
1604 : 0 : return -1;
1605 : :
1606 : 1 : return 0;
1607 : : }
1608 : :
1609 : :
1610 : 1 : static void wps_er_ap_settings_cb(void *ctx, const struct wps_credential *cred)
1611 : : {
1612 : 1 : struct wps_er_ap *ap = ctx;
1613 : : union wps_event_data data;
1614 : :
1615 : 1 : wpa_printf(MSG_DEBUG, "WPS ER: AP Settings received");
1616 : 1 : os_free(ap->ap_settings);
1617 : 1 : ap->ap_settings = os_malloc(sizeof(*cred));
1618 [ + - ]: 1 : if (ap->ap_settings) {
1619 : 1 : os_memcpy(ap->ap_settings, cred, sizeof(*cred));
1620 : 1 : ap->ap_settings->cred_attr = NULL;
1621 : : }
1622 : :
1623 : 1 : os_memset(&data, 0, sizeof(data));
1624 : 1 : data.ap_settings.uuid = ap->uuid;
1625 : 1 : data.ap_settings.cred = cred;
1626 : 1 : ap->er->wps->event_cb(ap->er->wps->cb_ctx, WPS_EV_ER_AP_SETTINGS,
1627 : : &data);
1628 : 1 : }
1629 : :
1630 : :
1631 : 0 : const u8 * wps_er_get_sta_uuid(struct wps_er *er, const u8 *addr)
1632 : : {
1633 : : struct wps_er_ap *ap;
1634 [ # # ]: 0 : dl_list_for_each(ap, &er->ap, struct wps_er_ap, list) {
1635 : : struct wps_er_sta *sta;
1636 : 0 : sta = wps_er_sta_get(ap, addr, NULL);
1637 [ # # ]: 0 : if (sta)
1638 : 0 : return sta->uuid;
1639 : : }
1640 : 0 : return NULL;
1641 : : }
1642 : :
1643 : :
1644 : 8 : static void wps_er_http_put_message_cb(void *ctx, struct http_client *c,
1645 : : enum http_client_event event)
1646 : : {
1647 : 8 : struct wps_er_ap *ap = ctx;
1648 : : struct wpabuf *reply;
1649 : 8 : char *msg = NULL;
1650 : :
1651 [ + + - ]: 8 : switch (event) {
1652 : : case HTTP_CLIENT_OK:
1653 : 7 : wpa_printf(MSG_DEBUG, "WPS ER: PutMessage OK");
1654 : 7 : reply = http_client_get_body(c);
1655 [ - + ]: 7 : if (reply == NULL)
1656 : 0 : break;
1657 : 7 : msg = os_zalloc(wpabuf_len(reply) + 1);
1658 [ - + ]: 7 : if (msg == NULL)
1659 : 0 : break;
1660 : 7 : os_memcpy(msg, wpabuf_head(reply), wpabuf_len(reply));
1661 : 7 : break;
1662 : : case HTTP_CLIENT_FAILED:
1663 : : case HTTP_CLIENT_INVALID_REPLY:
1664 : : case HTTP_CLIENT_TIMEOUT:
1665 : 1 : wpa_printf(MSG_DEBUG, "WPS ER: PutMessage failed");
1666 [ + - ]: 1 : if (ap->wps) {
1667 : 1 : wps_deinit(ap->wps);
1668 : 1 : ap->wps = NULL;
1669 : : }
1670 : 1 : break;
1671 : : }
1672 : 8 : http_client_free(ap->http);
1673 : 8 : ap->http = NULL;
1674 : :
1675 [ + + ]: 8 : if (msg) {
1676 : : struct wpabuf *buf;
1677 : : enum http_reply_code ret;
1678 : 7 : buf = xml_get_base64_item(msg, "NewOutMessage", &ret);
1679 : 7 : os_free(msg);
1680 [ - + ]: 7 : if (buf == NULL) {
1681 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Could not extract "
1682 : : "NewOutMessage from PutMessage response");
1683 : 0 : wps_deinit(ap->wps);
1684 : 0 : ap->wps = NULL;
1685 : 8 : return;
1686 : : }
1687 : 7 : wps_er_ap_process(ap, buf);
1688 : 7 : wpabuf_free(buf);
1689 : : }
1690 : : }
1691 : :
1692 : :
1693 : 8 : static void wps_er_ap_put_message(struct wps_er_ap *ap,
1694 : : const struct wpabuf *msg)
1695 : : {
1696 : : struct wpabuf *buf;
1697 : : char *len_ptr, *body_ptr;
1698 : : struct sockaddr_in dst;
1699 : : char *url, *path;
1700 : :
1701 [ - + ]: 8 : if (ap->http) {
1702 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP operation ongoing "
1703 : : "with the AP - cannot continue learn");
1704 : 0 : return;
1705 : : }
1706 : :
1707 [ - + ]: 8 : if (ap->control_url == NULL) {
1708 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
1709 : 0 : return;
1710 : : }
1711 : :
1712 : 8 : url = http_client_url_parse(ap->control_url, &dst, &path);
1713 [ - + ]: 8 : if (url == NULL) {
1714 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
1715 : 0 : return;
1716 : : }
1717 : :
1718 : 8 : buf = wps_er_soap_hdr(msg, "PutMessage", "NewInMessage", path, &dst,
1719 : : &len_ptr, &body_ptr);
1720 : 8 : os_free(url);
1721 [ - + ]: 8 : if (buf == NULL)
1722 : 0 : return;
1723 : :
1724 : 8 : wps_er_soap_end(buf, "PutMessage", len_ptr, body_ptr);
1725 : :
1726 : 8 : ap->http = http_client_addr(&dst, buf, 10000,
1727 : : wps_er_http_put_message_cb, ap);
1728 [ - + ]: 8 : if (ap->http == NULL)
1729 : 8 : wpabuf_free(buf);
1730 : : }
1731 : :
1732 : :
1733 : 9 : static void wps_er_ap_process(struct wps_er_ap *ap, struct wpabuf *msg)
1734 : : {
1735 : : enum wps_process_res res;
1736 : : struct wps_parse_attr attr;
1737 : : enum wsc_op_code op_code;
1738 : :
1739 : 9 : op_code = WSC_MSG;
1740 [ + - ][ + - ]: 9 : if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type) {
1741 [ - - + + ]: 9 : switch (*attr.msg_type) {
1742 : : case WPS_WSC_ACK:
1743 : 0 : op_code = WSC_ACK;
1744 : 0 : break;
1745 : : case WPS_WSC_NACK:
1746 : 0 : op_code = WSC_NACK;
1747 : 0 : break;
1748 : : case WPS_WSC_DONE:
1749 : 1 : op_code = WSC_Done;
1750 : 1 : break;
1751 : : }
1752 : : }
1753 : :
1754 : 9 : res = wps_process_msg(ap->wps, op_code, msg);
1755 [ + + ]: 9 : if (res == WPS_CONTINUE) {
1756 : 8 : struct wpabuf *next = wps_get_msg(ap->wps, &op_code);
1757 [ + - ]: 8 : if (next) {
1758 : 8 : wps_er_ap_put_message(ap, next);
1759 : 8 : wpabuf_free(next);
1760 : : } else {
1761 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Failed to build "
1762 : : "message");
1763 : 0 : wps_deinit(ap->wps);
1764 : 0 : ap->wps = NULL;
1765 : : }
1766 [ + - ]: 1 : } else if (res == WPS_DONE) {
1767 : 1 : wpa_printf(MSG_DEBUG, "WPS ER: Protocol run done");
1768 : 1 : wps_deinit(ap->wps);
1769 : 1 : ap->wps = NULL;
1770 : : } else {
1771 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Failed to process message from "
1772 : : "AP (res=%d)", res);
1773 : 0 : wps_deinit(ap->wps);
1774 : 0 : ap->wps = NULL;
1775 : : }
1776 : 9 : }
1777 : :
1778 : :
1779 : 1 : static void wps_er_ap_learn_m1(struct wps_er_ap *ap, struct wpabuf *m1)
1780 : : {
1781 : : struct wps_config cfg;
1782 : :
1783 [ - + ]: 1 : if (ap->wps) {
1784 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Protocol run already in "
1785 : : "progress with this AP");
1786 : 0 : return;
1787 : : }
1788 : :
1789 : 1 : os_memset(&cfg, 0, sizeof(cfg));
1790 : 1 : cfg.wps = ap->er->wps;
1791 : 1 : cfg.registrar = 1;
1792 : 1 : ap->wps = wps_init(&cfg);
1793 [ - + ]: 1 : if (ap->wps == NULL)
1794 : 0 : return;
1795 : 1 : ap->wps->ap_settings_cb = wps_er_ap_settings_cb;
1796 : 1 : ap->wps->ap_settings_cb_ctx = ap;
1797 : :
1798 : 1 : wps_er_ap_process(ap, m1);
1799 : : }
1800 : :
1801 : :
1802 : 5 : static void wps_er_ap_learn(struct wps_er_ap *ap, const char *dev_info)
1803 : : {
1804 : : struct wpabuf *info;
1805 : : enum http_reply_code ret;
1806 : :
1807 : 5 : wpa_printf(MSG_DEBUG, "WPS ER: Received GetDeviceInfo response (M1) "
1808 : : "from the AP");
1809 : 5 : info = xml_get_base64_item(dev_info, "NewDeviceInfo", &ret);
1810 [ - + ]: 5 : if (info == NULL) {
1811 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Could not extract "
1812 : : "NewDeviceInfo from GetDeviceInfo response");
1813 : 5 : return;
1814 : : }
1815 : :
1816 : 5 : ap->m1_handler(ap, info);
1817 : 5 : wpabuf_free(info);
1818 : : }
1819 : :
1820 : :
1821 : 6 : static void wps_er_http_get_dev_info_cb(void *ctx, struct http_client *c,
1822 : : enum http_client_event event)
1823 : : {
1824 : 6 : struct wps_er_ap *ap = ctx;
1825 : : struct wpabuf *reply;
1826 : 6 : char *dev_info = NULL;
1827 : :
1828 [ + + - ]: 6 : switch (event) {
1829 : : case HTTP_CLIENT_OK:
1830 : 5 : wpa_printf(MSG_DEBUG, "WPS ER: GetDeviceInfo OK");
1831 : 5 : reply = http_client_get_body(c);
1832 [ - + ]: 5 : if (reply == NULL)
1833 : 0 : break;
1834 : 5 : dev_info = os_zalloc(wpabuf_len(reply) + 1);
1835 [ - + ]: 5 : if (dev_info == NULL)
1836 : 0 : break;
1837 : 5 : os_memcpy(dev_info, wpabuf_head(reply), wpabuf_len(reply));
1838 : 5 : break;
1839 : : case HTTP_CLIENT_FAILED:
1840 : : case HTTP_CLIENT_INVALID_REPLY:
1841 : : case HTTP_CLIENT_TIMEOUT:
1842 : 1 : wpa_printf(MSG_DEBUG, "WPS ER: GetDeviceInfo failed");
1843 : 1 : break;
1844 : : }
1845 : 6 : http_client_free(ap->http);
1846 : 6 : ap->http = NULL;
1847 : :
1848 [ + + ]: 6 : if (dev_info) {
1849 : 5 : wps_er_ap_learn(ap, dev_info);
1850 : 5 : os_free(dev_info);
1851 : : }
1852 : 6 : }
1853 : :
1854 : :
1855 : 6 : static int wps_er_send_get_device_info(struct wps_er_ap *ap,
1856 : : void (*m1_handler)(struct wps_er_ap *ap,
1857 : : struct wpabuf *m1))
1858 : : {
1859 : : struct wpabuf *buf;
1860 : : char *len_ptr, *body_ptr;
1861 : : struct sockaddr_in dst;
1862 : : char *url, *path;
1863 : :
1864 [ - + ]: 6 : if (ap->http) {
1865 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP operation ongoing "
1866 : : "with the AP - cannot get device info");
1867 : 0 : return -1;
1868 : : }
1869 : :
1870 [ - + ]: 6 : if (ap->control_url == NULL) {
1871 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
1872 : 0 : return -1;
1873 : : }
1874 : :
1875 : 6 : url = http_client_url_parse(ap->control_url, &dst, &path);
1876 [ - + ]: 6 : if (url == NULL) {
1877 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
1878 : 0 : return -1;
1879 : : }
1880 : :
1881 : 6 : buf = wps_er_soap_hdr(NULL, "GetDeviceInfo", NULL, path, &dst,
1882 : : &len_ptr, &body_ptr);
1883 : 6 : os_free(url);
1884 [ - + ]: 6 : if (buf == NULL)
1885 : 0 : return -1;
1886 : :
1887 : 6 : wps_er_soap_end(buf, "GetDeviceInfo", len_ptr, body_ptr);
1888 : :
1889 : 6 : ap->http = http_client_addr(&dst, buf, 10000,
1890 : : wps_er_http_get_dev_info_cb, ap);
1891 [ - + ]: 6 : if (ap->http == NULL) {
1892 : 0 : wpabuf_free(buf);
1893 : 0 : return -1;
1894 : : }
1895 : :
1896 : 6 : ap->m1_handler = m1_handler;
1897 : :
1898 : 6 : return 0;
1899 : : }
1900 : :
1901 : :
1902 : 1 : int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *addr,
1903 : : const u8 *pin, size_t pin_len)
1904 : : {
1905 : : struct wps_er_ap *ap;
1906 : :
1907 [ - + ]: 1 : if (er == NULL)
1908 : 0 : return -1;
1909 : :
1910 : 1 : ap = wps_er_ap_get(er, NULL, uuid, addr);
1911 [ - + ]: 1 : if (ap == NULL) {
1912 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: AP not found for learn "
1913 : : "request");
1914 : 0 : return -1;
1915 : : }
1916 [ - + ]: 1 : if (uuid == NULL)
1917 : 0 : uuid = ap->uuid;
1918 [ - + ]: 1 : if (ap->wps) {
1919 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing "
1920 : : "with the AP - cannot start learn");
1921 : 0 : return -1;
1922 : : }
1923 : :
1924 [ - + ]: 1 : if (wps_er_send_get_device_info(ap, wps_er_ap_learn_m1) < 0)
1925 : 0 : return -1;
1926 : :
1927 : 1 : er->skip_set_sel_reg = 1;
1928 : 1 : wps_registrar_add_pin(er->wps->registrar, NULL, uuid, pin, pin_len, 0);
1929 : 1 : er->skip_set_sel_reg = 0;
1930 : :
1931 : 1 : return 0;
1932 : : }
1933 : :
1934 : :
1935 : 2 : int wps_er_set_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
1936 : : const struct wps_credential *cred)
1937 : : {
1938 : : struct wps_er_ap *ap;
1939 : :
1940 [ - + ]: 2 : if (er == NULL)
1941 : 0 : return -1;
1942 : :
1943 : 2 : ap = wps_er_ap_get(er, NULL, uuid, addr);
1944 [ - + ]: 2 : if (ap == NULL) {
1945 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: AP not found for set config "
1946 : : "request");
1947 : 0 : return -1;
1948 : : }
1949 : :
1950 : 2 : os_free(ap->ap_settings);
1951 : 2 : ap->ap_settings = os_malloc(sizeof(*cred));
1952 [ - + ]: 2 : if (ap->ap_settings == NULL)
1953 : 0 : return -1;
1954 : 2 : os_memcpy(ap->ap_settings, cred, sizeof(*cred));
1955 : 2 : ap->ap_settings->cred_attr = NULL;
1956 : 2 : wpa_printf(MSG_DEBUG, "WPS ER: Updated local AP settings based set "
1957 : : "config request");
1958 : :
1959 : 2 : return 0;
1960 : : }
1961 : :
1962 : :
1963 : 1 : static void wps_er_ap_config_m1(struct wps_er_ap *ap, struct wpabuf *m1)
1964 : : {
1965 : : struct wps_config cfg;
1966 : :
1967 [ - + ]: 1 : if (ap->wps) {
1968 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Protocol run already in "
1969 : : "progress with this AP");
1970 : 0 : return;
1971 : : }
1972 : :
1973 : 1 : os_memset(&cfg, 0, sizeof(cfg));
1974 : 1 : cfg.wps = ap->er->wps;
1975 : 1 : cfg.registrar = 1;
1976 : 1 : cfg.new_ap_settings = ap->ap_settings;
1977 : 1 : ap->wps = wps_init(&cfg);
1978 [ - + ]: 1 : if (ap->wps == NULL)
1979 : 0 : return;
1980 : 1 : ap->wps->ap_settings_cb = NULL;
1981 : 1 : ap->wps->ap_settings_cb_ctx = NULL;
1982 : :
1983 : 1 : wps_er_ap_process(ap, m1);
1984 : : }
1985 : :
1986 : :
1987 : 1 : int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *addr,
1988 : : const u8 *pin, size_t pin_len,
1989 : : const struct wps_credential *cred)
1990 : : {
1991 : : struct wps_er_ap *ap;
1992 : :
1993 [ - + ]: 1 : if (er == NULL)
1994 : 0 : return -1;
1995 : :
1996 : 1 : ap = wps_er_ap_get(er, NULL, uuid, addr);
1997 [ - + ]: 1 : if (ap == NULL) {
1998 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: AP not found for config "
1999 : : "request");
2000 : 0 : return -1;
2001 : : }
2002 [ + - ]: 1 : if (uuid == NULL)
2003 : 1 : uuid = ap->uuid;
2004 [ - + ]: 1 : if (ap->wps) {
2005 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing "
2006 : : "with the AP - cannot start config");
2007 : 0 : return -1;
2008 : : }
2009 : :
2010 : 1 : os_free(ap->ap_settings);
2011 : 1 : ap->ap_settings = os_malloc(sizeof(*cred));
2012 [ - + ]: 1 : if (ap->ap_settings == NULL)
2013 : 0 : return -1;
2014 : 1 : os_memcpy(ap->ap_settings, cred, sizeof(*cred));
2015 : 1 : ap->ap_settings->cred_attr = NULL;
2016 : :
2017 [ - + ]: 1 : if (wps_er_send_get_device_info(ap, wps_er_ap_config_m1) < 0)
2018 : 0 : return -1;
2019 : :
2020 : 1 : er->skip_set_sel_reg = 1;
2021 : 1 : wps_registrar_add_pin(er->wps->registrar, NULL, uuid, pin, pin_len, 0);
2022 : 1 : er->skip_set_sel_reg = 0;
2023 : :
2024 : 1 : return 0;
2025 : : }
2026 : :
2027 : :
2028 : : #ifdef CONFIG_WPS_NFC
2029 : :
2030 : 0 : struct wpabuf * wps_er_config_token_from_cred(struct wps_context *wps,
2031 : : struct wps_credential *cred)
2032 : : {
2033 : : struct wpabuf *ret;
2034 : : struct wps_data data;
2035 : :
2036 : 0 : ret = wpabuf_alloc(500);
2037 [ # # ]: 0 : if (ret == NULL)
2038 : 0 : return NULL;
2039 : :
2040 : 0 : os_memset(&data, 0, sizeof(data));
2041 : 0 : data.wps = wps;
2042 : 0 : data.use_cred = cred;
2043 [ # # # # ]: 0 : if (wps_build_version(ret) ||
2044 [ # # ]: 0 : wps_build_cred(&data, ret) ||
2045 : 0 : wps_build_wfa_ext(ret, 0, NULL, 0)) {
2046 : 0 : wpabuf_free(ret);
2047 : 0 : return NULL;
2048 : : }
2049 : :
2050 : 0 : return ret;
2051 : : }
2052 : :
2053 : :
2054 : 0 : struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid,
2055 : : const u8 *addr)
2056 : : {
2057 : : struct wps_er_ap *ap;
2058 : :
2059 [ # # ]: 0 : if (er == NULL)
2060 : 0 : return NULL;
2061 : :
2062 : 0 : ap = wps_er_ap_get(er, NULL, uuid, addr);
2063 [ # # ]: 0 : if (ap == NULL)
2064 : 0 : return NULL;
2065 [ # # ]: 0 : if (ap->ap_settings == NULL) {
2066 : 0 : wpa_printf(MSG_DEBUG, "WPS ER: No settings known for the "
2067 : : "selected AP");
2068 : 0 : return NULL;
2069 : : }
2070 : :
2071 : 0 : return wps_er_config_token_from_cred(er->wps, ap->ap_settings);
2072 : : }
2073 : :
2074 : : #endif /* CONFIG_WPS_NFC */
|