18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * UPnP SSDP for WPS 38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2000-2003 Intel Corporation 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2006-2007 Sony Corporation 58d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2008-2009 Atheros Communications 68d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2009, Jouni Malinen <j@w1.fi> 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * See wps_upnp.c for more details on licensing and code history. 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h" 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <fcntl.h> 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <sys/ioctl.h> 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <net/route.h> 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h" 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "uuid.h" 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eloop.h" 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps.h" 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps_upnp.h" 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps_upnp_i.h" 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define UPNP_CACHE_SEC (UPNP_CACHE_SEC_MIN + 1) /* cache time we use */ 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define UPNP_CACHE_SEC_MIN 1800 /* min cachable time per UPnP standard */ 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define UPNP_ADVERTISE_REPEAT 2 /* no more than 3 */ 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define MAX_MSEARCH 20 /* max simultaneous M-SEARCH replies ongoing */ 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define SSDP_TARGET "239.0.0.0" 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define SSDP_NETMASK "255.0.0.0" 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Check tokens for equality, where tokens consist of letters, digits, 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * underscore and hyphen, and are matched case insensitive. 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int token_eq(const char *s1, const char *s2) 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int c1; 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int c2; 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int end1 = 0; 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int end2 = 0; 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (;;) { 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt c1 = *s1++; 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt c2 = *s2++; 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (isalpha(c1) && isupper(c1)) 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt c1 = tolower(c1); 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (isalpha(c2) && isupper(c2)) 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt c2 = tolower(c2); 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end1 = !(isalnum(c1) || c1 == '_' || c1 == '-'); 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt end2 = !(isalnum(c2) || c2 == '_' || c2 == '-'); 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (end1 || end2 || c1 != c2) 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return end1 && end2; /* reached end of both words? */ 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Return length of token (see above for definition of token) */ 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int token_length(const char *s) 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const char *begin = s; 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (;; s++) { 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int c = *s; 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int end = !(isalnum(c) || c == '_' || c == '-'); 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (end) 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return s - begin; 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* return length of interword separation. 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This accepts only spaces/tabs and thus will not traverse a line 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * or buffer ending. 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int word_separation_length(const char *s) 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const char *begin = s; 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (;; s++) { 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int c = *s; 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (c == ' ' || c == '\t') 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return s - begin; 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* No. of chars through (including) end of line */ 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int line_length(const char *l) 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const char *lp = l; 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (*lp && *lp != '\n') 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt lp++; 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (*lp == '\n') 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt lp++; 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return lp - l; 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int str_starts(const char *str, const char *start) 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return os_strncmp(str, start, os_strlen(start)) == 0; 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*************************************************************************** 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Advertisements. 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * These are multicast to the world to tell them we are here. 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * The individual packets are spread out in time to limit loss, 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * and then after a much longer period of time the whole sequence 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * is repeated again (for NOTIFYs only). 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt **************************************************************************/ 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * next_advertisement - Build next message and advance the state machine 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @a: Advertisement state 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @islast: Buffer for indicating whether this is the last message (= 1) 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: The new message (caller is responsible for freeing this) 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Note: next_advertisement is shared code with msearchreply_* functions 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnext_advertisement(struct upnp_wps_device_sm *sm, 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct advertisement_state_machine *a, int *islast) 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *msg; 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char *NTString = ""; 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char uuid_string[80]; 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct upnp_wps_device_interface *iface; 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *islast = 0; 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface = dl_list_first(&sm->interfaces, 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct upnp_wps_device_interface, list); 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt uuid_bin2str(iface->wps->uuid, uuid_string, sizeof(uuid_string)); 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg = wpabuf_alloc(800); /* more than big enough */ 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (a->type) { 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ADVERTISE_UP: 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case ADVERTISE_DOWN: 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt NTString = "NT"; 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_str(msg, "NOTIFY * HTTP/1.1\r\n"); 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_printf(msg, "HOST: %s:%d\r\n", 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt UPNP_MULTICAST_ADDRESS, UPNP_MULTICAST_PORT); 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_printf(msg, "CACHE-CONTROL: max-age=%d\r\n", 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt UPNP_CACHE_SEC); 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_printf(msg, "NTS: %s\r\n", 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (a->type == ADVERTISE_UP ? 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "ssdp:alive" : "ssdp:byebye")); 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case MSEARCH_REPLY: 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt NTString = "ST"; 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_str(msg, "HTTP/1.1 200 OK\r\n"); 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_printf(msg, "CACHE-CONTROL: max-age=%d\r\n", 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt UPNP_CACHE_SEC); 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_str(msg, "DATE: "); 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt format_date(msg); 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_str(msg, "\r\n"); 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_str(msg, "EXT:\r\n"); 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (a->type != ADVERTISE_DOWN) { 1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Where others may get our XML files from */ 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_printf(msg, "LOCATION: http://%s:%d/%s\r\n", 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sm->ip_addr_text, sm->web_port, 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt UPNP_WPS_DEVICE_XML_FILE); 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* The SERVER line has three comma-separated fields: 1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * operating system / version 1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * upnp version 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * software package / version 1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * However, only the UPnP version is really required, the 1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * others can be place holders... for security reasons 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * it is better to NOT provide extra information. 1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_str(msg, "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n"); 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt switch (a->state / UPNP_ADVERTISE_REPEAT) { 1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 0: 1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_printf(msg, "%s: upnp:rootdevice\r\n", NTString); 1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_printf(msg, "USN: uuid:%s::upnp:rootdevice\r\n", 1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt uuid_string); 1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 1: 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_printf(msg, "%s: uuid:%s\r\n", NTString, uuid_string); 1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_printf(msg, "USN: uuid:%s\r\n", uuid_string); 1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 2: 1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_printf(msg, "%s: urn:schemas-wifialliance-org:device:" 1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "WFADevice:1\r\n", NTString); 1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_printf(msg, "USN: uuid:%s::urn:schemas-wifialliance-" 1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "org:device:WFADevice:1\r\n", uuid_string); 1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt case 3: 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_printf(msg, "%s: urn:schemas-wifialliance-org:service:" 2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "WFAWLANConfig:1\r\n", NTString); 2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_printf(msg, "USN: uuid:%s::urn:schemas-wifialliance-" 2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "org:service:WFAWLANConfig:1\r\n", uuid_string); 2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_put_str(msg, "\r\n"); 2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (a->state + 1 >= 4 * UPNP_ADVERTISE_REPEAT) 2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *islast = 1; 2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return msg; 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfail: 2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(msg); 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void advertisement_state_machine_handler(void *eloop_data, 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt void *user_ctx); 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * advertisement_state_machine_stop - Stop SSDP advertisements 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: WPS UPnP state machine from upnp_wps_device_init() 2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @send_byebye: Send byebye advertisement messages immediately 2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid advertisement_state_machine_stop(struct upnp_wps_device_sm *sm, 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int send_byebye) 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct advertisement_state_machine *a = &sm->advertisement; 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int islast = 0; 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *msg; 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct sockaddr_in dest; 2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_cancel_timeout(advertisement_state_machine_handler, NULL, sm); 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!send_byebye || sm->multicast_sd < 0) 2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt a->type = ADVERTISE_DOWN; 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt a->state = 0; 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(&dest, 0, sizeof(dest)); 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dest.sin_family = AF_INET; 2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dest.sin_addr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS); 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dest.sin_port = htons(UPNP_MULTICAST_PORT); 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (!islast) { 2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg = next_advertisement(sm, a, &islast); 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) 2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sendto(sm->multicast_sd, wpabuf_head(msg), wpabuf_len(msg), 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 0, (struct sockaddr *) &dest, sizeof(dest)) < 0) { 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "WPS UPnP: Advertisement sendto " 2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "failed: %d (%s)", errno, strerror(errno)); 2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(msg); 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt a->state++; 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void advertisement_state_machine_handler(void *eloop_data, 2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt void *user_ctx) 2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct upnp_wps_device_sm *sm = user_ctx; 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct advertisement_state_machine *a = &sm->advertisement; 2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *msg; 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int next_timeout_msec = 100; 2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int next_timeout_sec = 0; 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct sockaddr_in dest; 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int islast = 0; 2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Each is sent twice (in case lost) w/ 100 msec delay between; 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * spec says no more than 3 times. 2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * One pair for rootdevice, one pair for uuid, and a pair each for 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * each of the two urns. 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * The entire sequence must be repeated before cache control timeout 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * (which is min 1800 seconds), 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * recommend random portion of half of the advertised cache control age 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * to ensure against loss... perhaps 1800/4 + rand*1800/4 ? 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Delay random interval < 100 msec prior to initial sending. 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * TTL of 4 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_MSGDUMP, "WPS UPnP: Advertisement state=%d", a->state); 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg = next_advertisement(sm, a, &islast); 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(&dest, 0, sizeof(dest)); 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dest.sin_family = AF_INET; 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dest.sin_addr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS); 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dest.sin_port = htons(UPNP_MULTICAST_PORT); 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sendto(sm->multicast_sd, wpabuf_head(msg), wpabuf_len(msg), 0, 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (struct sockaddr *) &dest, sizeof(dest)) == -1) { 2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "WPS UPnP: Advertisement sendto failed:" 2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "%d (%s)", errno, strerror(errno)); 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_timeout_msec = 0; 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_timeout_sec = 10; /* ... later */ 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if (islast) { 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt a->state = 0; /* wrap around */ 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (a->type == ADVERTISE_DOWN) { 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "WPS UPnP: ADVERTISE_DOWN->UP"); 3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt a->type = ADVERTISE_UP; 3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* do it all over again right away */ 3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt u16 r; 3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Start over again after a long timeout 3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * (see notes above) 3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_timeout_msec = 0; 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_get_random((void *) &r, sizeof(r)); 3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_timeout_sec = UPNP_CACHE_SEC / 4 + 3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (((UPNP_CACHE_SEC / 4) * r) >> 16); 3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sm->advertise_count++; 3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "WPS UPnP: ADVERTISE_UP (#%u); " 3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "next in %d sec", 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sm->advertise_count, next_timeout_sec); 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt a->state++; 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(msg); 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_register_timeout(next_timeout_sec, next_timeout_msec, 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt advertisement_state_machine_handler, NULL, sm); 3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * advertisement_state_machine_start - Start SSDP advertisements 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: WPS UPnP state machine from upnp_wps_device_init() 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint advertisement_state_machine_start(struct upnp_wps_device_sm *sm) 3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct advertisement_state_machine *a = &sm->advertisement; 3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int next_timeout_msec; 3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt advertisement_state_machine_stop(sm, 0); 3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Start out advertising down, this automatically switches 3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * to advertising up which signals our restart. 3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt a->type = ADVERTISE_DOWN; 3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt a->state = 0; 3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* (other fields not used here) */ 3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* First timeout should be random interval < 100 msec */ 3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_timeout_msec = (100 * (os_random() & 0xFF)) >> 8; 3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return eloop_register_timeout(0, next_timeout_msec, 3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt advertisement_state_machine_handler, 3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt NULL, sm); 3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*************************************************************************** 3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * M-SEARCH replies 3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * These are very similar to the multicast advertisements, with some 3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * small changes in data content; and they are sent (UDP) to a specific 3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * unicast address instead of multicast. 3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * They are sent in response to a UDP M-SEARCH packet. 3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt **************************************************************************/ 3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * msearchreply_state_machine_stop - Stop M-SEARCH reply state machine 3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @a: Selected advertisement/reply state 3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid msearchreply_state_machine_stop(struct advertisement_state_machine *a) 3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "WPS UPnP: M-SEARCH stop"); 3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dl_list_del(&a->list); 3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(a); 3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void msearchreply_state_machine_handler(void *eloop_data, 3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt void *user_ctx) 3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct advertisement_state_machine *a = user_ctx; 3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct upnp_wps_device_sm *sm = eloop_data; 3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct wpabuf *msg; 3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int next_timeout_msec = 100; 3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int next_timeout_sec = 0; 3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int islast = 0; 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Each response is sent twice (in case lost) w/ 100 msec delay 3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * between; spec says no more than 3 times. 3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * One pair for rootdevice, one pair for uuid, and a pair each for 3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * each of the two urns. 3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* TODO: should only send the requested response types */ 4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_MSGDUMP, "WPS UPnP: M-SEARCH reply state=%d (%s:%d)", 4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt a->state, inet_ntoa(a->client.sin_addr), 4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ntohs(a->client.sin_port)); 4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msg = next_advertisement(sm, a, &islast); 4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (msg == NULL) 4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Send it on the multicast socket to avoid having to set up another 4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * socket. 4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sendto(sm->multicast_sd, wpabuf_head(msg), wpabuf_len(msg), 0, 4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (struct sockaddr *) &a->client, sizeof(a->client)) < 0) { 4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "WPS UPnP: M-SEARCH reply sendto " 4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "errno %d (%s) for %s:%d", 4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt errno, strerror(errno), 4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt inet_ntoa(a->client.sin_addr), 4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ntohs(a->client.sin_port)); 4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Ignore error and hope for the best */ 4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpabuf_free(msg); 4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (islast) { 4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "WPS UPnP: M-SEARCH reply done"); 4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msearchreply_state_machine_stop(a); 4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt a->state++; 4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_MSGDUMP, "WPS UPnP: M-SEARCH reply in %d.%03d sec", 4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_timeout_sec, next_timeout_msec); 4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_register_timeout(next_timeout_sec, next_timeout_msec, 4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msearchreply_state_machine_handler, sm, a); 4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * msearchreply_state_machine_start - Reply to M-SEARCH discovery request 4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: WPS UPnP state machine from upnp_wps_device_init() 4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @client: Client address 4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @mx: Maximum delay in seconds 4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Use TTL of 4 (this was done when socket set up). 4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * A response should be given in randomized portion of min(MX,120) seconds 4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * UPnP-arch-DeviceArchitecture, 1.2.3: 4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * To be found, a device must send a UDP response to the source IP address and 4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * port that sent the request to the multicast channel. Devices respond if the 4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * ST header of the M-SEARCH request is "ssdp:all", "upnp:rootdevice", "uuid:" 4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * followed by a UUID that exactly matches one advertised by the device. 4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void msearchreply_state_machine_start(struct upnp_wps_device_sm *sm, 4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct sockaddr_in *client, 4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int mx) 4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct advertisement_state_machine *a; 4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int next_timeout_sec; 4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int next_timeout_msec; 4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int replies; 4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt replies = dl_list_len(&sm->msearch_replies); 4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "WPS UPnP: M-SEARCH reply start (%d " 4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "outstanding)", replies); 4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (replies >= MAX_MSEARCH) { 4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "WPS UPnP: Too many outstanding " 4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "M-SEARCH replies"); 4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt a = os_zalloc(sizeof(*a)); 4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (a == NULL) 4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt a->type = MSEARCH_REPLY; 4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt a->state = 0; 4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(&a->client, client, sizeof(*client)); 4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Wait time depending on MX value */ 4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_timeout_msec = (1000 * mx * (os_random() & 0xFF)) >> 8; 4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_timeout_sec = next_timeout_msec / 1000; 4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt next_timeout_msec = next_timeout_msec % 1000; 4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (eloop_register_timeout(next_timeout_sec, next_timeout_msec, 4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msearchreply_state_machine_handler, sm, 4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt a)) { 4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* No way to recover (from malloc failure) */ 4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Remember for future cleanup */ 4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt dl_list_add(&sm->msearch_replies, &a->list); 4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfail: 4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "WPS UPnP: M-SEARCH reply failure!"); 4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_cancel_timeout(msearchreply_state_machine_handler, sm, a); 4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(a); 4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * ssdp_parse_msearch - Process a received M-SEARCH 4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: WPS UPnP state machine from upnp_wps_device_init() 4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @client: Client address 5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @data: NULL terminated M-SEARCH message 5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Given that we have received a header w/ M-SEARCH, act upon it 5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Format of M-SEARCH (case insensitive!): 5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * First line must be: 5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * M-SEARCH * HTTP/1.1 5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Other lines in arbitrary order: 5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * HOST:239.255.255.250:1900 5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * ST:<varies -- must match> 5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * MAN:"ssdp:discover" 5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * MX:<varies> 5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * It should be noted that when Microsoft Vista is still learning its IP 5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * address, it sends out host lines like: HOST:[FF02::C]:1900 5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ssdp_parse_msearch(struct upnp_wps_device_sm *sm, 5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct sockaddr_in *client, const char *data) 5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef CONFIG_NO_STDOUT_DEBUG 5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const char *start = data; 5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_NO_STDOUT_DEBUG */ 5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int got_host = 0; 5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int got_st = 0, st_match = 0; 5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int got_man = 0; 5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int got_mx = 0; 5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int mx = 0; 5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Skip first line M-SEARCH * HTTP/1.1 5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * (perhaps we should check remainder of the line for syntax) 5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data += line_length(data); 5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Parse remaining lines */ 5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (; *data != '\0'; data += line_length(data)) { 5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (token_eq(data, "host")) { 5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* The host line indicates who the packet 5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * is addressed to... but do we really care? 5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Note that Microsoft sometimes does funny 5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * stuff with the HOST: line. 5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if 0 /* could be */ 5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data += token_length(data); 5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data += word_separation_length(data); 5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (*data != ':') 5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto bad; 5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data++; 5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data += word_separation_length(data); 5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* UPNP_MULTICAST_ADDRESS */ 5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!str_starts(data, "239.255.255.250")) 5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto bad; 5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data += os_strlen("239.255.255.250"); 5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (*data == ':') { 5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!str_starts(data, ":1900")) 5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto bad; 5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* could be */ 5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt got_host = 1; 5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if (token_eq(data, "st")) { 5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* There are a number of forms; we look 5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * for one that matches our case. 5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt got_st = 1; 5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data += token_length(data); 5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data += word_separation_length(data); 5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (*data != ':') 5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data++; 5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data += word_separation_length(data); 5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (str_starts(data, "ssdp:all")) { 5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt st_match = 1; 5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (str_starts(data, "upnp:rootdevice")) { 5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt st_match = 1; 5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (str_starts(data, "uuid:")) { 5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char uuid_string[80]; 5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct upnp_wps_device_interface *iface; 5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface = dl_list_first( 5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &sm->interfaces, 5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct upnp_wps_device_interface, 5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt list); 5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data += os_strlen("uuid:"); 5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt uuid_bin2str(iface->wps->uuid, uuid_string, 5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sizeof(uuid_string)); 5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (str_starts(data, uuid_string)) 5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt st_match = 1; 5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if 0 5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* FIX: should we really reply to IGD string? */ 5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (str_starts(data, "urn:schemas-upnp-org:device:" 5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "InternetGatewayDevice:1")) { 5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt st_match = 1; 5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif 6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (str_starts(data, "urn:schemas-wifialliance-org:" 6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "service:WFAWLANConfig:1")) { 6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt st_match = 1; 6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (str_starts(data, "urn:schemas-wifialliance-org:" 6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "device:WFADevice:1")) { 6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt st_match = 1; 6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if (token_eq(data, "man")) { 6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data += token_length(data); 6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data += word_separation_length(data); 6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (*data != ':') 6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data++; 6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data += word_separation_length(data); 6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!str_starts(data, "\"ssdp:discover\"")) { 6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "WPS UPnP: Unexpected " 6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "M-SEARCH man-field"); 6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto bad; 6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt got_man = 1; 6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if (token_eq(data, "mx")) { 6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data += token_length(data); 6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data += word_separation_length(data); 6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (*data != ':') 6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data++; 6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt data += word_separation_length(data); 6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt mx = atol(data); 6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt got_mx = 1; 6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt continue; 6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* ignore anything else */ 6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!got_host || !got_st || !got_man || !got_mx || mx < 0) { 6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "WPS UPnP: Invalid M-SEARCH: %d %d %d " 6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "%d mx=%d", got_host, got_st, got_man, got_mx, mx); 6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto bad; 6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!st_match) { 6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "WPS UPnP: Ignored M-SEARCH (no ST " 6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "match)"); 6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (mx > 120) 6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt mx = 120; /* UPnP-arch-DeviceArchitecture, 1.2.3 */ 6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt msearchreply_state_machine_start(sm, client, mx); 6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtbad: 6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "WPS UPnP: Failed to parse M-SEARCH"); 6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_MSGDUMP, "WPS UPnP: M-SEARCH data:\n%s", start); 6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Listening for (UDP) discovery (M-SEARCH) packets */ 6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * ssdp_listener_stop - Stop SSDP listered 6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: WPS UPnP state machine from upnp_wps_device_init() 6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function stops the SSDP listener that was started by calling 6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * ssdp_listener_start(). 6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ssdp_listener_stop(struct upnp_wps_device_sm *sm) 6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sm->ssdp_sd_registered) { 6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_unregister_sock(sm->ssdp_sd, EVENT_TYPE_READ); 6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sm->ssdp_sd_registered = 0; 6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sm->ssdp_sd != -1) { 6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt close(sm->ssdp_sd); 6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sm->ssdp_sd = -1; 6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_cancel_timeout(msearchreply_state_machine_handler, sm, 6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ELOOP_ALL_CTX); 6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ssdp_listener_handler(int sd, void *eloop_ctx, void *sock_ctx) 6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct upnp_wps_device_sm *sm = sock_ctx; 6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct sockaddr_in addr; /* client address */ 6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt socklen_t addr_len; 6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int nread; 6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt char buf[MULTICAST_MAX_READ], *pos; 6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr_len = sizeof(addr); 6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nread = recvfrom(sm->ssdp_sd, buf, sizeof(buf) - 1, 0, 6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (struct sockaddr *) &addr, &addr_len); 6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (nread <= 0) 6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt buf[nread] = '\0'; /* need null termination for algorithm */ 7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (str_starts(buf, "NOTIFY ")) { 7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Silently ignore NOTIFYs to avoid filling debug log with 7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * unwanted messages. 7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt pos = os_strchr(buf, '\n'); 7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos) 7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos = '\0'; 7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_MSGDUMP, "WPS UPnP: Received SSDP packet from %s:%d: " 7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "%s", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), buf); 7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (pos) 7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *pos = '\n'; 7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Parse first line */ 7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_strncasecmp(buf, "M-SEARCH", os_strlen("M-SEARCH")) == 0 && 7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !isgraph(buf[strlen("M-SEARCH")])) { 7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ssdp_parse_msearch(sm, &addr, buf); 7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Ignore anything else */ 7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ssdp_listener_open(void) 7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct sockaddr_in addr; 7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ip_mreq mcast_addr; 7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int on = 1; 7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* per UPnP spec, keep IP packet time to live (TTL) small */ 7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt unsigned char ttl = 4; 7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sd; 7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sd = socket(AF_INET, SOCK_DGRAM, 0); 7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sd < 0) 7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0) 7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) 7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(&addr, 0, sizeof(addr)); 7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr.sin_family = AF_INET; 7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr.sin_addr.s_addr = htonl(INADDR_ANY); 7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt addr.sin_port = htons(UPNP_MULTICAST_PORT); 7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (bind(sd, (struct sockaddr *) &addr, sizeof(addr))) 7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(&mcast_addr, 0, sizeof(mcast_addr)); 7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt mcast_addr.imr_interface.s_addr = htonl(INADDR_ANY); 7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt mcast_addr.imr_multiaddr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS); 7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, 7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt (char *) &mcast_addr, sizeof(mcast_addr))) 7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL, 7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &ttl, sizeof(ttl))) 7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return sd; 7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfail: 7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sd >= 0) 7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt close(sd); 7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * ssdp_listener_start - Set up for receiving discovery (UDP) packets 7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: WPS UPnP state machine from upnp_wps_device_init() 7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure 7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * The SSDP listener is stopped by calling ssdp_listener_stop(). 7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ssdp_listener_start(struct upnp_wps_device_sm *sm) 7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sm->ssdp_sd = ssdp_listener_open(); 7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (eloop_register_sock(sm->ssdp_sd, EVENT_TYPE_READ, 7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ssdp_listener_handler, NULL, sm)) 7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sm->ssdp_sd_registered = 1; 7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfail: 7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Error */ 7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, "WPS UPnP: ssdp_listener_start failed"); 7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ssdp_listener_stop(sm); 7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 7928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 7938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 7958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * add_ssdp_network - Add routing entry for SSDP 7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @net_if: Selected network interface name 7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure 7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function assures that the multicast address will be properly 8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * handled by Linux networking code (by a modification to routing tables). 8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This must be done per network interface. It really only needs to be done 8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * once after booting up, but it does not hurt to call this more frequently 8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * "to be safe". 8058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 8068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint add_ssdp_network(const char *net_if) 8078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef __linux__ 8098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret = -1; 8108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sock = -1; 8118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct rtentry rt; 8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct sockaddr_in *sin; 8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!net_if) 8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(&rt, 0, sizeof(rt)); 8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sock = socket(AF_INET, SOCK_DGRAM, 0); 8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sock < 0) 8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rt.rt_dev = (char *) net_if; 8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sin = aliasing_hide_typecast(&rt.rt_dst, struct sockaddr_in); 8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sin->sin_family = AF_INET; 8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sin->sin_port = 0; 8268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sin->sin_addr.s_addr = inet_addr(SSDP_TARGET); 8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sin = aliasing_hide_typecast(&rt.rt_genmask, struct sockaddr_in); 8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sin->sin_family = AF_INET; 8298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sin->sin_port = 0; 8308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sin->sin_addr.s_addr = inet_addr(SSDP_NETMASK); 8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt rt.rt_flags = RTF_UP; 8328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ioctl(sock, SIOCADDRT, &rt) < 0) { 8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (errno == EPERM) { 8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "add_ssdp_network: No " 8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "permissions to add routing table entry"); 8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* Continue to allow testing as non-root */ 8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if (errno != EEXIST) { 8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_INFO, "add_ssdp_network() ioctl errno " 8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "%d (%s)", errno, strerror(errno)); 8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt goto fail; 8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = 0; 8458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfail: 8478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sock >= 0) 8488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt close(sock); 8498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ret; 8518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* __linux__ */ 8528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 8538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* __linux__ */ 8548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 8558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ssdp_open_multicast_sock(u32 ip_addr) 8588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 8598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int sd; 8608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* per UPnP-arch-DeviceArchitecture, 1. Discovery, keep IP packet 8618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * time to live (TTL) small */ 8628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt unsigned char ttl = 4; 8638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sd = socket(AF_INET, SOCK_DGRAM, 0); 8658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sd < 0) 8668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 8678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if 0 /* maybe ok if we sometimes block on writes */ 86904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0) { 87004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt close(sd); 8718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 87204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt } 8738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif 8748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, 8768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &ip_addr, sizeof(ip_addr))) { 8778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "WPS: setsockopt(IP_MULTICAST_IF) %x: " 8788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "%d (%s)", ip_addr, errno, strerror(errno)); 87904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt close(sd); 8808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 8818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL, 8838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt &ttl, sizeof(ttl))) { 8848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "WPS: setsockopt(IP_MULTICAST_TTL): " 8858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "%d (%s)", errno, strerror(errno)); 88604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt close(sd); 8878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 8888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 8898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 8908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if 0 /* not needed, because we don't receive using multicast_sd */ 8918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt { 8928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ip_mreq mreq; 8938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt mreq.imr_multiaddr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS); 8948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt mreq.imr_interface.s_addr = ip_addr; 8958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "WPS UPnP: Multicast addr 0x%x if addr " 8968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "0x%x", 8978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt mreq.imr_multiaddr.s_addr, 8988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt mreq.imr_interface.s_addr); 8998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, 9008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sizeof(mreq))) { 9018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_ERROR, 9028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "WPS UPnP: setsockopt " 9038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "IP_ADD_MEMBERSHIP errno %d (%s)", 9048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt errno, strerror(errno)); 90504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt close(sd); 9068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 9078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 9098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* not needed */ 9108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 9128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * TODO: What about IP_MULTICAST_LOOP? It seems to be on by default? 9138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * which aids debugging I suppose but isn't really necessary? 9148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 9158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return sd; 9178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 9188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 9208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/** 9218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * ssdp_open_multicast - Open socket for sending multicast SSDP messages 9228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: WPS UPnP state machine from upnp_wps_device_init() 9238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure 9248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 9258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ssdp_open_multicast(struct upnp_wps_device_sm *sm) 9268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 9278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt sm->multicast_sd = ssdp_open_multicast_sock(sm->ip_addr); 9288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (sm->multicast_sd < 0) 9298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return -1; 9308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 9318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 932