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