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