2e11dd604dad584cb4107440f721a5a10bd2d3bd
[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 "uuid.h"
19 #include "eloop.h"
20 #include "httpread.h"
21 #include "http_client.h"
22 #include "http_server.h"
23 #include "upnp_xml.h"
24 #include "wps_i.h"
25 #include "wps_upnp.h"
26 #include "wps_upnp_i.h"
27
28
29 /* TODO:
30  * send notification of new AP device with wpa_msg
31  * re-send notifications with wpa_msg if ER re-started (to update wpa_gui-qt4)
32  * (also re-send SSDP M-SEARCH in this case to find new APs)
33  * parse UPnP event messages
34  */
35
36 static void wps_er_ap_timeout(void *eloop_data, void *user_ctx);
37
38
39 struct wps_er_ap {
40         struct wps_er_ap *next;
41         struct wps_er *er;
42         struct in_addr addr;
43         char *location;
44         struct http_client *http;
45
46         char *friendly_name;
47         char *manufacturer;
48         char *manufacturer_url;
49         char *model_description;
50         char *model_name;
51         char *model_number;
52         char *model_url;
53         char *serial_number;
54         char *udn;
55         char *upc;
56
57         char *scpd_url;
58         char *control_url;
59         char *event_sub_url;
60
61         int subscribed;
62         unsigned int id;
63 };
64
65 struct wps_er {
66         struct wps_registrar *reg;
67         char ifname[17];
68         char *mac_addr_text; /* mac addr of network i.f. we use */
69         u8 mac_addr[ETH_ALEN]; /* mac addr of network i.f. we use */
70         char *ip_addr_text; /* IP address of network i.f. we use */
71         unsigned ip_addr; /* IP address of network i.f. we use (host order) */
72         int multicast_sd;
73         int ssdp_sd;
74         struct wps_er_ap *ap;
75         struct http_server *http_srv;
76         int http_port;
77         unsigned int next_ap_id;
78 };
79
80
81 static void wps_er_pin_needed_cb(void *ctx, const u8 *uuid_e,
82                                  const struct wps_device_data *dev)
83 {
84         wpa_printf(MSG_DEBUG, "WPS ER: PIN needed");
85 }
86
87
88 static struct wps_er_ap * wps_er_ap_get(struct wps_er *er,
89                                         struct in_addr *addr)
90 {
91         struct wps_er_ap *ap;
92         for (ap = er->ap; ap; ap = ap->next) {
93                 if (ap->addr.s_addr == addr->s_addr)
94                         break;
95         }
96         return ap;
97 }
98
99
100 static struct wps_er_ap * wps_er_ap_get_id(struct wps_er *er, unsigned int id)
101 {
102         struct wps_er_ap *ap;
103         for (ap = er->ap; ap; ap = ap->next) {
104                 if (ap->id == id)
105                         break;
106         }
107         return ap;
108 }
109
110
111 static void wps_er_ap_free(struct wps_er *er, struct wps_er_ap *ap)
112 {
113         /* TODO: if ap->subscribed, unsubscribe from events if the AP is still
114          * alive */
115         wpa_printf(MSG_DEBUG, "WPS ER: Removing AP entry for %s (%s)",
116                    inet_ntoa(ap->addr), ap->location);
117         eloop_cancel_timeout(wps_er_ap_timeout, er, ap);
118         os_free(ap->location);
119         http_client_free(ap->http);
120
121         os_free(ap->friendly_name);
122         os_free(ap->manufacturer);
123         os_free(ap->manufacturer_url);
124         os_free(ap->model_description);
125         os_free(ap->model_name);
126         os_free(ap->model_number);
127         os_free(ap->model_url);
128         os_free(ap->serial_number);
129         os_free(ap->udn);
130         os_free(ap->upc);
131
132         os_free(ap->scpd_url);
133         os_free(ap->control_url);
134         os_free(ap->event_sub_url);
135
136         os_free(ap);
137 }
138
139
140 static void wps_er_ap_timeout(void *eloop_data, void *user_ctx)
141 {
142         struct wps_er *er = eloop_data;
143         struct wps_er_ap *ap = user_ctx;
144         wpa_printf(MSG_DEBUG, "WPS ER: AP advertisement timed out");
145         wps_er_ap_free(er, ap);
146 }
147
148
149 static void wps_er_http_subscribe_cb(void *ctx, struct http_client *c,
150                                      enum http_client_event event)
151 {
152         struct wps_er_ap *ap = ctx;
153
154         switch (event) {
155         case HTTP_CLIENT_OK:
156                 wpa_printf(MSG_DEBUG, "WPS ER: Subscribed to events");
157                 break;
158         case HTTP_CLIENT_FAILED:
159         case HTTP_CLIENT_INVALID_REPLY:
160         case HTTP_CLIENT_TIMEOUT:
161                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to subscribe to events");
162                 break;
163         }
164         http_client_free(ap->http);
165         ap->http = NULL;
166 }
167
168
169 static void wps_er_subscribe(struct wps_er_ap *ap)
170 {
171         struct wpabuf *req;
172         struct sockaddr_in dst;
173         char *url, *path;
174
175         if (ap->event_sub_url == NULL) {
176                 wpa_printf(MSG_DEBUG, "WPS ER: No eventSubURL - cannot "
177                            "subscribe");
178                 return;
179         }
180         if (ap->http) {
181                 wpa_printf(MSG_DEBUG, "WPS ER: Pending HTTP request - cannot "
182                            "send subscribe request");
183                 return;
184         }
185
186         url = http_client_url_parse(ap->event_sub_url, &dst, &path);
187         if (url == NULL) {
188                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse eventSubURL");
189                 return;
190         }
191
192         req = wpabuf_alloc(os_strlen(ap->event_sub_url) + 1000);
193         if (req == NULL) {
194                 os_free(url);
195                 return;
196         }
197         wpabuf_printf(req,
198                       "SUBSCRIBE %s HTTP/1.1\r\n"
199                       "HOST: %s:%d\r\n"
200                       "CALLBACK: <http://%s:%d/event/%d>\r\n"
201                       "NT: upnp:event\r\n"
202                       "TIMEOUT: Second-%d\r\n"
203                       "\r\n",
204                       path, inet_ntoa(dst.sin_addr), ntohs(dst.sin_port),
205                       ap->er->ip_addr_text, ap->er->http_port, ap->id, 1800);
206         os_free(url);
207         wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Subscription request",
208                           wpabuf_head(req), wpabuf_len(req));
209
210         ap->http = http_client_addr(&dst, req, 1000, wps_er_http_subscribe_cb,
211                                     ap);
212         if (ap->http == NULL)
213                 wpabuf_free(req);
214 }
215
216
217 static void wps_er_parse_device_description(struct wps_er_ap *ap,
218                                             struct wpabuf *reply)
219 {
220         /* Note: reply includes null termination after the buffer data */
221         const char *data = wpabuf_head(reply);
222
223         wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Device info",
224                           wpabuf_head(reply), wpabuf_len(reply));
225
226         ap->friendly_name = xml_get_first_item(data, "friendlyName");
227         wpa_printf(MSG_DEBUG, "WPS ER: friendlyName='%s'", ap->friendly_name);
228
229         ap->manufacturer = xml_get_first_item(data, "manufacturer");
230         wpa_printf(MSG_DEBUG, "WPS ER: manufacturer='%s'", ap->manufacturer);
231
232         ap->manufacturer_url = xml_get_first_item(data, "manufacturerURL");
233         wpa_printf(MSG_DEBUG, "WPS ER: manufacturerURL='%s'",
234                    ap->manufacturer_url);
235
236         ap->model_description = xml_get_first_item(data, "modelDescription");
237         wpa_printf(MSG_DEBUG, "WPS ER: modelDescription='%s'",
238                    ap->model_description);
239
240         ap->model_name = xml_get_first_item(data, "modelName");
241         wpa_printf(MSG_DEBUG, "WPS ER: modelName='%s'", ap->model_name);
242
243         ap->model_number = xml_get_first_item(data, "modelNumber");
244         wpa_printf(MSG_DEBUG, "WPS ER: modelNumber='%s'", ap->model_number);
245
246         ap->model_url = xml_get_first_item(data, "modelURL");
247         wpa_printf(MSG_DEBUG, "WPS ER: modelURL='%s'", ap->model_url);
248
249         ap->serial_number = xml_get_first_item(data, "serialNumber");
250         wpa_printf(MSG_DEBUG, "WPS ER: serialNumber='%s'", ap->serial_number);
251
252         ap->udn = xml_get_first_item(data, "UDN");
253         wpa_printf(MSG_DEBUG, "WPS ER: UDN='%s'", ap->udn);
254
255         ap->upc = xml_get_first_item(data, "UPC");
256         wpa_printf(MSG_DEBUG, "WPS ER: UPC='%s'", ap->upc);
257
258         ap->scpd_url = http_link_update(
259                 xml_get_first_item(data, "SCPDURL"), ap->location);
260         wpa_printf(MSG_DEBUG, "WPS ER: SCPDURL='%s'", ap->scpd_url);
261
262         ap->control_url = http_link_update(
263                 xml_get_first_item(data, "controlURL"), ap->location);
264         wpa_printf(MSG_DEBUG, "WPS ER: controlURL='%s'", ap->control_url);
265
266         ap->event_sub_url = http_link_update(
267                 xml_get_first_item(data, "eventSubURL"), ap->location);
268         wpa_printf(MSG_DEBUG, "WPS ER: eventSubURL='%s'", ap->event_sub_url);
269 }
270
271
272 static void wps_er_http_dev_desc_cb(void *ctx, struct http_client *c,
273                                     enum http_client_event event)
274 {
275         struct wps_er_ap *ap = ctx;
276         struct wpabuf *reply;
277         int subscribe = 0;
278
279         switch (event) {
280         case HTTP_CLIENT_OK:
281                 reply = http_client_get_body(c);
282                 if (reply == NULL)
283                         break;
284                 wps_er_parse_device_description(ap, reply);
285                 subscribe = 1;
286                 break;
287         case HTTP_CLIENT_FAILED:
288         case HTTP_CLIENT_INVALID_REPLY:
289         case HTTP_CLIENT_TIMEOUT:
290                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to fetch device info");
291                 break;
292         }
293         http_client_free(ap->http);
294         ap->http = NULL;
295         if (subscribe)
296                 wps_er_subscribe(ap);
297 }
298
299
300 static void wps_er_ap_add(struct wps_er *er, struct in_addr *addr,
301                           const char *location, int max_age)
302 {
303         struct wps_er_ap *ap;
304
305         ap = wps_er_ap_get(er, addr);
306         if (ap) {
307                 /* Update advertisement timeout */
308                 eloop_cancel_timeout(wps_er_ap_timeout, er, ap);
309                 eloop_register_timeout(max_age, 0, wps_er_ap_timeout, er, ap);
310                 return;
311         }
312
313         ap = os_zalloc(sizeof(*ap));
314         if (ap == NULL)
315                 return;
316         ap->er = er;
317         ap->id = ++er->next_ap_id;
318         ap->location = os_strdup(location);
319         if (ap->location == NULL) {
320                 os_free(ap);
321                 return;
322         }
323         ap->next = er->ap;
324         er->ap = ap;
325
326         ap->addr.s_addr = addr->s_addr;
327         eloop_register_timeout(max_age, 0, wps_er_ap_timeout, er, ap);
328
329         wpa_printf(MSG_DEBUG, "WPS ER: Added AP entry for %s (%s)",
330                    inet_ntoa(ap->addr), ap->location);
331
332         /* Fetch device description */
333         ap->http = http_client_url(ap->location, NULL, 10000,
334                                    wps_er_http_dev_desc_cb, ap);
335 }
336
337
338 static void wps_er_ap_remove(struct wps_er *er, struct in_addr *addr)
339 {
340         struct wps_er_ap *prev = NULL, *ap = er->ap;
341
342         while (ap) {
343                 if (ap->addr.s_addr == addr->s_addr) {
344                         if (prev)
345                                 prev->next = ap->next;
346                         else
347                                 er->ap = ap->next;
348                         wps_er_ap_free(er, ap);
349                         return;
350                 }
351                 prev = ap;
352                 ap = ap->next;
353         }
354 }
355
356
357 static void wps_er_ap_remove_all(struct wps_er *er)
358 {
359         struct wps_er_ap *prev, *ap;
360
361         ap = er->ap;
362         er->ap = NULL;
363
364         while (ap) {
365                 prev = ap;
366                 ap = ap->next;
367                 wps_er_ap_free(er, prev);
368         }
369 }
370
371
372 static void wps_er_ssdp_rx(int sd, void *eloop_ctx, void *sock_ctx)
373 {
374         struct wps_er *er = eloop_ctx;
375         struct sockaddr_in addr; /* client address */
376         socklen_t addr_len;
377         int nread;
378         char buf[MULTICAST_MAX_READ], *pos, *pos2, *start;
379         int wfa = 0, byebye = 0;
380         int max_age = -1;
381         char *location = NULL;
382
383         addr_len = sizeof(addr);
384         nread = recvfrom(sd, buf, sizeof(buf) - 1, 0,
385                          (struct sockaddr *) &addr, &addr_len);
386         if (nread <= 0)
387                 return;
388         buf[nread] = '\0';
389
390         wpa_printf(MSG_DEBUG, "WPS ER: Received SSDP from %s",
391                    inet_ntoa(addr.sin_addr));
392         wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Received SSDP contents",
393                           (u8 *) buf, nread);
394
395         if (sd == er->multicast_sd) {
396                 /* Reply to M-SEARCH */
397                 if (os_strncmp(buf, "HTTP/1.1 200 OK", 15) != 0)
398                         return; /* unexpected response header */
399         } else {
400                 /* Unsolicited message (likely NOTIFY or M-SEARCH) */
401                 if (os_strncmp(buf, "NOTIFY ", 7) != 0)
402                         return; /* only process notifications */
403         }
404
405         for (start = buf; start && *start; start = pos) {
406                 pos = os_strchr(start, '\n');
407                 if (pos) {
408                         if (pos[-1] == '\r')
409                                 pos[-1] = '\0';
410                         *pos++ = '\0';
411                 }
412                 if (os_strstr(start, "schemas-wifialliance-org:device:"
413                               "WFADevice:1"))
414                         wfa = 1;
415                 if (os_strstr(start, "schemas-wifialliance-org:service:"
416                               "WFAWLANConfig:1"))
417                         wfa = 1;
418                 if (os_strncasecmp(start, "LOCATION:", 9) == 0) {
419                         start += 9;
420                         while (*start == ' ')
421                                 start++;
422                         location = start;
423                 } else if (os_strncasecmp(start, "NTS:", 4) == 0) {
424                         if (os_strstr(start, "ssdp:byebye"))
425                                 byebye = 1;
426                 } else if (os_strncasecmp(start, "CACHE-CONTROL:", 14) == 0) {
427                         start += 9;
428                         while (*start == ' ')
429                                 start++;
430                         pos2 = os_strstr(start, "max-age=");
431                         if (pos2 == NULL)
432                                 continue;
433                         pos2 += 8;
434                         max_age = atoi(pos2);
435                 }
436         }
437
438         if (!wfa)
439                 return; /* Not WPS advertisement/reply */
440
441         if (byebye) {
442                 wps_er_ap_remove(er, &addr.sin_addr);
443                 return;
444         }
445
446         if (!location)
447                 return; /* Unknown location */
448
449         if (max_age < 1)
450                 return; /* No max-age reported */
451
452         wpa_printf(MSG_DEBUG, "WPS ER: AP discovered: %s "
453                    "(packet source: %s  max-age: %d)",
454                    location, inet_ntoa(addr.sin_addr), max_age);
455
456         wps_er_ap_add(er, &addr.sin_addr, location, max_age);
457 }
458
459
460 static void wps_er_send_ssdp_msearch(struct wps_er *er)
461 {
462         struct wpabuf *msg;
463         struct sockaddr_in dest;
464
465         msg = wpabuf_alloc(500);
466         if (msg == NULL)
467                 return;
468
469         wpabuf_put_str(msg,
470                        "M-SEARCH * HTTP/1.1\r\n"
471                        "HOST: 239.255.255.250:1900\r\n"
472                        "MAN: \"ssdp:discover\"\r\n"
473                        "MX: 3\r\n"
474                        "ST: urn:schemas-wifialliance-org:device:WFADevice:1"
475                        "\r\n"
476                        "\r\n");
477
478         os_memset(&dest, 0, sizeof(dest));
479         dest.sin_family = AF_INET;
480         dest.sin_addr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS);
481         dest.sin_port = htons(UPNP_MULTICAST_PORT);
482
483         if (sendto(er->multicast_sd, wpabuf_head(msg), wpabuf_len(msg), 0,
484                    (struct sockaddr *) &dest, sizeof(dest)) < 0)
485                 wpa_printf(MSG_DEBUG, "WPS ER: M-SEARCH sendto failed: "
486                            "%d (%s)", errno, strerror(errno));
487
488         wpabuf_free(msg);
489 }
490
491
492 static void http_put_date(struct wpabuf *buf)
493 {
494         wpabuf_put_str(buf, "Date: ");
495         format_date(buf);
496         wpabuf_put_str(buf, "\r\n");
497 }
498
499
500 static void wps_er_http_resp_not_found(struct http_request *req)
501 {
502         struct wpabuf *buf;
503         buf = wpabuf_alloc(200);
504         if (buf == NULL) {
505                 http_request_deinit(req);
506                 return;
507         }
508
509         wpabuf_put_str(buf,
510                        "HTTP/1.1 404 Not Found\r\n"
511                        "Server: unspecified, UPnP/1.0, unspecified\r\n"
512                        "Connection: close\r\n");
513         http_put_date(buf);
514         wpabuf_put_str(buf, "\r\n");
515         http_request_send_and_deinit(req, buf);
516 }
517
518
519 static void wps_er_http_resp_ok(struct http_request *req)
520 {
521         struct wpabuf *buf;
522         buf = wpabuf_alloc(200);
523         if (buf == NULL) {
524                 http_request_deinit(req);
525                 return;
526         }
527
528         wpabuf_put_str(buf,
529                        "HTTP/1.1 200 OK\r\n"
530                        "Server: unspecified, UPnP/1.0, unspecified\r\n"
531                        "Connection: close\r\n"
532                        "Content-Length: 0\r\n");
533         http_put_date(buf);
534         wpabuf_put_str(buf, "\r\n");
535         http_request_send_and_deinit(req, buf);
536 }
537
538
539 static void wps_er_process_wlanevent_probe_req(struct wps_er_ap *ap,
540                                                const u8 *addr,
541                                                struct wpabuf *msg)
542 {
543         struct wps_parse_attr attr;
544
545         wpa_printf(MSG_DEBUG, "WPS ER: WLANEvent - Probe Request - from "
546                    MACSTR, MAC2STR(addr));
547         wpa_hexdump_buf(MSG_MSGDUMP, "WPS ER: WLANEvent - Enrollee's message "
548                         "(TLVs from Probe Request)", msg);
549
550         if (wps_parse_msg(msg, &attr) < 0) {
551                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse TLVs in "
552                            "WLANEvent message");
553                 return;
554         }
555
556         /* TODO: add STA table to the AP entry and wpa_msg indication if new
557          * STA */
558 }
559
560
561 static void wps_er_process_wlanevent_eap(struct wps_er_ap *ap, const u8 *addr,
562                                          struct wpabuf *msg)
563 {
564         struct wps_parse_attr attr;
565
566         wpa_printf(MSG_DEBUG, "WPS ER: WLANEvent - EAP - from " MACSTR,
567                    MAC2STR(addr));
568         wpa_hexdump_buf(MSG_MSGDUMP, "WPS ER: WLANEvent - Enrollee's message "
569                         "(TLVs from EAP-WSC)", msg);
570
571         if (wps_parse_msg(msg, &attr) < 0) {
572                 wpa_printf(MSG_DEBUG, "WPS ER: Failed to parse TLVs in "
573                            "WLANEvent message");
574                 return;
575         }
576
577         /* TODO: add STA table to the AP entry and wpa_msg indication if new
578          * STA; process message if it is part of ongoing protocol run */
579 }
580
581
582 static void wps_er_process_wlanevent(struct wps_er_ap *ap,
583                                      struct wpabuf *event)
584 {
585         u8 *data;
586         u8 wlan_event_type;
587         u8 wlan_event_mac[ETH_ALEN];
588         struct wpabuf msg;
589
590         wpa_hexdump(MSG_MSGDUMP, "WPS ER: Received WLANEvent",
591                     wpabuf_head(event), wpabuf_len(event));
592         if (wpabuf_len(event) < 1 + 17) {
593                 wpa_printf(MSG_DEBUG, "WPS ER: Too short WLANEvent");
594                 return;
595         }
596
597         data = wpabuf_mhead(event);
598         wlan_event_type = data[0];
599         if (hwaddr_aton((char *) data + 1, wlan_event_mac) < 0) {
600                 wpa_printf(MSG_DEBUG, "WPS ER: Invalid WLANEventMAC in "
601                            "WLANEvent");
602                 return;
603         }
604
605         wpabuf_set(&msg, data + 1 + 17, wpabuf_len(event) - (1 + 17));
606
607         switch (wlan_event_type) {
608         case 1:
609                 wps_er_process_wlanevent_probe_req(ap, wlan_event_mac, &msg);
610                 break;
611         case 2:
612                 wps_er_process_wlanevent_eap(ap, wlan_event_mac, &msg);
613                 break;
614         default:
615                 wpa_printf(MSG_DEBUG, "WPS ER: Unknown WLANEventType %d",
616                            wlan_event_type);
617                 break;
618         }
619 }
620
621
622 static void wps_er_http_event(struct wps_er *er, struct http_request *req,
623                               unsigned int ap_id)
624 {
625         struct wps_er_ap *ap = wps_er_ap_get_id(er, ap_id);
626         struct wpabuf *event;
627         enum http_reply_code ret;
628
629         if (ap == NULL) {
630                 wpa_printf(MSG_DEBUG, "WPS ER: HTTP event from unknown AP id "
631                            "%u", ap_id);
632                 wps_er_http_resp_not_found(req);
633                 return;
634         }
635         wpa_printf(MSG_MSGDUMP, "WPS ER: HTTP event from AP id %u: %s",
636                    ap_id, http_request_get_data(req));
637
638         event = xml_get_base64_item(http_request_get_data(req), "WLANEvent",
639                                     &ret);
640         if (event == NULL) {
641                 wpa_printf(MSG_DEBUG, "WPS ER: Could not extract WLANEvent "
642                            "from the event notification");
643                 /*
644                  * Reply with OK anyway to avoid getting unregistered from
645                  * events.
646                  */
647                 wps_er_http_resp_ok(req);
648                 return;
649         }
650
651         wps_er_process_wlanevent(ap, event);
652
653         wpabuf_free(event);
654         wps_er_http_resp_ok(req);
655 }
656
657
658 static void wps_er_http_notify(struct wps_er *er, struct http_request *req)
659 {
660         char *uri = http_request_get_uri(req);
661
662         if (os_strncmp(uri, "/event/", 7) == 0) {
663                 wps_er_http_event(er, req, atoi(uri + 7));
664         } else {
665                 wpa_printf(MSG_DEBUG, "WPS ER: Unknown HTTP NOTIFY for '%s'",
666                            uri);
667                 wps_er_http_resp_not_found(req);
668         }
669 }
670
671
672 static void wps_er_http_req(void *ctx, struct http_request *req)
673 {
674         struct wps_er *er = ctx;
675         struct sockaddr_in *cli = http_request_get_cli_addr(req);
676         enum httpread_hdr_type type = http_request_get_type(req);
677         struct wpabuf *buf;
678
679         wpa_printf(MSG_DEBUG, "WPS ER: HTTP request: '%s' (type %d) from "
680                    "%s:%d",
681                    http_request_get_uri(req), type,
682                    inet_ntoa(cli->sin_addr), ntohs(cli->sin_port));
683
684         switch (type) {
685         case HTTPREAD_HDR_TYPE_NOTIFY:
686                 wps_er_http_notify(er, req);
687                 break;
688         default:
689                 wpa_printf(MSG_DEBUG, "WPS ER: Unsupported HTTP request type "
690                            "%d", type);
691                 buf = wpabuf_alloc(200);
692                 if (buf == NULL) {
693                         http_request_deinit(req);
694                         return;
695                 }
696                 wpabuf_put_str(buf,
697                                "HTTP/1.1 501 Unimplemented\r\n"
698                                "Connection: close\r\n");
699                 http_put_date(buf);
700                 wpabuf_put_str(buf, "\r\n");
701                 http_request_send_and_deinit(req, buf);
702                 break;
703         }
704 }
705
706
707 struct wps_er *
708 wps_er_init(struct wps_context *wps, const char *ifname)
709 {
710         struct wps_er *er;
711         struct wps_registrar_config rcfg;
712         struct in_addr addr;
713
714         er = os_zalloc(sizeof(*er));
715         if (er == NULL)
716                 return NULL;
717
718         er->multicast_sd = -1;
719         er->ssdp_sd = -1;
720
721         os_strlcpy(er->ifname, ifname, sizeof(er->ifname));
722         os_memset(&rcfg, 0, sizeof(rcfg));
723         rcfg.pin_needed_cb = wps_er_pin_needed_cb;
724         rcfg.cb_ctx = er;
725
726         er->reg = wps_registrar_init(wps, &rcfg);
727         if (er->reg == NULL) {
728                 wps_er_deinit(er);
729                 return NULL;
730         }
731
732         if (get_netif_info(ifname,
733                            &er->ip_addr, &er->ip_addr_text,
734                            er->mac_addr, &er->mac_addr_text)) {
735                 wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address "
736                            "for %s. Does it have IP address?", ifname);
737                 wps_er_deinit(er);
738                 return NULL;
739         }
740
741         if (add_ssdp_network(ifname)) {
742                 wps_er_deinit(er);
743                 return NULL;
744         }
745
746         er->multicast_sd = ssdp_open_multicast_sock(er->ip_addr);
747         if (er->multicast_sd < 0) {
748                 wps_er_deinit(er);
749                 return NULL;
750         }
751
752         er->ssdp_sd = ssdp_listener_open();
753         if (er->ssdp_sd < 0) {
754                 wps_er_deinit(er);
755                 return NULL;
756         }
757         if (eloop_register_sock(er->multicast_sd, EVENT_TYPE_READ,
758                                 wps_er_ssdp_rx, er, NULL) ||
759             eloop_register_sock(er->ssdp_sd, EVENT_TYPE_READ,
760                                 wps_er_ssdp_rx, er, NULL)) {
761                 wps_er_deinit(er);
762                 return NULL;
763         }
764
765         addr.s_addr = er->ip_addr;
766         er->http_srv = http_server_init(&addr, -1, wps_er_http_req, er);
767         if (er->http_srv == NULL) {
768                 wps_er_deinit(er);
769                 return NULL;
770         }
771         er->http_port = http_server_get_port(er->http_srv);
772
773         wpa_printf(MSG_DEBUG, "WPS ER: Start (ifname=%s ip_addr=%s "
774                    "mac_addr=%s)",
775                    er->ifname, er->ip_addr_text, er->mac_addr_text);
776
777         wps_er_send_ssdp_msearch(er);
778
779         return er;
780 }
781
782
783 void wps_er_deinit(struct wps_er *er)
784 {
785         if (er == NULL)
786                 return;
787         http_server_deinit(er->http_srv);
788         wps_er_ap_remove_all(er);
789         if (er->multicast_sd >= 0) {
790                 eloop_unregister_sock(er->multicast_sd, EVENT_TYPE_READ);
791                 close(er->multicast_sd);
792         }
793         if (er->ssdp_sd >= 0) {
794                 eloop_unregister_sock(er->ssdp_sd, EVENT_TYPE_READ);
795                 close(er->ssdp_sd);
796         }
797         wps_registrar_deinit(er->reg);
798         os_free(er->ip_addr_text);
799         os_free(er->mac_addr_text);
800         os_free(er);
801 }