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