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