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