wps_er_ssdp.c revision c5ec7f57ead87efa365800228aa0b09a12d9e6c4
18ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project/*
28ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project * Wi-Fi Protected Setup - External Registrar (SSDP)
38ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
48ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project *
58ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project * This software may be distributed under the terms of the BSD license.
68ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project * See README for more details.
78ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project */
88ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
98ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project#include "includes.h"
108ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
118ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project#include "common.h"
128ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project#include "uuid.h"
138ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project#include "eloop.h"
148ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project#include "wps_i.h"
158ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project#include "wps_upnp.h"
168ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project#include "wps_upnp_i.h"
178ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project#include "wps_er.h"
188ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
198ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
208ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Projectstatic void wps_er_ssdp_rx(int sd, void *eloop_ctx, void *sock_ctx)
218ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project{
228ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	struct wps_er *er = eloop_ctx;
238ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	struct sockaddr_in addr; /* client address */
248ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	socklen_t addr_len;
258ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	int nread;
268ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	char buf[MULTICAST_MAX_READ], *pos, *pos2, *start;
278ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	int wfa = 0, byebye = 0;
288ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	int max_age = -1;
298ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	char *location = NULL;
308ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	u8 uuid[WPS_UUID_LEN];
318ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
328ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	addr_len = sizeof(addr);
338ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	nread = recvfrom(sd, buf, sizeof(buf) - 1, 0,
348ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			 (struct sockaddr *) &addr, &addr_len);
358ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	if (nread <= 0)
368ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		return;
378ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	buf[nread] = '\0';
388ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	if (er->filter_addr.s_addr &&
398ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	    er->filter_addr.s_addr != addr.sin_addr.s_addr)
408ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		return;
418ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
428ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	wpa_printf(MSG_DEBUG, "WPS ER: Received SSDP from %s",
438ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		   inet_ntoa(addr.sin_addr));
448ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Received SSDP contents",
458ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			  (u8 *) buf, nread);
468ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
478ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	if (sd == er->multicast_sd) {
488ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		/* Reply to M-SEARCH */
498ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		if (os_strncmp(buf, "HTTP/1.1 200 OK", 15) != 0)
508ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			return; /* unexpected response header */
518ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	} else {
528ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		/* Unsolicited message (likely NOTIFY or M-SEARCH) */
538ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		if (os_strncmp(buf, "NOTIFY ", 7) != 0)
548ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			return; /* only process notifications */
558ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	}
568ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
578ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	os_memset(uuid, 0, sizeof(uuid));
588ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
598ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	for (start = buf; start && *start; start = pos) {
608ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		pos = os_strchr(start, '\n');
618ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		if (pos) {
628ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			if (pos[-1] == '\r')
638ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project				pos[-1] = '\0';
646c569d212164aa9334e27abac8884a3d13999420Colin Cross			*pos++ = '\0';
658ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		}
668ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		if (os_strstr(start, "schemas-wifialliance-org:device:"
678ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			      "WFADevice:1"))
688ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			wfa = 1;
698ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		if (os_strstr(start, "schemas-wifialliance-org:service:"
708ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			      "WFAWLANConfig:1"))
718ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			wfa = 1;
728ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		if (os_strncasecmp(start, "LOCATION:", 9) == 0) {
738ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			start += 9;
748ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			while (*start == ' ')
758ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project				start++;
768ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			location = start;
778ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		} else if (os_strncasecmp(start, "NTS:", 4) == 0) {
788ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			if (os_strstr(start, "ssdp:byebye"))
798ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project				byebye = 1;
808ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		} else if (os_strncasecmp(start, "CACHE-CONTROL:", 14) == 0) {
818ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			start += 9;
828ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			while (*start == ' ')
838ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project				start++;
848527dca81baa73fba64d6724bd498195ed1abbf2Nick Kralevich			pos2 = os_strstr(start, "max-age=");
858527dca81baa73fba64d6724bd498195ed1abbf2Nick Kralevich			if (pos2 == NULL)
868ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project				continue;
878ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			pos2 += 8;
888ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			max_age = atoi(pos2);
898ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		} else if (os_strncasecmp(start, "USN:", 4) == 0) {
908ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			start += 4;
918ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			pos2 = os_strstr(start, "uuid:");
928ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			if (pos2) {
938ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project				pos2 += 5;
948ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project				while (*pos2 == ' ')
958ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project					pos2++;
968ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project				if (uuid_str2bin(pos2, uuid) < 0) {
978ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project					wpa_printf(MSG_DEBUG, "WPS ER: "
988ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project						   "Invalid UUID in USN: %s",
998ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project						   pos2);
1008ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project					return;
1018ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project				}
1028ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			}
1038ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		}
1048ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	}
1058ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
1068ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	if (!wfa)
1078ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		return; /* Not WPS advertisement/reply */
1088ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
1098ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	if (byebye) {
1108ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		wps_er_ap_cache_settings(er, &addr.sin_addr);
1118ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		wps_er_ap_remove(er, &addr.sin_addr);
1128ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		return;
1138ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	}
1148ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
1158ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	if (!location)
1168ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		return; /* Unknown location */
1178ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
1188ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	if (max_age < 1)
1198ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		return; /* No max-age reported */
1208ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
1218ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	wpa_printf(MSG_DEBUG, "WPS ER: AP discovered: %s "
1228ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		   "(packet source: %s  max-age: %d)",
1238527dca81baa73fba64d6724bd498195ed1abbf2Nick Kralevich		   location, inet_ntoa(addr.sin_addr), max_age);
1248ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
1258ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	wps_er_ap_add(er, uuid, &addr.sin_addr, location, max_age);
1268ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project}
1278ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
1288ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
1298ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Projectvoid wps_er_send_ssdp_msearch(struct wps_er *er)
1308ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project{
1318ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	struct wpabuf *msg;
1328ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	struct sockaddr_in dest;
1338ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
1348ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	msg = wpabuf_alloc(500);
1358ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	if (msg == NULL)
1368ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		return;
1378ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
1388ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	wpabuf_put_str(msg,
1398ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		       "M-SEARCH * HTTP/1.1\r\n"
1408ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		       "HOST: 239.255.255.250:1900\r\n"
1418ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		       "MAN: \"ssdp:discover\"\r\n"
1428ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		       "MX: 3\r\n"
1438ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		       "ST: urn:schemas-wifialliance-org:device:WFADevice:1"
1448ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		       "\r\n"
1458ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		       "\r\n");
1468ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
1478ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	os_memset(&dest, 0, sizeof(dest));
1488ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	dest.sin_family = AF_INET;
1498ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	dest.sin_addr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS);
1508ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	dest.sin_port = htons(UPNP_MULTICAST_PORT);
1518ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
1528ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	if (sendto(er->multicast_sd, wpabuf_head(msg), wpabuf_len(msg), 0,
1538ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		   (struct sockaddr *) &dest, sizeof(dest)) < 0)
1548ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		wpa_printf(MSG_DEBUG, "WPS ER: M-SEARCH sendto failed: "
1558ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			   "%d (%s)", errno, strerror(errno));
1568ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
1578ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	wpabuf_free(msg);
1588ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project}
1598ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
1608ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
1618ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Projectint wps_er_ssdp_init(struct wps_er *er)
1628ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project{
1638ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	if (add_ssdp_network(er->ifname)) {
1648ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		wpa_printf(MSG_INFO, "WPS ER: Failed to add routing entry for "
1658ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			   "SSDP");
1668ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		return -1;
1678ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	}
1688ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
1698ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	er->multicast_sd = ssdp_open_multicast_sock(er->ip_addr);
1708ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	if (er->multicast_sd < 0) {
1718ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		wpa_printf(MSG_INFO, "WPS ER: Failed to open multicast socket "
1728ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			   "for SSDP");
1738ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		return -1;
1748ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	}
1758ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
1768ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	er->ssdp_sd = ssdp_listener_open();
1778ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	if (er->ssdp_sd < 0) {
1788ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		wpa_printf(MSG_INFO, "WPS ER: Failed to open SSDP listener "
1798ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project			   "socket");
1808ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		return -1;
1818ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	}
1828ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
1838ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	if (eloop_register_sock(er->multicast_sd, EVENT_TYPE_READ,
1848ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project				wps_er_ssdp_rx, er, NULL) ||
1858ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	    eloop_register_sock(er->ssdp_sd, EVENT_TYPE_READ,
1868ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project				wps_er_ssdp_rx, er, NULL))
1878ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		return -1;
1888ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
1898ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	wps_er_send_ssdp_msearch(er);
1908ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
1918ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	return 0;
1928ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project}
1938ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
1948ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project
1958ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Projectvoid wps_er_ssdp_deinit(struct wps_er *er)
1968ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project{
1978ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	if (er->multicast_sd >= 0) {
1988ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		eloop_unregister_sock(er->multicast_sd, EVENT_TYPE_READ);
1998ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		close(er->multicast_sd);
2008ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	}
2018ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	if (er->ssdp_sd >= 0) {
2028ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		eloop_unregister_sock(er->ssdp_sd, EVENT_TYPE_READ);
2038ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project		close(er->ssdp_sd);
2048ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project	}
2058ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project}
2068ad0dd2a5c5f23cd210aedba72a43e48026e7436The Android Open Source Project