c88bee5d6290d679dc32441c260f67cd782eb256
[libeap.git] / src / wps / wps_er.c
1 /*
2  * Wi-Fi Protected Setup - External Registrar
3  * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14
15 #include "includes.h"
16
17 #include "common.h"
18 #include "base64.h"
19 #include "uuid.h"
20 #include "eloop.h"
21 #include "httpread.h"
22 #include "http_client.h"
23 #include "http_server.h"
24 #include "upnp_xml.h"
25 #include "wps_i.h"
26 #include "wps_upnp.h"
27 #include "wps_upnp_i.h"
28 #include "wps_er.h"
29
30
31 static void wps_er_ap_timeout(void *eloop_data, void *user_ctx);
32 static void wps_er_sta_timeout(void *eloop_data, void *user_ctx);
33 static void wps_er_ap_process(struct wps_er_ap *ap, struct wpabuf *msg);
34 static int wps_er_send_get_device_info(struct wps_er_ap *ap,
35                                        void (*m1_handler)(struct wps_er_ap *ap,
36                                                           struct wpabuf *m1));
37
38
39 static void wps_er_sta_event(struct wps_context *wps, struct wps_er_sta *sta,
40                              enum wps_event event)
41 {
42         union wps_event_data data;
43         struct wps_event_er_enrollee *ev = &data.enrollee;
44
45         if (wps->event_cb == NULL)
46                 return;
47
48         os_memset(&data, 0, sizeof(data));
49         ev->uuid = sta->uuid;
50         ev->mac_addr = sta->addr;
51         ev->m1_received = sta->m1_received;
52         ev->config_methods = sta->config_methods;
53         ev->dev_passwd_id = sta->dev_passwd_id;
54         ev->pri_dev_type = sta->pri_dev_type;
55         ev->dev_name = sta->dev_name;
56         ev->manufacturer = sta->manufacturer;
57         ev->model_name = sta->model_name;
58         ev->model_number = sta->model_number;
59         ev->serial_number = sta->serial_number;
60         wps->event_cb(wps->cb_ctx, event, &data);
61 }
62
63
64 static struct wps_er_sta * wps_er_sta_get(struct wps_er_ap *ap, const u8 *addr)
65 {
66         struct wps_er_sta *sta = ap->sta;
67         while (sta) {
68                 if (os_memcmp(sta->addr, addr, ETH_ALEN) == 0)
69                         return sta;
70                 sta = sta->next;
71         }
72         return NULL;
73 }
74
75
76 static void wps_er_sta_free(struct wps_er_sta *sta)
77 {
78         wps_er_sta_event(sta->ap->er->wps, sta, WPS_EV_ER_ENROLLEE_REMOVE);
79         if (sta->wps)
80                 wps_deinit(sta->wps);
81         os_free(sta->manufacturer);
82         os_free(sta->model_name);
83         os_free(sta->model_number);
84         os_free(sta->serial_number);
85         os_free(sta->dev_name);
86         http_client_free(sta->http);
87         eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL);
88         os_free(sta);
89 }
90
91
92 static void wps_er_sta_unlink(struct wps_er_sta *sta)
93 {
94         struct wps_er_sta *prev, *tmp;
95         struct wps_er_ap *ap = sta->ap;
96         tmp = ap->sta;
97         prev = NULL;
98         while (tmp) {
99                 if (tmp == sta) {
100                         if (prev)
101                                 prev->next = sta->next;
102                         else
103                                 ap->sta = sta->next;
104                         return;
105                 }
106                 prev = tmp;
107                 tmp = tmp->next;
108         }
109 }
110
111
112 static void wps_er_sta_remove_all(struct wps_er_ap *ap)
113 {
114         struct wps_er_sta *prev, *sta;
115
116         sta = ap->sta;
117         ap->sta = NULL;
118
119         while (sta) {
120                 prev = sta;
121                 sta = sta->next;
122                 wps_er_sta_free(prev);
123         }
124 }
125
126
127 static struct wps_er_ap * wps_er_ap_get(struct wps_er *er,
128                                         struct in_addr *addr, const u8 *uuid)
129 {
130         struct wps_er_ap *ap;
131         for (ap = er->ap; ap; ap = ap->next) {
132                 if ((addr == NULL || ap->addr.s_addr == addr->s_addr) &&
133                     (uuid == NULL ||
134                      os_memcmp(uuid, ap->uuid, WPS_UUID_LEN) == 0))
135                         break;
136         }
137         return ap;
138 }
139
140
141 static struct wps_er_ap * wps_er_ap_get_id(struct wps_er *er, unsigned int id)
142 {
143         struct wps_er_ap *ap;
144         for (ap = er->ap; ap; ap = ap->next) {
145                 if (ap->id == id)
146                         break;
147         }
148         return ap;
149 }
150
151
152 static void wps_er_ap_event(struct wps_context *wps, struct wps_er_ap *ap,
153                             enum wps_event event)
154 {
155         union wps_event_data data;
156         struct wps_event_er_ap *evap = &data.ap;
157
158         if (wps->event_cb == NULL)
159                 return;
160
161         os_memset(&data, 0, sizeof(data));
162         evap->uuid = ap->uuid;
163         evap->friendly_name = ap->friendly_name;
164         evap->manufacturer = ap->manufacturer;
165         evap->manufacturer_url = ap->manufacturer_url;
166         evap->model_description = ap->model_description;
167         evap->model_name = ap->model_name;
168         evap->model_number = ap->model_number;
169         evap->model_url = ap->model_url;
170         evap->serial_number = ap->serial_number;
171         evap->upc = ap->upc;
172         evap->pri_dev_type = ap->pri_dev_type;
173         evap->wps_state = ap->wps_state;
174         evap->mac_addr = ap->mac_addr;
175         wps->event_cb(wps->cb_ctx, event, &data);
176 }
177
178
179 static void wps_er_ap_free(struct wps_er *er, struct wps_er_ap *ap)
180 {
181         /* TODO: if ap->subscribed, unsubscribe from events if the AP is still
182          * alive */
183         wpa_printf(MSG_DEBUG, "WPS ER: Removing AP entry for %s (%s)",
184                    inet_ntoa(ap->addr), ap->location);
185         eloop_cancel_timeout(wps_er_ap_timeout, er, ap);
186         wps_er_ap_event(er->wps, ap, WPS_EV_ER_AP_REMOVE);
187         os_free(ap->location);
188         http_client_free(ap->http);
189         if (ap->wps)
190                 wps_deinit(ap->wps);
191
192         os_free(ap->friendly_name);
193         os_free(ap->manufacturer);
194         os_free(ap->manufacturer_url);
195         os_free(ap->model_description);
196         os_free(ap->model_name);
197         os_free(ap->model_number);
198         os_free(ap->model_url);
199         os_free(ap->serial_number);
200         os_free(ap->udn);
201         os_free(ap->upc);
202
203         os_free(ap->scpd_url);
204         os_free(ap->control_url);
205         os_free(ap->event_sub_url);
206
207         os_free(ap->ap_settings);
208
209         wps_er_sta_remove_all(ap);
210
211         os_free(ap);
212 }
213
214
215 static void wps_er_ap_unlink(struct wps_er *er, struct wps_er_ap *ap)
216 {
217         struct wps_er_ap *prev, *tmp;
218         tmp = er->ap;
219         prev = NULL;
220         while (tmp) {
221                 if (tmp == ap) {
222                         if (prev)
223                                 prev->next = ap->next;
224                         else
225                                 er->ap = ap->next;
226                         return;
227                 }
228                 prev = tmp;
229                 tmp = tmp->next;
230         }
231 }
232
233
234 static void wps_er_ap_timeout(void *eloop_data, void *user_ctx)
235 {
236         struct wps_er *er = eloop_data;
237         struct wps_er_ap *ap = user_ctx;
238         wpa_printf(MSG_DEBUG, "WPS ER: AP advertisement timed out");
239         wps_er_ap_unlink(er, ap);
240         wps_er_ap_free(er, ap);
241 }
242
243
244 static void wps_er_http_subscribe_cb(void *ctx, struct http_client *c,
245                                      enum http_client_event event)
246 {
247         struct wps_er_ap *ap = ctx;
248
249         switch (event) {
250         case HTTP_CLIENT_OK:
251                 wpa_printf(MSG_DEBUG, "WPS ER: Subscribed to events");
252                 wps_er_ap_event(ap->er->wps, ap, WPS_EV_ER_AP_ADD);
253                 break;
254         case HTTP_CLIENT_FAILED:
255         case HTTP_CLIENT_INVALID_REPLY:
256         case HTTP_CLIENT_TIMEOUT:
257                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to subscribe to events");
258                 break;
259         }
260         http_client_free(ap->http);
261         ap->http = NULL;
262 }
263
264
265 static void wps_er_subscribe(struct wps_er_ap *ap)
266 {
267         struct wpabuf *req;
268         struct sockaddr_in dst;
269         char *url, *path;
270
271         if (ap->event_sub_url == NULL) {
272                 wpa_printf(MSG_DEBUG, "WPS ER: No eventSubURL - cannot "
273                            "subscribe");
274                 return;
275         }
276         if (ap->http) {
277                 wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request - cannot "
278                            "send subscribe request");
279                 return;
280         }
281
282         url = http_client_url_parse(ap->event_sub_url, &dst, &path);
283         if (url == NULL) {
284                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse eventSubURL");
285                 return;
286         }
287
288         req = wpabuf_alloc(os_strlen(ap->event_sub_url) + 1000);
289         if (req == NULL) {
290                 os_free(url);
291                 return;
292         }
293         wpabuf_printf(req,
294                       "SUBSCRIBE %s HTTP/1.1\r\n"
295                       "HOST: %s:%d\r\n"
296                       "CALLBACK: <http://%s:%d/event/%u/%u>\r\n"
297                       "NT: upnp:event\r\n"
298                       "TIMEOUT: Second-%d\r\n"
299                       "\r\n",
300                       path, inet_ntoa(dst.sin_addr), ntohs(dst.sin_port),
301                       ap->er->ip_addr_text, ap->er->http_port,
302                       ap->er->event_id, ap->id, 1800);
303         os_free(url);
304         wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Subscription request",
305                           wpabuf_head(req), wpabuf_len(req));
306
307         ap->http = http_client_addr(&dst, req, 1000, wps_er_http_subscribe_cb,
308                                     ap);
309         if (ap->http == NULL)
310                 wpabuf_free(req);
311 }
312
313
314 static void wps_er_ap_get_m1(struct wps_er_ap *ap, struct wpabuf *m1)
315 {
316         struct wps_parse_attr attr;
317
318         if (wps_parse_msg(m1, &attr) < 0) {
319                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse M1");
320                 return;
321         }
322         if (attr.primary_dev_type)
323                 os_memcpy(ap->pri_dev_type, attr.primary_dev_type, 8);
324         if (attr.wps_state)
325                 ap->wps_state = *attr.wps_state;
326         if (attr.mac_addr)
327                 os_memcpy(ap->mac_addr, attr.mac_addr, ETH_ALEN);
328
329         wps_er_subscribe(ap);
330 }
331
332
333 static void wps_er_get_device_info(struct wps_er_ap *ap)
334 {
335         wps_er_send_get_device_info(ap, wps_er_ap_get_m1);
336 }
337
338
339 static void wps_er_parse_device_description(struct wps_er_ap *ap,
340                                             struct wpabuf *reply)
341 {
342         /* Note: reply includes null termination after the buffer data */
343         const char *data = wpabuf_head(reply);
344         char *pos;
345
346         wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Device info",
347                           wpabuf_head(reply), wpabuf_len(reply));
348
349         ap->friendly_name = xml_get_first_item(data, "friendlyName");
350         wpa_printf(MSG_DEBUG, "WPS ER: friendlyName='%s'", ap->friendly_name);
351
352         ap->manufacturer = xml_get_first_item(data, "manufacturer");
353         wpa_printf(MSG_DEBUG, "WPS ER: manufacturer='%s'", ap->manufacturer);
354
355         ap->manufacturer_url = xml_get_first_item(data, "manufacturerURL");
356         wpa_printf(MSG_DEBUG, "WPS ER: manufacturerURL='%s'",
357                    ap->manufacturer_url);
358
359         ap->model_description = xml_get_first_item(data, "modelDescription");
360         wpa_printf(MSG_DEBUG, "WPS ER: modelDescription='%s'",
361                    ap->model_description);
362
363         ap->model_name = xml_get_first_item(data, "modelName");
364         wpa_printf(MSG_DEBUG, "WPS ER: modelName='%s'", ap->model_name);
365
366         ap->model_number = xml_get_first_item(data, "modelNumber");
367         wpa_printf(MSG_DEBUG, "WPS ER: modelNumber='%s'", ap->model_number);
368
369         ap->model_url = xml_get_first_item(data, "modelURL");
370         wpa_printf(MSG_DEBUG, "WPS ER: modelURL='%s'", ap->model_url);
371
372         ap->serial_number = xml_get_first_item(data, "serialNumber");
373         wpa_printf(MSG_DEBUG, "WPS ER: serialNumber='%s'", ap->serial_number);
374
375         ap->udn = xml_get_first_item(data, "UDN");
376         wpa_printf(MSG_DEBUG, "WPS ER: UDN='%s'", ap->udn);
377         pos = os_strstr(ap->udn, "uuid:");
378         if (pos) {
379                 pos += 5;
380                 uuid_str2bin(pos, ap->uuid);
381         }
382
383         ap->upc = xml_get_first_item(data, "UPC");
384         wpa_printf(MSG_DEBUG, "WPS ER: UPC='%s'", ap->upc);
385
386         ap->scpd_url = http_link_update(
387                 xml_get_first_item(data, "SCPDURL"), ap->location);
388         wpa_printf(MSG_DEBUG, "WPS ER: SCPDURL='%s'", ap->scpd_url);
389
390         ap->control_url = http_link_update(
391                 xml_get_first_item(data, "controlURL"), ap->location);
392         wpa_printf(MSG_DEBUG, "WPS ER: controlURL='%s'", ap->control_url);
393
394         ap->event_sub_url = http_link_update(
395                 xml_get_first_item(data, "eventSubURL"), ap->location);
396         wpa_printf(MSG_DEBUG, "WPS ER: eventSubURL='%s'", ap->event_sub_url);
397 }
398
399
400 static void wps_er_http_dev_desc_cb(void *ctx, struct http_client *c,
401                                     enum http_client_event event)
402 {
403         struct wps_er_ap *ap = ctx;
404         struct wpabuf *reply;
405         int ok = 0;
406
407         switch (event) {
408         case HTTP_CLIENT_OK:
409                 reply = http_client_get_body(c);
410                 if (reply == NULL)
411                         break;
412                 wps_er_parse_device_description(ap, reply);
413                 ok = 1;
414                 break;
415         case HTTP_CLIENT_FAILED:
416         case HTTP_CLIENT_INVALID_REPLY:
417         case HTTP_CLIENT_TIMEOUT:
418                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to fetch device info");
419                 break;
420         }
421         http_client_free(ap->http);
422         ap->http = NULL;
423         if (ok)
424                 wps_er_get_device_info(ap);
425 }
426
427
428 void wps_er_ap_add(struct wps_er *er, const u8 *uuid, struct in_addr *addr,
429                    const char *location, int max_age)
430 {
431         struct wps_er_ap *ap;
432
433         ap = wps_er_ap_get(er, addr, uuid);
434         if (ap) {
435                 /* Update advertisement timeout */
436                 eloop_cancel_timeout(wps_er_ap_timeout, er, ap);
437                 eloop_register_timeout(max_age, 0, wps_er_ap_timeout, er, ap);
438                 return;
439         }
440
441         ap = os_zalloc(sizeof(*ap));
442         if (ap == NULL)
443                 return;
444         ap->er = er;
445         ap->id = ++er->next_ap_id;
446         ap->location = os_strdup(location);
447         if (ap->location == NULL) {
448                 os_free(ap);
449                 return;
450         }
451         ap->next = er->ap;
452         er->ap = ap;
453
454         ap->addr.s_addr = addr->s_addr;
455         os_memcpy(ap->uuid, uuid, WPS_UUID_LEN);
456         eloop_register_timeout(max_age, 0, wps_er_ap_timeout, er, ap);
457
458         wpa_printf(MSG_DEBUG, "WPS ER: Added AP entry for %s (%s)",
459                    inet_ntoa(ap->addr), ap->location);
460
461         /* Fetch device description */
462         ap->http = http_client_url(ap->location, NULL, 10000,
463                                    wps_er_http_dev_desc_cb, ap);
464 }
465
466
467 void wps_er_ap_remove(struct wps_er *er, struct in_addr *addr)
468 {
469         struct wps_er_ap *prev = NULL, *ap = er->ap;
470
471         while (ap) {
472                 if (ap->addr.s_addr == addr->s_addr) {
473                         if (prev)
474                                 prev->next = ap->next;
475                         else
476                                 er->ap = ap->next;
477                         wps_er_ap_free(er, ap);
478                         return;
479                 }
480                 prev = ap;
481                 ap = ap->next;
482         }
483 }
484
485
486 static void wps_er_ap_remove_all(struct wps_er *er)
487 {
488         struct wps_er_ap *prev, *ap;
489
490         ap = er->ap;
491         er->ap = NULL;
492
493         while (ap) {
494                 prev = ap;
495                 ap = ap->next;
496                 wps_er_ap_free(er, prev);
497         }
498 }
499
500
501 static void http_put_date(struct wpabuf *buf)
502 {
503         wpabuf_put_str(buf, "Date: ");
504         format_date(buf);
505         wpabuf_put_str(buf, "\r\n");
506 }
507
508
509 static void wps_er_http_resp_not_found(struct http_request *req)
510 {
511         struct wpabuf *buf;
512         buf = wpabuf_alloc(200);
513         if (buf == NULL) {
514                 http_request_deinit(req);
515                 return;
516         }
517
518         wpabuf_put_str(buf,
519                        "HTTP/1.1 404 Not Found\r\n"
520                        "Server: unspecified, UPnP/1.0, unspecified\r\n"
521                        "Connection: close\r\n");
522         http_put_date(buf);
523         wpabuf_put_str(buf, "\r\n");
524         http_request_send_and_deinit(req, buf);
525 }
526
527
528 static void wps_er_http_resp_ok(struct http_request *req)
529 {
530         struct wpabuf *buf;
531         buf = wpabuf_alloc(200);
532         if (buf == NULL) {
533                 http_request_deinit(req);
534                 return;
535         }
536
537         wpabuf_put_str(buf,
538                        "HTTP/1.1 200 OK\r\n"
539                        "Server: unspecified, UPnP/1.0, unspecified\r\n"
540                        "Connection: close\r\n"
541                        "Content-Length: 0\r\n");
542         http_put_date(buf);
543         wpabuf_put_str(buf, "\r\n");
544         http_request_send_and_deinit(req, buf);
545 }
546
547
548 static void wps_er_sta_timeout(void *eloop_data, void *user_ctx)
549 {
550         struct wps_er_sta *sta = eloop_data;
551         wpa_printf(MSG_DEBUG, "WPS ER: STA entry timed out");
552         wps_er_sta_unlink(sta);
553         wps_er_sta_free(sta);
554 }
555
556
557 static struct wps_er_sta * wps_er_add_sta_data(struct wps_er_ap *ap,
558                                                const u8 *addr,
559                                                struct wps_parse_attr *attr,
560                                                int probe_req)
561 {
562         struct wps_er_sta *sta = wps_er_sta_get(ap, addr);
563         int new_sta = 0;
564         int m1;
565
566         m1 = !probe_req && attr->msg_type && *attr->msg_type == WPS_M1;
567
568         if (sta == NULL) {
569                 /*
570                  * Only allow new STA entry to be added based on Probe Request
571                  * or M1. This will filter out bogus events and anything that
572                  * may have been ongoing at the time ER subscribed for events.
573                  */
574                 if (!probe_req && !m1)
575                         return NULL;
576
577                 sta = os_zalloc(sizeof(*sta));
578                 if (sta == NULL)
579                         return NULL;
580                 os_memcpy(sta->addr, addr, ETH_ALEN);
581                 sta->ap = ap;
582                 sta->next = ap->sta;
583                 ap->sta = sta;
584                 new_sta = 1;
585         }
586
587         if (m1)
588                 sta->m1_received = 1;
589
590         if (attr->config_methods && (!probe_req || !sta->m1_received))
591                 sta->config_methods = WPA_GET_BE16(attr->config_methods);
592         if (attr->uuid_e && (!probe_req || !sta->m1_received))
593                 os_memcpy(sta->uuid, attr->uuid_e, WPS_UUID_LEN);
594         if (attr->primary_dev_type && (!probe_req || !sta->m1_received))
595                 os_memcpy(sta->pri_dev_type, attr->primary_dev_type, 8);
596         if (attr->dev_password_id && (!probe_req || !sta->m1_received))
597                 sta->dev_passwd_id = WPA_GET_BE16(attr->dev_password_id);
598
599         if (attr->manufacturer) {
600                 os_free(sta->manufacturer);
601                 sta->manufacturer = os_malloc(attr->manufacturer_len + 1);
602                 if (sta->manufacturer) {
603                         os_memcpy(sta->manufacturer, attr->manufacturer,
604                                   attr->manufacturer_len);
605                         sta->manufacturer[attr->manufacturer_len] = '\0';
606                 }
607         }
608
609         if (attr->model_name) {
610                 os_free(sta->model_name);
611                 sta->model_name = os_malloc(attr->model_name_len + 1);
612                 if (sta->model_name) {
613                         os_memcpy(sta->model_name, attr->model_name,
614                                   attr->model_name_len);
615                         sta->model_name[attr->model_name_len] = '\0';
616                 }
617         }
618
619         if (attr->model_number) {
620                 os_free(sta->model_number);
621                 sta->model_number = os_malloc(attr->model_number_len + 1);
622                 if (sta->model_number) {
623                         os_memcpy(sta->model_number, attr->model_number,
624                                   attr->model_number_len);
625                         sta->model_number[attr->model_number_len] = '\0';
626                 }
627         }
628
629         if (attr->serial_number) {
630                 os_free(sta->serial_number);
631                 sta->serial_number = os_malloc(attr->serial_number_len + 1);
632                 if (sta->serial_number) {
633                         os_memcpy(sta->serial_number, attr->serial_number,
634                                   attr->serial_number_len);
635                         sta->serial_number[attr->serial_number_len] = '\0';
636                 }
637         }
638
639         if (attr->dev_name) {
640                 os_free(sta->dev_name);
641                 sta->dev_name = os_malloc(attr->dev_name_len + 1);
642                 if (sta->dev_name) {
643                         os_memcpy(sta->dev_name, attr->dev_name,
644                                   attr->dev_name_len);
645                         sta->dev_name[attr->dev_name_len] = '\0';
646                 }
647         }
648
649         eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL);
650         eloop_register_timeout(300, 0, wps_er_sta_timeout, sta, NULL);
651
652         if (m1 || new_sta)
653                 wps_er_sta_event(ap->er->wps, sta, WPS_EV_ER_ENROLLEE_ADD);
654
655         return sta;
656 }
657
658
659 static void wps_er_process_wlanevent_probe_req(struct wps_er_ap *ap,
660                                                const u8 *addr,
661                                                struct wpabuf *msg)
662 {
663         struct wps_parse_attr attr;
664
665         wpa_printf(MSG_DEBUG, "WPS ER: WLANEvent - Probe Request - from "
666                    MACSTR, MAC2STR(addr));
667         wpa_hexdump_buf(MSG_MSGDUMP, "WPS ER: WLANEvent - Enrollee's message "
668                         "(TLVs from Probe Request)", msg);
669
670         if (wps_parse_msg(msg, &attr) < 0) {
671                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse TLVs in "
672                            "WLANEvent message");
673                 return;
674         }
675
676         wps_er_add_sta_data(ap, addr, &attr, 1);
677 }
678
679
680 static void wps_er_http_put_wlan_response_cb(void *ctx, struct http_client *c,
681                                              enum http_client_event event)
682 {
683         struct wps_er_sta *sta = ctx;
684
685         switch (event) {
686         case HTTP_CLIENT_OK:
687                 wpa_printf(MSG_DEBUG, "WPS ER: PutWLANResponse OK");
688                 break;
689         case HTTP_CLIENT_FAILED:
690         case HTTP_CLIENT_INVALID_REPLY:
691         case HTTP_CLIENT_TIMEOUT:
692                 wpa_printf(MSG_DEBUG, "WPS ER: PutWLANResponse failed");
693                 break;
694         }
695         http_client_free(sta->http);
696         sta->http = NULL;
697 }
698
699
700 static const char *soap_prefix =
701         "<?xml version=\"1.0\"?>\n"
702         "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
703         "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
704         "<s:Body>\n";
705 static const char *soap_postfix =
706         "</s:Body>\n</s:Envelope>\n";
707 static const char *urn_wfawlanconfig =
708         "urn:schemas-wifialliance-org:service:WFAWLANConfig:1";
709
710 static struct wpabuf * wps_er_soap_hdr(const struct wpabuf *msg,
711                                        const char *name, const char *arg_name,
712                                        const char *path,
713                                        const struct sockaddr_in *dst,
714                                        char **len_ptr, char **body_ptr)
715 {
716         unsigned char *encoded;
717         size_t encoded_len;
718         struct wpabuf *buf;
719
720         if (msg) {
721                 encoded = base64_encode(wpabuf_head(msg), wpabuf_len(msg),
722                                         &encoded_len);
723                 if (encoded == NULL)
724                         return NULL;
725         } else {
726                 encoded = NULL;
727                 encoded_len = 0;
728         }
729
730         buf = wpabuf_alloc(1000 + encoded_len);
731         if (buf == NULL) {
732                 os_free(encoded);
733                 return NULL;
734         }
735
736         wpabuf_printf(buf,
737                       "POST %s HTTP/1.1\r\n"
738                       "Host: %s:%d\r\n"
739                       "Content-Type: text/xml; charset=\"utf-8\"\r\n"
740                       "Content-Length: ",
741                       path, inet_ntoa(dst->sin_addr), ntohs(dst->sin_port));
742
743         *len_ptr = wpabuf_put(buf, 0);
744         wpabuf_printf(buf,
745                       "        \r\n"
746                       "SOAPACTION: \"%s#%s\"\r\n"
747                       "\r\n",
748                       urn_wfawlanconfig, name);
749
750         *body_ptr = wpabuf_put(buf, 0);
751
752         wpabuf_put_str(buf, soap_prefix);
753         wpabuf_printf(buf, "<u:%s xmlns:u=\"", name);
754         wpabuf_put_str(buf, urn_wfawlanconfig);
755         wpabuf_put_str(buf, "\">\n");
756         if (encoded) {
757                 wpabuf_printf(buf, "<%s>%s</%s>\n",
758                               arg_name, (char *) encoded, arg_name);
759                 os_free(encoded);
760         }
761
762         return buf;
763 }
764
765
766 static void wps_er_soap_end(struct wpabuf *buf, const char *name,
767                             char *len_ptr, char *body_ptr)
768 {
769         char len_buf[10];
770         wpabuf_printf(buf, "</u:%s>\n", name);
771         wpabuf_put_str(buf, soap_postfix);
772         os_snprintf(len_buf, sizeof(len_buf), "%d",
773                     (int) ((char *) wpabuf_put(buf, 0) - body_ptr));
774         os_memcpy(len_ptr, len_buf, os_strlen(len_buf));
775 }
776
777
778 static void wps_er_sta_send_msg(struct wps_er_sta *sta, struct wpabuf *msg)
779 {
780         struct wpabuf *buf;
781         char *len_ptr, *body_ptr;
782         struct sockaddr_in dst;
783         char *url, *path;
784
785         if (sta->http) {
786                 wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request for STA - "
787                            "ignore new request");
788                 wpabuf_free(msg);
789                 return;
790         }
791
792         if (sta->ap->control_url == NULL) {
793                 wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
794                 wpabuf_free(msg);
795                 return;
796         }
797
798         url = http_client_url_parse(sta->ap->control_url, &dst, &path);
799         if (url == NULL) {
800                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
801                 wpabuf_free(msg);
802                 return;
803         }
804
805         buf = wps_er_soap_hdr(msg, "PutWLANResponse", "NewMessage", path, &dst,
806                               &len_ptr, &body_ptr);
807         wpabuf_free(msg);
808         os_free(url);
809         if (buf == NULL)
810                 return;
811         wpabuf_printf(buf, "<NewWLANEventType>%d</NewWLANEventType>\n",
812                       UPNP_WPS_WLANEVENT_TYPE_EAP);
813         wpabuf_printf(buf, "<NewWLANEventMAC>" MACSTR "</NewWLANEventMAC>\n",
814                       MAC2STR(sta->addr));
815
816         wps_er_soap_end(buf, "PutWLANResponse", len_ptr, body_ptr);
817
818         sta->http = http_client_addr(&dst, buf, 1000,
819                                      wps_er_http_put_wlan_response_cb, sta);
820         if (sta->http == NULL)
821                 wpabuf_free(buf);
822 }
823
824
825 static void wps_er_sta_process(struct wps_er_sta *sta, struct wpabuf *msg,
826                                enum wsc_op_code op_code)
827 {
828         enum wps_process_res res;
829
830         res = wps_process_msg(sta->wps, op_code, msg);
831         if (res == WPS_CONTINUE) {
832                 struct wpabuf *next = wps_get_msg(sta->wps, &op_code);
833                 if (next)
834                         wps_er_sta_send_msg(sta, next);
835         } else {
836                 wpa_printf(MSG_DEBUG, "WPS ER: Protocol run %s with the "
837                            "enrollee (res=%d)",
838                            res == WPS_DONE ? "succeeded" : "failed", res);
839                 wps_deinit(sta->wps);
840                 sta->wps = NULL;
841                 if (res == WPS_DONE) {
842                         /* Remove the STA entry after short timeout */
843                         eloop_cancel_timeout(wps_er_sta_timeout, sta, NULL);
844                         eloop_register_timeout(10, 0, wps_er_sta_timeout, sta,
845                                                NULL);
846                 }
847         }
848 }
849
850
851 static void wps_er_sta_start(struct wps_er_sta *sta, struct wpabuf *msg)
852 {
853         struct wps_config cfg;
854
855         if (sta->wps)
856                 wps_deinit(sta->wps);
857
858         os_memset(&cfg, 0, sizeof(cfg));
859         cfg.wps = sta->ap->er->wps;
860         cfg.registrar = 1;
861         cfg.peer_addr = sta->addr;
862
863         sta->wps = wps_init(&cfg);
864         if (sta->wps == NULL)
865                 return;
866         sta->wps->er = 1;
867         sta->wps->use_cred = sta->ap->ap_settings;
868
869         wps_er_sta_process(sta, msg, WSC_MSG);
870 }
871
872
873 static void wps_er_process_wlanevent_eap(struct wps_er_ap *ap, const u8 *addr,
874                                          struct wpabuf *msg)
875 {
876         struct wps_parse_attr attr;
877         struct wps_er_sta *sta;
878
879         wpa_printf(MSG_DEBUG, "WPS ER: WLANEvent - EAP - from " MACSTR,
880                    MAC2STR(addr));
881         wpa_hexdump_buf(MSG_MSGDUMP, "WPS ER: WLANEvent - Enrollee's message "
882                         "(TLVs from EAP-WSC)", msg);
883
884         if (wps_parse_msg(msg, &attr) < 0) {
885                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse TLVs in "
886                            "WLANEvent message");
887                 return;
888         }
889
890         sta = wps_er_add_sta_data(ap, addr, &attr, 0);
891         if (sta == NULL)
892                 return;
893
894         if (attr.msg_type && *attr.msg_type == WPS_M1)
895                 wps_er_sta_start(sta, msg);
896         else if (sta->wps) {
897                 enum wsc_op_code op_code = WSC_MSG;
898                 if (attr.msg_type) {
899                         switch (*attr.msg_type) {
900                         case WPS_WSC_ACK:
901                                 op_code = WSC_ACK;
902                                 break;
903                         case WPS_WSC_NACK:
904                                 op_code = WSC_NACK;
905                                 break;
906                         case WPS_WSC_DONE:
907                                 op_code = WSC_Done;
908                                 break;
909                         }
910                 }
911                 wps_er_sta_process(sta, msg, op_code);
912         }
913 }
914
915
916 static void wps_er_process_wlanevent(struct wps_er_ap *ap,
917                                      struct wpabuf *event)
918 {
919         u8 *data;
920         u8 wlan_event_type;
921         u8 wlan_event_mac[ETH_ALEN];
922         struct wpabuf msg;
923
924         wpa_hexdump(MSG_MSGDUMP, "WPS ER: Received WLANEvent",
925                     wpabuf_head(event), wpabuf_len(event));
926         if (wpabuf_len(event) < 1 + 17) {
927                 wpa_printf(MSG_DEBUG, "WPS ER: Too short WLANEvent");
928                 return;
929         }
930
931         data = wpabuf_mhead(event);
932         wlan_event_type = data[0];
933         if (hwaddr_aton((char *) data + 1, wlan_event_mac) < 0) {
934                 wpa_printf(MSG_DEBUG, "WPS ER: Invalid WLANEventMAC in "
935                            "WLANEvent");
936                 return;
937         }
938
939         wpabuf_set(&msg, data + 1 + 17, wpabuf_len(event) - (1 + 17));
940
941         switch (wlan_event_type) {
942         case 1:
943                 wps_er_process_wlanevent_probe_req(ap, wlan_event_mac, &msg);
944                 break;
945         case 2:
946                 wps_er_process_wlanevent_eap(ap, wlan_event_mac, &msg);
947                 break;
948         default:
949                 wpa_printf(MSG_DEBUG, "WPS ER: Unknown WLANEventType %d",
950                            wlan_event_type);
951                 break;
952         }
953 }
954
955
956 static void wps_er_http_event(struct wps_er *er, struct http_request *req,
957                               unsigned int ap_id)
958 {
959         struct wps_er_ap *ap = wps_er_ap_get_id(er, ap_id);
960         struct wpabuf *event;
961         enum http_reply_code ret;
962
963         if (ap == NULL) {
964                 wpa_printf(MSG_DEBUG, "WPS ER: HTTP event from unknown AP id "
965                            "%u", ap_id);
966                 wps_er_http_resp_not_found(req);
967                 return;
968         }
969         wpa_printf(MSG_MSGDUMP, "WPS ER: HTTP event from AP id %u: %s",
970                    ap_id, http_request_get_data(req));
971
972         event = xml_get_base64_item(http_request_get_data(req), "WLANEvent",
973                                     &ret);
974         if (event == NULL) {
975                 wpa_printf(MSG_DEBUG, "WPS ER: Could not extract WLANEvent "
976                            "from the event notification");
977                 /*
978                  * Reply with OK anyway to avoid getting unregistered from
979                  * events.
980                  */
981                 wps_er_http_resp_ok(req);
982                 return;
983         }
984
985         wps_er_process_wlanevent(ap, event);
986
987         wpabuf_free(event);
988         wps_er_http_resp_ok(req);
989 }
990
991
992 static void wps_er_http_notify(struct wps_er *er, struct http_request *req)
993 {
994         char *uri = http_request_get_uri(req);
995
996         if (os_strncmp(uri, "/event/", 7) == 0) {
997                 unsigned int event_id;
998                 char *pos;
999                 event_id = atoi(uri + 7);
1000                 if (event_id != er->event_id) {
1001                         wpa_printf(MSG_DEBUG, "WPS ER: HTTP event for an "
1002                                    "unknown event id %u", event_id);
1003                         return;
1004                 }
1005                 pos = os_strchr(uri + 7, '/');
1006                 if (pos == NULL)
1007                         return;
1008                 pos++;
1009                 wps_er_http_event(er, req, atoi(pos));
1010         } else {
1011                 wpa_printf(MSG_DEBUG, "WPS ER: Unknown HTTP NOTIFY for '%s'",
1012                            uri);
1013                 wps_er_http_resp_not_found(req);
1014         }
1015 }
1016
1017
1018 static void wps_er_http_req(void *ctx, struct http_request *req)
1019 {
1020         struct wps_er *er = ctx;
1021         struct sockaddr_in *cli = http_request_get_cli_addr(req);
1022         enum httpread_hdr_type type = http_request_get_type(req);
1023         struct wpabuf *buf;
1024
1025         wpa_printf(MSG_DEBUG, "WPS ER: HTTP request: '%s' (type %d) from "
1026                    "%s:%d",
1027                    http_request_get_uri(req), type,
1028                    inet_ntoa(cli->sin_addr), ntohs(cli->sin_port));
1029
1030         switch (type) {
1031         case HTTPREAD_HDR_TYPE_NOTIFY:
1032                 wps_er_http_notify(er, req);
1033                 break;
1034         default:
1035                 wpa_printf(MSG_DEBUG, "WPS ER: Unsupported HTTP request type "
1036                            "%d", type);
1037                 buf = wpabuf_alloc(200);
1038                 if (buf == NULL) {
1039                         http_request_deinit(req);
1040                         return;
1041                 }
1042                 wpabuf_put_str(buf,
1043                                "HTTP/1.1 501 Unimplemented\r\n"
1044                                "Connection: close\r\n");
1045                 http_put_date(buf);
1046                 wpabuf_put_str(buf, "\r\n");
1047                 http_request_send_and_deinit(req, buf);
1048                 break;
1049         }
1050 }
1051
1052
1053 struct wps_er *
1054 wps_er_init(struct wps_context *wps, const char *ifname)
1055 {
1056         struct wps_er *er;
1057         struct in_addr addr;
1058
1059         er = os_zalloc(sizeof(*er));
1060         if (er == NULL)
1061                 return NULL;
1062
1063         er->multicast_sd = -1;
1064         er->ssdp_sd = -1;
1065
1066         os_strlcpy(er->ifname, ifname, sizeof(er->ifname));
1067         er->wps = wps;
1068         os_get_random((unsigned char *) &er->event_id, sizeof(er->event_id));
1069
1070         if (get_netif_info(ifname,
1071                            &er->ip_addr, &er->ip_addr_text,
1072                            er->mac_addr, &er->mac_addr_text)) {
1073                 wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address "
1074                            "for %s. Does it have IP address?", ifname);
1075                 wps_er_deinit(er);
1076                 return NULL;
1077         }
1078
1079         if (wps_er_ssdp_init(er) < 0) {
1080                 wps_er_deinit(er);
1081                 return NULL;
1082         }
1083
1084         addr.s_addr = er->ip_addr;
1085         er->http_srv = http_server_init(&addr, -1, wps_er_http_req, er);
1086         if (er->http_srv == NULL) {
1087                 wps_er_deinit(er);
1088                 return NULL;
1089         }
1090         er->http_port = http_server_get_port(er->http_srv);
1091
1092         wpa_printf(MSG_DEBUG, "WPS ER: Start (ifname=%s ip_addr=%s "
1093                    "mac_addr=%s)",
1094                    er->ifname, er->ip_addr_text, er->mac_addr_text);
1095
1096         return er;
1097 }
1098
1099
1100 void wps_er_refresh(struct wps_er *er)
1101 {
1102         struct wps_er_ap *ap;
1103         struct wps_er_sta *sta;
1104
1105         for (ap = er->ap; ap; ap = ap->next) {
1106                 wps_er_ap_event(er->wps, ap, WPS_EV_ER_AP_ADD);
1107                 for (sta = ap->sta; sta; sta = sta->next)
1108                         wps_er_sta_event(er->wps, sta, WPS_EV_ER_ENROLLEE_ADD);
1109         }
1110
1111         wps_er_send_ssdp_msearch(er);
1112 }
1113
1114
1115 void wps_er_deinit(struct wps_er *er)
1116 {
1117         if (er == NULL)
1118                 return;
1119         http_server_deinit(er->http_srv);
1120         wps_er_ap_remove_all(er);
1121         wps_er_ssdp_deinit(er);
1122         os_free(er->ip_addr_text);
1123         os_free(er->mac_addr_text);
1124         os_free(er);
1125 }
1126
1127
1128 static void wps_er_http_set_sel_reg_cb(void *ctx, struct http_client *c,
1129                                        enum http_client_event event)
1130 {
1131         struct wps_er_ap *ap = ctx;
1132
1133         switch (event) {
1134         case HTTP_CLIENT_OK:
1135                 wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar OK");
1136                 break;
1137         case HTTP_CLIENT_FAILED:
1138         case HTTP_CLIENT_INVALID_REPLY:
1139         case HTTP_CLIENT_TIMEOUT:
1140                 wpa_printf(MSG_DEBUG, "WPS ER: SetSelectedRegistrar failed");
1141                 break;
1142         }
1143         http_client_free(ap->http);
1144         ap->http = NULL;
1145 }
1146
1147
1148 static void wps_er_send_set_sel_reg(struct wps_er_ap *ap, struct wpabuf *msg)
1149 {
1150         struct wpabuf *buf;
1151         char *len_ptr, *body_ptr;
1152         struct sockaddr_in dst;
1153         char *url, *path;
1154
1155         if (ap->control_url == NULL) {
1156                 wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
1157                 return;
1158         }
1159
1160         if (ap->http) {
1161                 wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request for AP - "
1162                            "ignore new request");
1163                 return;
1164         }
1165
1166         url = http_client_url_parse(ap->control_url, &dst, &path);
1167         if (url == NULL) {
1168                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
1169                 return;
1170         }
1171
1172         buf = wps_er_soap_hdr(msg, "SetSelectedRegistrar", "NewMessage", path,
1173                               &dst, &len_ptr, &body_ptr);
1174         os_free(url);
1175         if (buf == NULL)
1176                 return;
1177
1178         wps_er_soap_end(buf, "SetSelectedRegistrar", len_ptr, body_ptr);
1179
1180         ap->http = http_client_addr(&dst, buf, 1000,
1181                                     wps_er_http_set_sel_reg_cb, ap);
1182         if (ap->http == NULL)
1183                 wpabuf_free(buf);
1184 }
1185
1186
1187 static int wps_er_build_selected_registrar(struct wpabuf *msg, int sel_reg)
1188 {
1189         wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR);
1190         wpabuf_put_be16(msg, 1);
1191         wpabuf_put_u8(msg, !!sel_reg);
1192         return 0;
1193 }
1194
1195
1196 static int wps_er_build_dev_password_id(struct wpabuf *msg, u16 dev_passwd_id)
1197 {
1198         wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID);
1199         wpabuf_put_be16(msg, 2);
1200         wpabuf_put_be16(msg, dev_passwd_id);
1201         return 0;
1202 }
1203
1204
1205 static int wps_er_build_sel_reg_config_methods(struct wpabuf *msg,
1206                                                u16 sel_reg_config_methods)
1207 {
1208         wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR_CONFIG_METHODS);
1209         wpabuf_put_be16(msg, 2);
1210         wpabuf_put_be16(msg, sel_reg_config_methods);
1211         return 0;
1212 }
1213
1214
1215 void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id,
1216                         u16 sel_reg_config_methods)
1217 {
1218         struct wpabuf *msg;
1219         struct wps_er_ap *ap;
1220
1221         msg = wpabuf_alloc(500);
1222         if (msg == NULL)
1223                 return;
1224
1225         if (wps_build_version(msg) ||
1226             wps_er_build_selected_registrar(msg, sel_reg) ||
1227             wps_er_build_dev_password_id(msg, dev_passwd_id) ||
1228             wps_er_build_sel_reg_config_methods(msg, sel_reg_config_methods)) {
1229                 wpabuf_free(msg);
1230                 return;
1231         }
1232
1233         for (ap = er->ap; ap; ap = ap->next)
1234                 wps_er_send_set_sel_reg(ap, msg);
1235
1236         wpabuf_free(msg);
1237 }
1238
1239
1240 int wps_er_pbc(struct wps_er *er, const u8 *uuid)
1241 {
1242         if (er == NULL || er->wps == NULL)
1243                 return -1;
1244
1245         /*
1246          * TODO: Should enable PBC mode only in a single AP based on which AP
1247          * the Enrollee (uuid) is using. Now, we may end up enabling multiple
1248          * APs in PBC mode which could result in session overlap at the
1249          * Enrollee.
1250          */
1251         if (wps_registrar_button_pushed(er->wps->registrar))
1252                 return -1;
1253
1254         return 0;
1255 }
1256
1257
1258 static void wps_er_ap_settings_cb(void *ctx, const struct wps_credential *cred)
1259 {
1260         struct wps_er_ap *ap = ctx;
1261         wpa_printf(MSG_DEBUG, "WPS ER: AP Settings received");
1262         os_free(ap->ap_settings);
1263         ap->ap_settings = os_malloc(sizeof(*cred));
1264         if (ap->ap_settings) {
1265                 os_memcpy(ap->ap_settings, cred, sizeof(*cred));
1266                 ap->ap_settings->cred_attr = NULL;
1267         }
1268
1269         /* TODO: send info through ctrl_iface */
1270 }
1271
1272
1273 static void wps_er_http_put_message_cb(void *ctx, struct http_client *c,
1274                                        enum http_client_event event)
1275 {
1276         struct wps_er_ap *ap = ctx;
1277         struct wpabuf *reply;
1278         char *msg = NULL;
1279
1280         switch (event) {
1281         case HTTP_CLIENT_OK:
1282                 wpa_printf(MSG_DEBUG, "WPS ER: PutMessage OK");
1283                 reply = http_client_get_body(c);
1284                 if (reply == NULL)
1285                         break;
1286                 msg = os_zalloc(wpabuf_len(reply) + 1);
1287                 if (msg == NULL)
1288                         break;
1289                 os_memcpy(msg, wpabuf_head(reply), wpabuf_len(reply));
1290                 break;
1291         case HTTP_CLIENT_FAILED:
1292         case HTTP_CLIENT_INVALID_REPLY:
1293         case HTTP_CLIENT_TIMEOUT:
1294                 wpa_printf(MSG_DEBUG, "WPS ER: PutMessage failed");
1295                 if (ap->wps) {
1296                         wps_deinit(ap->wps);
1297                         ap->wps = NULL;
1298                 }
1299                 break;
1300         }
1301         http_client_free(ap->http);
1302         ap->http = NULL;
1303
1304         if (msg) {
1305                 struct wpabuf *buf;
1306                 enum http_reply_code ret;
1307                 buf = xml_get_base64_item(msg, "NewOutMessage", &ret);
1308                 os_free(msg);
1309                 if (buf == NULL) {
1310                         wpa_printf(MSG_DEBUG, "WPS ER: Could not extract "
1311                                    "NewOutMessage from PutMessage response");
1312                         return;
1313                 }
1314                 wps_er_ap_process(ap, buf);
1315                 wpabuf_free(buf);
1316         }
1317 }
1318
1319
1320 static void wps_er_ap_put_message(struct wps_er_ap *ap,
1321                                   const struct wpabuf *msg)
1322 {
1323         struct wpabuf *buf;
1324         char *len_ptr, *body_ptr;
1325         struct sockaddr_in dst;
1326         char *url, *path;
1327
1328         if (ap->http) {
1329                 wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP operation ongoing "
1330                            "with the AP - cannot continue learn");
1331                 return;
1332         }
1333
1334         if (ap->control_url == NULL) {
1335                 wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
1336                 return;
1337         }
1338
1339         url = http_client_url_parse(ap->control_url, &dst, &path);
1340         if (url == NULL) {
1341                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
1342                 return;
1343         }
1344
1345         buf = wps_er_soap_hdr(msg, "PutMessage", "NewInMessage", path, &dst,
1346                               &len_ptr, &body_ptr);
1347         os_free(url);
1348         if (buf == NULL)
1349                 return;
1350
1351         wps_er_soap_end(buf, "PutMessage", len_ptr, body_ptr);
1352
1353         ap->http = http_client_addr(&dst, buf, 10000,
1354                                     wps_er_http_put_message_cb, ap);
1355         if (ap->http == NULL)
1356                 wpabuf_free(buf);
1357 }
1358
1359
1360 static void wps_er_ap_process(struct wps_er_ap *ap, struct wpabuf *msg)
1361 {
1362         enum wps_process_res res;
1363
1364         res = wps_process_msg(ap->wps, WSC_MSG, msg);
1365         if (res == WPS_CONTINUE) {
1366                 enum wsc_op_code op_code;
1367                 struct wpabuf *next = wps_get_msg(ap->wps, &op_code);
1368                 if (next) {
1369                         wps_er_ap_put_message(ap, next);
1370                         wpabuf_free(next);
1371                 } else {
1372                         wpa_printf(MSG_DEBUG, "WPS ER: Failed to build "
1373                                    "message");
1374                         wps_deinit(ap->wps);
1375                         ap->wps = NULL;
1376                 }
1377         } else {
1378                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to process message from "
1379                            "AP (res=%d)", res);
1380                 wps_deinit(ap->wps);
1381                 ap->wps = NULL;
1382         }
1383 }
1384
1385
1386 static void wps_er_ap_learn_m1(struct wps_er_ap *ap, struct wpabuf *m1)
1387 {
1388         struct wps_config cfg;
1389
1390         if (ap->wps) {
1391                 wpa_printf(MSG_DEBUG, "WPS ER: Protocol run already in "
1392                            "progress with this AP");
1393                 return;
1394         }
1395
1396         os_memset(&cfg, 0, sizeof(cfg));
1397         cfg.wps = ap->er->wps;
1398         cfg.registrar = 1;
1399         ap->wps = wps_init(&cfg);
1400         if (ap->wps == NULL)
1401                 return;
1402         ap->wps->ap_settings_cb = wps_er_ap_settings_cb;
1403         ap->wps->ap_settings_cb_ctx = ap;
1404
1405         wps_er_ap_process(ap, m1);
1406 }
1407
1408
1409 static void wps_er_ap_learn(struct wps_er_ap *ap, const char *dev_info)
1410 {
1411         struct wpabuf *info;
1412         enum http_reply_code ret;
1413
1414         wpa_printf(MSG_DEBUG, "WPS ER: Received GetDeviceInfo response (M1) "
1415                    "from the AP");
1416         info = xml_get_base64_item(dev_info, "NewDeviceInfo", &ret);
1417         if (info == NULL) {
1418                 wpa_printf(MSG_DEBUG, "WPS ER: Could not extract "
1419                            "NewDeviceInfo from GetDeviceInfo response");
1420                 return;
1421         }
1422
1423         ap->m1_handler(ap, info);
1424         wpabuf_free(info);
1425 }
1426
1427
1428 static void wps_er_http_get_dev_info_cb(void *ctx, struct http_client *c,
1429                                         enum http_client_event event)
1430 {
1431         struct wps_er_ap *ap = ctx;
1432         struct wpabuf *reply;
1433         char *dev_info = NULL;
1434
1435         switch (event) {
1436         case HTTP_CLIENT_OK:
1437                 wpa_printf(MSG_DEBUG, "WPS ER: GetDeviceInfo OK");
1438                 reply = http_client_get_body(c);
1439                 if (reply == NULL)
1440                         break;
1441                 dev_info = os_zalloc(wpabuf_len(reply) + 1);
1442                 if (dev_info == NULL)
1443                         break;
1444                 os_memcpy(dev_info, wpabuf_head(reply), wpabuf_len(reply));
1445                 break;
1446         case HTTP_CLIENT_FAILED:
1447         case HTTP_CLIENT_INVALID_REPLY:
1448         case HTTP_CLIENT_TIMEOUT:
1449                 wpa_printf(MSG_DEBUG, "WPS ER: GetDeviceInfo failed");
1450                 break;
1451         }
1452         http_client_free(ap->http);
1453         ap->http = NULL;
1454
1455         if (dev_info) {
1456                 wps_er_ap_learn(ap, dev_info);
1457                 os_free(dev_info);
1458         }
1459 }
1460
1461
1462 static int wps_er_send_get_device_info(struct wps_er_ap *ap,
1463                                        void (*m1_handler)(struct wps_er_ap *ap,
1464                                                           struct wpabuf *m1))
1465 {
1466         struct wpabuf *buf;
1467         char *len_ptr, *body_ptr;
1468         struct sockaddr_in dst;
1469         char *url, *path;
1470
1471         if (ap->http) {
1472                 wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP operation ongoing "
1473                            "with the AP - cannot get device info");
1474                 return -1;
1475         }
1476
1477         if (ap->control_url == NULL) {
1478                 wpa_printf(MSG_DEBUG, "WPS ER: No controlURL for AP");
1479                 return -1;
1480         }
1481
1482         url = http_client_url_parse(ap->control_url, &dst, &path);
1483         if (url == NULL) {
1484                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse controlURL");
1485                 return -1;
1486         }
1487
1488         buf = wps_er_soap_hdr(NULL, "GetDeviceInfo", NULL, path, &dst,
1489                               &len_ptr, &body_ptr);
1490         os_free(url);
1491         if (buf == NULL)
1492                 return -1;
1493
1494         wps_er_soap_end(buf, "GetDeviceInfo", len_ptr, body_ptr);
1495
1496         ap->http = http_client_addr(&dst, buf, 10000,
1497                                     wps_er_http_get_dev_info_cb, ap);
1498         if (ap->http == NULL) {
1499                 wpabuf_free(buf);
1500                 return -1;
1501         }
1502
1503         ap->m1_handler = m1_handler;
1504
1505         return 0;
1506 }
1507
1508
1509 int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin,
1510                  size_t pin_len)
1511 {
1512         struct wps_er_ap *ap;
1513
1514         if (er == NULL)
1515                 return -1;
1516
1517         ap = wps_er_ap_get(er, NULL, uuid);
1518         if (ap == NULL) {
1519                 wpa_printf(MSG_DEBUG, "WPS ER: AP not found for learn "
1520                            "request");
1521                 return -1;
1522         }
1523         if (ap->wps) {
1524                 wpa_printf(MSG_DEBUG, "WPS ER: Pending operation ongoing "
1525                            "with the AP - cannot start learn");
1526                 return -1;
1527         }
1528
1529         if (wps_er_send_get_device_info(ap, wps_er_ap_learn_m1) < 0)
1530                 return -1;
1531
1532         /* TODO: add PIN without SetSelectedRegistrar trigger to all APs */
1533         wps_registrar_add_pin(er->wps->registrar, uuid, pin, pin_len, 0);
1534
1535         return 0;
1536 }