wps_upnp.c 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108
  1. /*
  2. * UPnP WPS Device
  3. * Copyright (c) 2000-2003 Intel Corporation
  4. * Copyright (c) 2006-2007 Sony Corporation
  5. * Copyright (c) 2008-2009 Atheros Communications
  6. * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  7. *
  8. * See below for more details on licensing and code history.
  9. */
  10. /*
  11. * This has been greatly stripped down from the original file
  12. * (upnp_wps_device.c) by Ted Merrill, Atheros Communications
  13. * in order to eliminate use of the bulky libupnp library etc.
  14. *
  15. * History:
  16. * upnp_wps_device.c is/was a shim layer between wps_opt_upnp.c and
  17. * the libupnp library.
  18. * The layering (by Sony) was well done; only a very minor modification
  19. * to API of upnp_wps_device.c was required.
  20. * libupnp was found to be undesirable because:
  21. * -- It consumed too much code and data space
  22. * -- It uses multiple threads, making debugging more difficult
  23. * and possibly reducing reliability.
  24. * -- It uses static variables and only supports one instance.
  25. * The shim and libupnp are here replaced by special code written
  26. * specifically for the needs of hostapd.
  27. * Various shortcuts can and are taken to keep the code size small.
  28. * Generally, execution time is not as crucial.
  29. *
  30. * BUGS:
  31. * -- UPnP requires that we be able to resolve domain names.
  32. * While uncommon, if we have to do it then it will stall the entire
  33. * hostapd program, which is bad.
  34. * This is because we use the standard linux getaddrinfo() function
  35. * which is syncronous.
  36. * An asyncronous solution would be to use the free "ares" library.
  37. * -- Does not have a robust output buffering scheme. Uses a single
  38. * fixed size output buffer per TCP/HTTP connection, with possible (although
  39. * unlikely) possibility of overflow and likely excessive use of RAM.
  40. * A better solution would be to write the HTTP output as a buffered stream,
  41. * using chunking: (handle header specially, then) generate data with
  42. * a printf-like function into a buffer, catching buffer full condition,
  43. * then send it out surrounded by http chunking.
  44. * -- There is some code that could be separated out into the common
  45. * library to be shared with wpa_supplicant.
  46. * -- Needs renaming with module prefix to avoid polluting the debugger
  47. * namespace and causing possible collisions with other static fncs
  48. * and structure declarations when using the debugger.
  49. * -- Just what should be in the first event message sent after subscription
  50. * for the WLANEvent field? If i pass it empty, Vista replies with OK
  51. * but apparently barfs on the message.
  52. * -- The http error code generation is pretty bogus, hopefully noone cares.
  53. *
  54. * Author: Ted Merrill, Atheros Communications, based upon earlier work
  55. * as explained above and below.
  56. *
  57. * Copyright:
  58. * Copyright 2008 Atheros Communications.
  59. *
  60. * The original header (of upnp_wps_device.c) reads:
  61. *
  62. * Copyright (c) 2006-2007 Sony Corporation. All Rights Reserved.
  63. *
  64. * File Name: upnp_wps_device.c
  65. * Description: EAP-WPS UPnP device source
  66. *
  67. * Redistribution and use in source and binary forms, with or without
  68. * modification, are permitted provided that the following conditions
  69. * are met:
  70. *
  71. * * Redistributions of source code must retain the above copyright
  72. * notice, this list of conditions and the following disclaimer.
  73. * * Redistributions in binary form must reproduce the above copyright
  74. * notice, this list of conditions and the following disclaimer in
  75. * the documentation and/or other materials provided with the
  76. * distribution.
  77. * * Neither the name of Sony Corporation nor the names of its
  78. * contributors may be used to endorse or promote products derived
  79. * from this software without specific prior written permission.
  80. *
  81. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  82. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  83. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  84. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  85. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  86. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  87. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  88. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  89. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  90. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  91. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  92. *
  93. * Portions from Intel libupnp files, e.g. genlib/net/http/httpreadwrite.c
  94. * typical header:
  95. *
  96. * Copyright (c) 2000-2003 Intel Corporation
  97. * All rights reserved.
  98. *
  99. * Redistribution and use in source and binary forms, with or without
  100. * modification, are permitted provided that the following conditions are met:
  101. *
  102. * * Redistributions of source code must retain the above copyright notice,
  103. * this list of conditions and the following disclaimer.
  104. * * Redistributions in binary form must reproduce the above copyright notice,
  105. * this list of conditions and the following disclaimer in the documentation
  106. * and/or other materials provided with the distribution.
  107. * * Neither name of Intel Corporation nor the names of its contributors
  108. * may be used to endorse or promote products derived from this software
  109. * without specific prior written permission.
  110. *
  111. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  112. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  113. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  114. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
  115. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  116. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  117. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  118. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  119. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  120. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  121. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  122. */
  123. /*
  124. * Overview of WPS over UPnP:
  125. *
  126. * UPnP is a protocol that allows devices to discover each other and control
  127. * each other. In UPnP terminology, a device is either a "device" (a server
  128. * that provides information about itself and allows itself to be controlled)
  129. * or a "control point" (a client that controls "devices") or possibly both.
  130. * This file implements a UPnP "device".
  131. *
  132. * For us, we use mostly basic UPnP discovery, but the control part of interest
  133. * is WPS carried via UPnP messages. There is quite a bit of basic UPnP
  134. * discovery to do before we can get to WPS, however.
  135. *
  136. * UPnP discovery begins with "devices" send out multicast UDP packets to a
  137. * certain fixed multicast IP address and port, and "control points" sending
  138. * out other such UDP packets.
  139. *
  140. * The packets sent by devices are NOTIFY packets (not to be confused with TCP
  141. * NOTIFY packets that are used later) and those sent by control points are
  142. * M-SEARCH packets. These packets contain a simple HTTP style header. The
  143. * packets are sent redundantly to get around packet loss. Devices respond to
  144. * M-SEARCH packets with HTTP-like UDP packets containing HTTP/1.1 200 OK
  145. * messages, which give similar information as the UDP NOTIFY packets.
  146. *
  147. * The above UDP packets advertise the (arbitrary) TCP ports that the
  148. * respective parties will listen to. The control point can then do a HTTP
  149. * SUBSCRIBE (something like an HTTP PUT) after which the device can do a
  150. * separate HTTP NOTIFY (also like an HTTP PUT) to do event messaging.
  151. *
  152. * The control point will also do HTTP GET of the "device file" listed in the
  153. * original UDP information from the device (see UPNP_WPS_DEVICE_XML_FILE
  154. * data), and based on this will do additional GETs... HTTP POSTs are done to
  155. * cause an action.
  156. *
  157. * Beyond some basic information in HTTP headers, additional information is in
  158. * the HTTP bodies, in a format set by the SOAP and XML standards, a markup
  159. * language related to HTML used for web pages. This language is intended to
  160. * provide the ultimate in self-documentation by providing a universal
  161. * namespace based on pseudo-URLs called URIs. Note that although a URI looks
  162. * like a URL (a web address), they are never accessed as such but are used
  163. * only as identifiers.
  164. *
  165. * The POST of a GetDeviceInfo gets information similar to what might be
  166. * obtained from a probe request or response on Wi-Fi. WPS messages M1-M8
  167. * are passed via a POST of a PutMessage; the M1-M8 WPS messages are converted
  168. * to a bin64 ascii representation for encapsulation. When proxying messages,
  169. * WLANEvent and PutWLANResponse are used.
  170. *
  171. * This of course glosses over a lot of details.
  172. */
  173. #include "includes.h"
  174. #include <assert.h>
  175. #include <net/if.h>
  176. #include <netdb.h>
  177. #include <sys/ioctl.h>
  178. #include "common.h"
  179. #include "uuid.h"
  180. #include "base64.h"
  181. #include "wps.h"
  182. #include "wps_i.h"
  183. #include "wps_upnp.h"
  184. #include "wps_upnp_i.h"
  185. /*
  186. * UPnP allows a client ("control point") to send a server like us ("device")
  187. * a domain name for registration, and we are supposed to resolve it. This is
  188. * bad because, using the standard Linux library, we will stall the entire
  189. * hostapd waiting for resolution.
  190. *
  191. * The "correct" solution would be to use an event driven library for domain
  192. * name resolution such as "ares". However, this would increase code size
  193. * further. Since it is unlikely that we'll actually see such domain names, we
  194. * can just refuse to accept them.
  195. */
  196. #define NO_DOMAIN_NAME_RESOLUTION 1 /* 1 to allow only dotted ip addresses */
  197. /*
  198. * UPnP does not scale well. If we were in a room with thousands of control
  199. * points then potentially we could be expected to handle subscriptions for
  200. * each of them, which would exhaust our memory. So we must set a limit. In
  201. * practice we are unlikely to see more than one or two.
  202. */
  203. #define MAX_SUBSCRIPTIONS 4 /* how many subscribing clients we handle */
  204. #define MAX_ADDR_PER_SUBSCRIPTION 8
  205. /* Write the current date/time per RFC */
  206. void format_date(struct wpabuf *buf)
  207. {
  208. const char *weekday_str = "Sun\0Mon\0Tue\0Wed\0Thu\0Fri\0Sat";
  209. const char *month_str = "Jan\0Feb\0Mar\0Apr\0May\0Jun\0"
  210. "Jul\0Aug\0Sep\0Oct\0Nov\0Dec";
  211. struct tm *date;
  212. time_t t;
  213. t = time(NULL);
  214. date = gmtime(&t);
  215. wpabuf_printf(buf, "%s, %02d %s %d %02d:%02d:%02d GMT",
  216. &weekday_str[date->tm_wday * 4], date->tm_mday,
  217. &month_str[date->tm_mon * 4], date->tm_year + 1900,
  218. date->tm_hour, date->tm_min, date->tm_sec);
  219. }
  220. /***************************************************************************
  221. * UUIDs (unique identifiers)
  222. *
  223. * These are supposed to be unique in all the world.
  224. * Sometimes permanent ones are used, sometimes temporary ones
  225. * based on random numbers... there are different rules for valid content
  226. * of different types.
  227. * Each uuid is 16 bytes long.
  228. **************************************************************************/
  229. /* uuid_make -- construct a random UUID
  230. * The UPnP documents don't seem to offer any guidelines as to which method to
  231. * use for constructing UUIDs for subscriptions. Presumably any method from
  232. * rfc4122 is good enough; I've chosen random number method.
  233. */
  234. static void uuid_make(u8 uuid[UUID_LEN])
  235. {
  236. os_get_random(uuid, UUID_LEN);
  237. /* Replace certain bits as specified in rfc4122 or X.667 */
  238. uuid[6] &= 0x0f; uuid[6] |= (4 << 4); /* version 4 == random gen */
  239. uuid[8] &= 0x3f; uuid[8] |= 0x80;
  240. }
  241. /*
  242. * Subscriber address handling.
  243. * Since a subscriber may have an arbitrary number of addresses, we have to
  244. * add a bunch of code to handle them.
  245. *
  246. * Addresses are passed in text, and MAY be domain names instead of the (usual
  247. * and expected) dotted IP addresses. Resolving domain names consumes a lot of
  248. * resources. Worse, we are currently using the standard Linux getaddrinfo()
  249. * which will block the entire program until complete or timeout! The proper
  250. * solution would be to use the "ares" library or similar with more state
  251. * machine steps etc. or just disable domain name resolution by setting
  252. * NO_DOMAIN_NAME_RESOLUTION to 1 at top of this file.
  253. */
  254. /* subscr_addr_delete -- delete single unlinked subscriber address
  255. * (be sure to unlink first if need be)
  256. */
  257. static void subscr_addr_delete(struct subscr_addr *a)
  258. {
  259. /*
  260. * Note: do NOT free domain_and_port or path because they point to
  261. * memory within the allocation of "a".
  262. */
  263. os_free(a);
  264. }
  265. /* subscr_addr_unlink -- unlink subscriber address from linked list */
  266. static void subscr_addr_unlink(struct subscription *s, struct subscr_addr *a)
  267. {
  268. struct subscr_addr **listp = &s->addr_list;
  269. s->n_addr--;
  270. a->next->prev = a->prev;
  271. a->prev->next = a->next;
  272. if (*listp == a) {
  273. if (a == a->next) {
  274. /* last in queue */
  275. *listp = NULL;
  276. assert(s->n_addr == 0);
  277. } else {
  278. *listp = a->next;
  279. }
  280. }
  281. }
  282. /* subscr_addr_free_all -- unlink and delete list of subscriber addresses. */
  283. static void subscr_addr_free_all(struct subscription *s)
  284. {
  285. struct subscr_addr **listp = &s->addr_list;
  286. struct subscr_addr *a;
  287. while ((a = *listp) != NULL) {
  288. subscr_addr_unlink(s, a);
  289. subscr_addr_delete(a);
  290. }
  291. }
  292. /* subscr_addr_link -- add subscriber address to list of addresses */
  293. static void subscr_addr_link(struct subscription *s, struct subscr_addr *a)
  294. {
  295. struct subscr_addr **listp = &s->addr_list;
  296. s->n_addr++;
  297. if (*listp == NULL) {
  298. *listp = a->next = a->prev = a;
  299. } else {
  300. a->next = *listp;
  301. a->prev = (*listp)->prev;
  302. a->prev->next = a;
  303. a->next->prev = a;
  304. }
  305. }
  306. /* subscr_addr_add_url -- add address(es) for one url to subscription */
  307. static void subscr_addr_add_url(struct subscription *s, const char *url)
  308. {
  309. int alloc_len;
  310. char *scratch_mem = NULL;
  311. char *mem;
  312. char *domain_and_port;
  313. char *delim;
  314. char *path;
  315. char *domain;
  316. int port = 80; /* port to send to (default is port 80) */
  317. struct addrinfo hints;
  318. struct addrinfo *result = NULL;
  319. struct addrinfo *rp;
  320. int rerr;
  321. struct subscr_addr *a = NULL;
  322. /* url MUST begin with http: */
  323. if (os_strncasecmp(url, "http://", 7))
  324. goto fail;
  325. url += 7;
  326. /* allocate memory for the extra stuff we need */
  327. alloc_len = (2 * (os_strlen(url) + 1));
  328. scratch_mem = os_zalloc(alloc_len);
  329. if (scratch_mem == NULL)
  330. goto fail;
  331. mem = scratch_mem;
  332. strcpy(mem, url);
  333. domain_and_port = mem;
  334. mem += 1 + os_strlen(mem);
  335. delim = os_strchr(domain_and_port, '/');
  336. if (delim) {
  337. *delim++ = 0; /* null terminate domain and port */
  338. path = delim;
  339. } else {
  340. path = domain_and_port + os_strlen(domain_and_port);
  341. }
  342. domain = mem;
  343. strcpy(domain, domain_and_port);
  344. delim = strchr(domain, ':');
  345. if (delim) {
  346. *delim++ = 0; /* null terminate domain */
  347. if (isdigit(*delim))
  348. port = atol(delim);
  349. }
  350. /*
  351. * getaddrinfo does the right thing with dotted decimal notations, or
  352. * will resolve domain names. Resolving domain names will unfortunately
  353. * hang the entire program until it is resolved or it times out
  354. * internal to getaddrinfo; fortunately we think that the use of actual
  355. * domain names (vs. dotted decimal notations) should be uncommon.
  356. */
  357. os_memset(&hints, 0, sizeof(struct addrinfo));
  358. hints.ai_family = AF_INET; /* IPv4 */
  359. hints.ai_socktype = SOCK_STREAM;
  360. #if NO_DOMAIN_NAME_RESOLUTION
  361. /* Suppress domain name resolutions that would halt
  362. * the program for periods of time
  363. */
  364. hints.ai_flags = AI_NUMERICHOST;
  365. #else
  366. /* Allow domain name resolution. */
  367. hints.ai_flags = 0;
  368. #endif
  369. hints.ai_protocol = 0; /* Any protocol? */
  370. rerr = getaddrinfo(domain, NULL /* fill in port ourselves */,
  371. &hints, &result);
  372. if (rerr) {
  373. wpa_printf(MSG_INFO, "WPS UPnP: Resolve error %d (%s) on: %s",
  374. rerr, gai_strerror(rerr), domain);
  375. goto fail;
  376. }
  377. for (rp = result; rp; rp = rp->ai_next) {
  378. /* Limit no. of address to avoid denial of service attack */
  379. if (s->n_addr >= MAX_ADDR_PER_SUBSCRIPTION) {
  380. wpa_printf(MSG_INFO, "WPS UPnP: subscr_addr_add_url: "
  381. "Ignoring excessive addresses");
  382. break;
  383. }
  384. a = os_zalloc(sizeof(*a) + alloc_len);
  385. if (a == NULL)
  386. continue;
  387. a->s = s;
  388. mem = (void *) (a + 1);
  389. a->domain_and_port = mem;
  390. strcpy(mem, domain_and_port);
  391. mem += 1 + strlen(mem);
  392. a->path = mem;
  393. if (path[0] != '/')
  394. *mem++ = '/';
  395. strcpy(mem, path);
  396. mem += 1 + strlen(mem);
  397. os_memcpy(&a->saddr, rp->ai_addr, sizeof(a->saddr));
  398. a->saddr.sin_port = htons(port);
  399. subscr_addr_link(s, a);
  400. a = NULL; /* don't free it below */
  401. }
  402. fail:
  403. if (result)
  404. freeaddrinfo(result);
  405. os_free(scratch_mem);
  406. os_free(a);
  407. }
  408. /* subscr_addr_list_create -- create list from urls in string.
  409. * Each url is enclosed by angle brackets.
  410. */
  411. static void subscr_addr_list_create(struct subscription *s,
  412. const char *url_list)
  413. {
  414. char *end;
  415. for (;;) {
  416. while (*url_list == ' ' || *url_list == '\t')
  417. url_list++;
  418. if (*url_list != '<')
  419. break;
  420. url_list++;
  421. end = os_strchr(url_list, '>');
  422. if (end == NULL)
  423. break;
  424. *end++ = 0;
  425. subscr_addr_add_url(s, url_list);
  426. url_list = end;
  427. }
  428. }
  429. int send_wpabuf(int fd, struct wpabuf *buf)
  430. {
  431. wpa_printf(MSG_DEBUG, "WPS UPnP: Send %lu byte message",
  432. (unsigned long) wpabuf_len(buf));
  433. errno = 0;
  434. if (write(fd, wpabuf_head(buf), wpabuf_len(buf)) !=
  435. (int) wpabuf_len(buf)) {
  436. wpa_printf(MSG_ERROR, "WPS UPnP: Failed to send buffer: "
  437. "errno=%d (%s)",
  438. errno, strerror(errno));
  439. return -1;
  440. }
  441. return 0;
  442. }
  443. static void wpabuf_put_property(struct wpabuf *buf, const char *name,
  444. const char *value)
  445. {
  446. wpabuf_put_str(buf, "<e:property>");
  447. wpabuf_printf(buf, "<%s>", name);
  448. if (value)
  449. wpabuf_put_str(buf, value);
  450. wpabuf_printf(buf, "</%s>", name);
  451. wpabuf_put_str(buf, "</e:property>\n");
  452. }
  453. /**
  454. * upnp_wps_device_send_event - Queue event messages for subscribers
  455. * @sm: WPS UPnP state machine from upnp_wps_device_init()
  456. *
  457. * This function queues the last WLANEvent to be sent for all currently
  458. * subscribed UPnP control points. sm->wlanevent must have been set with the
  459. * encoded data before calling this function.
  460. */
  461. static void upnp_wps_device_send_event(struct upnp_wps_device_sm *sm)
  462. {
  463. /* Enqueue event message for all subscribers */
  464. struct wpabuf *buf; /* holds event message */
  465. int buf_size = 0;
  466. struct subscription *s;
  467. /* Actually, utf-8 is the default, but it doesn't hurt to specify it */
  468. const char *format_head =
  469. "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
  470. "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">\n";
  471. const char *format_tail = "</e:propertyset>\n";
  472. if (sm->subscriptions == NULL) {
  473. /* optimize */
  474. return;
  475. }
  476. /* Determine buffer size needed first */
  477. buf_size += os_strlen(format_head);
  478. buf_size += 50 + 2 * os_strlen("WLANEvent");
  479. if (sm->wlanevent)
  480. buf_size += os_strlen(sm->wlanevent);
  481. buf_size += os_strlen(format_tail);
  482. buf = wpabuf_alloc(buf_size);
  483. if (buf == NULL)
  484. return;
  485. wpabuf_put_str(buf, format_head);
  486. wpabuf_put_property(buf, "WLANEvent", sm->wlanevent);
  487. wpabuf_put_str(buf, format_tail);
  488. wpa_printf(MSG_MSGDUMP, "WPS UPnP: WLANEvent message:\n%s",
  489. (char *) wpabuf_head(buf));
  490. s = sm->subscriptions;
  491. do {
  492. if (event_add(s, buf)) {
  493. struct subscription *s_old = s;
  494. wpa_printf(MSG_INFO, "WPS UPnP: Dropping "
  495. "subscriber due to event backlog");
  496. s = s_old->next;
  497. subscription_unlink(s_old);
  498. subscription_destroy(s_old);
  499. } else {
  500. s = s->next;
  501. }
  502. } while (s != sm->subscriptions);
  503. wpabuf_free(buf);
  504. }
  505. /*
  506. * Event subscription (subscriber machines register with us to receive event
  507. * messages).
  508. * This is the result of an incoming HTTP over TCP SUBSCRIBE request.
  509. */
  510. /* subscription_unlink -- remove from the active list */
  511. void subscription_unlink(struct subscription *s)
  512. {
  513. struct upnp_wps_device_sm *sm = s->sm;
  514. if (s->next == s) {
  515. /* only one? */
  516. sm->subscriptions = NULL;
  517. } else {
  518. if (sm->subscriptions == s)
  519. sm->subscriptions = s->next;
  520. s->next->prev = s->prev;
  521. s->prev->next = s->next;
  522. }
  523. sm->n_subscriptions--;
  524. }
  525. /* subscription_link_to_end -- link to end of active list
  526. * (should have high expiry time!)
  527. */
  528. static void subscription_link_to_end(struct subscription *s)
  529. {
  530. struct upnp_wps_device_sm *sm = s->sm;
  531. if (sm->subscriptions) {
  532. s->next = sm->subscriptions;
  533. s->prev = s->next->prev;
  534. s->prev->next = s;
  535. s->next->prev = s;
  536. } else {
  537. sm->subscriptions = s->next = s->prev = s;
  538. }
  539. sm->n_subscriptions++;
  540. }
  541. /* subscription_destroy -- destroy an unlinked subscription
  542. * Be sure to unlink first if necessary.
  543. */
  544. void subscription_destroy(struct subscription *s)
  545. {
  546. wpa_printf(MSG_DEBUG, "WPS UPnP: Destroy subscription %p", s);
  547. if (s->addr_list)
  548. subscr_addr_free_all(s);
  549. event_delete_all(s);
  550. os_free(s);
  551. }
  552. /* subscription_list_age -- remove expired subscriptions */
  553. static void subscription_list_age(struct upnp_wps_device_sm *sm, time_t now)
  554. {
  555. struct subscription *s;
  556. while ((s = sm->subscriptions) != NULL && s->timeout_time < now) {
  557. wpa_printf(MSG_DEBUG, "WPS UPnP: Removing aged subscription");
  558. subscription_unlink(s);
  559. subscription_destroy(s);
  560. }
  561. }
  562. /* subscription_find -- return existing subscription matching uuid, if any
  563. * returns NULL if not found
  564. */
  565. struct subscription * subscription_find(struct upnp_wps_device_sm *sm,
  566. const u8 uuid[UUID_LEN])
  567. {
  568. struct subscription *s0 = sm->subscriptions;
  569. struct subscription *s = s0;
  570. if (s0 == NULL)
  571. return NULL;
  572. do {
  573. if (os_memcmp(s->uuid, uuid, UUID_LEN) == 0)
  574. return s; /* Found match */
  575. s = s->next;
  576. } while (s != s0);
  577. return NULL;
  578. }
  579. /* subscription_first_event -- send format/queue event that is automatically
  580. * sent on a new subscription.
  581. */
  582. static int subscription_first_event(struct subscription *s)
  583. {
  584. /*
  585. * Actually, utf-8 is the default, but it doesn't hurt to specify it.
  586. *
  587. * APStatus is apparently a bit set,
  588. * 0x1 = configuration change (but is always set?)
  589. * 0x10 = ap is locked
  590. *
  591. * Per UPnP spec, we send out the last value of each variable, even
  592. * for WLANEvent, whatever it was.
  593. */
  594. char *wlan_event;
  595. struct wpabuf *buf;
  596. int ap_status = 1; /* TODO: add 0x10 if access point is locked */
  597. const char *head =
  598. "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
  599. "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">\n";
  600. const char *tail = "</e:propertyset>\n";
  601. char txt[10];
  602. wlan_event = s->sm->wlanevent;
  603. if (wlan_event == NULL || *wlan_event == '\0') {
  604. wpa_printf(MSG_DEBUG, "WPS UPnP: WLANEvent not known for "
  605. "initial event message");
  606. wlan_event = "";
  607. }
  608. buf = wpabuf_alloc(500 + os_strlen(wlan_event));
  609. if (buf == NULL)
  610. return 1;
  611. wpabuf_put_str(buf, head);
  612. wpabuf_put_property(buf, "STAStatus", "1");
  613. os_snprintf(txt, sizeof(txt), "%d", ap_status);
  614. wpabuf_put_property(buf, "APStatus", txt);
  615. if (*wlan_event)
  616. wpabuf_put_property(buf, "WLANEvent", wlan_event);
  617. wpabuf_put_str(buf, tail);
  618. if (event_add(s, buf)) {
  619. wpabuf_free(buf);
  620. return 1;
  621. }
  622. wpabuf_free(buf);
  623. return 0;
  624. }
  625. /**
  626. * subscription_start - Rremember a UPnP control point to send events to.
  627. * @sm: WPS UPnP state machine from upnp_wps_device_init()
  628. * @callback_urls: malloc' mem given to the subscription
  629. * Returns: %NULL on error, or pointer to new subscription structure.
  630. */
  631. struct subscription * subscription_start(struct upnp_wps_device_sm *sm,
  632. char *callback_urls)
  633. {
  634. struct subscription *s;
  635. time_t now = time(NULL);
  636. time_t expire = now + UPNP_SUBSCRIBE_SEC;
  637. /* Get rid of expired subscriptions so we have room */
  638. subscription_list_age(sm, now);
  639. /* If too many subscriptions, remove oldest */
  640. if (sm->n_subscriptions >= MAX_SUBSCRIPTIONS) {
  641. s = sm->subscriptions;
  642. wpa_printf(MSG_INFO, "WPS UPnP: Too many subscriptions, "
  643. "trashing oldest");
  644. subscription_unlink(s);
  645. subscription_destroy(s);
  646. }
  647. s = os_zalloc(sizeof(*s));
  648. if (s == NULL)
  649. return NULL;
  650. s->sm = sm;
  651. s->timeout_time = expire;
  652. uuid_make(s->uuid);
  653. subscr_addr_list_create(s, callback_urls);
  654. /* Add to end of list, since it has the highest expiration time */
  655. subscription_link_to_end(s);
  656. /* Queue up immediate event message (our last event)
  657. * as required by UPnP spec.
  658. */
  659. if (subscription_first_event(s)) {
  660. wpa_printf(MSG_INFO, "WPS UPnP: Dropping subscriber due to "
  661. "event backlog");
  662. subscription_unlink(s);
  663. subscription_destroy(s);
  664. return NULL;
  665. }
  666. wpa_printf(MSG_DEBUG, "WPS UPnP: Subscription %p started with %s",
  667. s, callback_urls);
  668. os_free(callback_urls);
  669. /* Schedule sending this */
  670. event_send_all_later(sm);
  671. return s;
  672. }
  673. /* subscription_renew -- find subscription and reset timeout */
  674. struct subscription * subscription_renew(struct upnp_wps_device_sm *sm,
  675. const u8 uuid[UUID_LEN])
  676. {
  677. time_t now = time(NULL);
  678. time_t expire = now + UPNP_SUBSCRIBE_SEC;
  679. struct subscription *s = subscription_find(sm, uuid);
  680. if (s == NULL)
  681. return NULL;
  682. wpa_printf(MSG_DEBUG, "WPS UPnP: Subscription renewed");
  683. subscription_unlink(s);
  684. s->timeout_time = expire;
  685. /* add back to end of list, since it now has highest expiry */
  686. subscription_link_to_end(s);
  687. return s;
  688. }
  689. /**
  690. * upnp_wps_device_send_wlan_event - Event notification
  691. * @sm: WPS UPnP state machine from upnp_wps_device_init()
  692. * @from_mac_addr: Source (Enrollee) MAC address for the event
  693. * @ev_type: Event type
  694. * @msg: Event data
  695. * Returns: 0 on success, -1 on failure
  696. *
  697. * Tell external Registrars (UPnP control points) that something happened. In
  698. * particular, events include WPS messages from clients that are proxied to
  699. * external Registrars.
  700. */
  701. int upnp_wps_device_send_wlan_event(struct upnp_wps_device_sm *sm,
  702. const u8 from_mac_addr[ETH_ALEN],
  703. enum upnp_wps_wlanevent_type ev_type,
  704. const struct wpabuf *msg)
  705. {
  706. int ret = -1;
  707. char type[2];
  708. const u8 *mac = from_mac_addr;
  709. char mac_text[18];
  710. u8 *raw = NULL;
  711. size_t raw_len;
  712. char *val;
  713. size_t val_len;
  714. int pos = 0;
  715. if (!sm)
  716. goto fail;
  717. os_snprintf(type, sizeof(type), "%1u", ev_type);
  718. raw_len = 1 + 17 + (msg ? wpabuf_len(msg) : 0);
  719. raw = os_zalloc(raw_len);
  720. if (!raw)
  721. goto fail;
  722. *(raw + pos) = (u8) ev_type;
  723. pos += 1;
  724. os_snprintf(mac_text, sizeof(mac_text), MACSTR, MAC2STR(mac));
  725. wpa_printf(MSG_DEBUG, "WPS UPnP: Proxying WLANEvent from %s",
  726. mac_text);
  727. os_memcpy(raw + pos, mac_text, 17);
  728. pos += 17;
  729. if (msg) {
  730. os_memcpy(raw + pos, wpabuf_head(msg), wpabuf_len(msg));
  731. pos += wpabuf_len(msg);
  732. }
  733. raw_len = pos;
  734. val = (char *) base64_encode(raw, raw_len, &val_len);
  735. if (val == NULL)
  736. goto fail;
  737. os_free(sm->wlanevent);
  738. sm->wlanevent = val;
  739. upnp_wps_device_send_event(sm);
  740. ret = 0;
  741. fail:
  742. os_free(raw);
  743. return ret;
  744. }
  745. #ifdef __FreeBSD__
  746. #include <sys/sysctl.h>
  747. #include <net/route.h>
  748. #include <net/if_dl.h>
  749. static int eth_get(const char *device, u8 ea[ETH_ALEN])
  750. {
  751. struct if_msghdr *ifm;
  752. struct sockaddr_dl *sdl;
  753. u_char *p, *buf;
  754. size_t len;
  755. int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
  756. if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
  757. return -1;
  758. if ((buf = os_malloc(len)) == NULL)
  759. return -1;
  760. if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
  761. os_free(buf);
  762. return -1;
  763. }
  764. for (p = buf; p < buf + len; p += ifm->ifm_msglen) {
  765. ifm = (struct if_msghdr *)p;
  766. sdl = (struct sockaddr_dl *)(ifm + 1);
  767. if (ifm->ifm_type != RTM_IFINFO ||
  768. (ifm->ifm_addrs & RTA_IFP) == 0)
  769. continue;
  770. if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
  771. os_memcmp(sdl->sdl_data, device, sdl->sdl_nlen) != 0)
  772. continue;
  773. os_memcpy(ea, LLADDR(sdl), sdl->sdl_alen);
  774. break;
  775. }
  776. os_free(buf);
  777. if (p >= buf + len) {
  778. errno = ESRCH;
  779. return -1;
  780. }
  781. return 0;
  782. }
  783. #endif /* __FreeBSD__ */
  784. /**
  785. * get_netif_info - Get hw and IP addresses for network device
  786. * @net_if: Selected network interface name
  787. * @ip_addr: Buffer for returning IP address in network byte order
  788. * @ip_addr_text: Buffer for returning a pointer to allocated IP address text
  789. * @mac: Buffer for returning MAC address
  790. * @mac_addr_text: Buffer for returning allocated MAC address text
  791. * Returns: 0 on success, -1 on failure
  792. */
  793. int get_netif_info(const char *net_if, unsigned *ip_addr, char **ip_addr_text,
  794. u8 mac[ETH_ALEN], char **mac_addr_text)
  795. {
  796. struct ifreq req;
  797. int sock = -1;
  798. struct sockaddr_in *addr;
  799. struct in_addr in_addr;
  800. *ip_addr_text = os_zalloc(16);
  801. *mac_addr_text = os_zalloc(18);
  802. if (*ip_addr_text == NULL || *mac_addr_text == NULL)
  803. goto fail;
  804. sock = socket(AF_INET, SOCK_DGRAM, 0);
  805. if (sock < 0)
  806. goto fail;
  807. os_strlcpy(req.ifr_name, net_if, sizeof(req.ifr_name));
  808. if (ioctl(sock, SIOCGIFADDR, &req) < 0) {
  809. wpa_printf(MSG_ERROR, "WPS UPnP: SIOCGIFADDR failed: %d (%s)",
  810. errno, strerror(errno));
  811. goto fail;
  812. }
  813. addr = (void *) &req.ifr_addr;
  814. *ip_addr = addr->sin_addr.s_addr;
  815. in_addr.s_addr = *ip_addr;
  816. os_snprintf(*ip_addr_text, 16, "%s", inet_ntoa(in_addr));
  817. #ifdef __linux__
  818. os_strlcpy(req.ifr_name, net_if, sizeof(req.ifr_name));
  819. if (ioctl(sock, SIOCGIFHWADDR, &req) < 0) {
  820. wpa_printf(MSG_ERROR, "WPS UPnP: SIOCGIFHWADDR failed: "
  821. "%d (%s)", errno, strerror(errno));
  822. goto fail;
  823. }
  824. os_memcpy(mac, req.ifr_addr.sa_data, 6);
  825. #elif defined(__FreeBSD__)
  826. if (eth_get(net_if, mac) < 0) {
  827. wpa_printf(MSG_ERROR, "WPS UPnP: Failed to get MAC address");
  828. goto fail;
  829. }
  830. #else
  831. #error MAC address fetch not implemented
  832. #endif
  833. os_snprintf(*mac_addr_text, 18, MACSTR, MAC2STR(mac));
  834. close(sock);
  835. return 0;
  836. fail:
  837. if (sock >= 0)
  838. close(sock);
  839. os_free(*ip_addr_text);
  840. *ip_addr_text = NULL;
  841. os_free(*mac_addr_text);
  842. *mac_addr_text = NULL;
  843. return -1;
  844. }
  845. /**
  846. * upnp_wps_device_stop - Stop WPS UPnP operations on an interface
  847. * @sm: WPS UPnP state machine from upnp_wps_device_init()
  848. */
  849. void upnp_wps_device_stop(struct upnp_wps_device_sm *sm)
  850. {
  851. if (!sm || !sm->started)
  852. return;
  853. wpa_printf(MSG_DEBUG, "WPS UPnP: Stop device");
  854. web_listener_stop(sm);
  855. while (sm->web_connections)
  856. web_connection_stop(sm->web_connections);
  857. while (sm->msearch_replies)
  858. msearchreply_state_machine_stop(sm->msearch_replies);
  859. while (sm->subscriptions) {
  860. struct subscription *s = sm->subscriptions;
  861. subscription_unlink(s);
  862. subscription_destroy(s);
  863. }
  864. advertisement_state_machine_stop(sm);
  865. /* TODO: send byebye notifications */
  866. event_send_stop_all(sm);
  867. os_free(sm->wlanevent);
  868. sm->wlanevent = NULL;
  869. os_free(sm->net_if);
  870. sm->net_if = NULL;
  871. os_free(sm->mac_addr_text);
  872. sm->mac_addr_text = NULL;
  873. os_free(sm->ip_addr_text);
  874. sm->ip_addr_text = NULL;
  875. if (sm->multicast_sd >= 0)
  876. close(sm->multicast_sd);
  877. sm->multicast_sd = -1;
  878. ssdp_listener_stop(sm);
  879. sm->started = 0;
  880. }
  881. /**
  882. * upnp_wps_device_start - Start WPS UPnP operations on an interface
  883. * @sm: WPS UPnP state machine from upnp_wps_device_init()
  884. * @net_if: Selected network interface name
  885. * Returns: 0 on success, -1 on failure
  886. */
  887. int upnp_wps_device_start(struct upnp_wps_device_sm *sm, char *net_if)
  888. {
  889. if (!sm || !net_if)
  890. return -1;
  891. if (sm->started)
  892. upnp_wps_device_stop(sm);
  893. sm->net_if = strdup(net_if);
  894. sm->multicast_sd = -1;
  895. sm->ssdp_sd = -1;
  896. sm->started = 1;
  897. sm->advertise_count = 0;
  898. /* Fix up linux multicast handling */
  899. if (add_ssdp_network(net_if))
  900. goto fail;
  901. /* Determine which IP and mac address we're using */
  902. if (get_netif_info(net_if,
  903. &sm->ip_addr, &sm->ip_addr_text,
  904. sm->mac_addr, &sm->mac_addr_text)) {
  905. wpa_printf(MSG_INFO, "WPS UPnP: Could not get IP/MAC address "
  906. "for %s. Does it have IP address?", net_if);
  907. goto fail;
  908. }
  909. /* Listen for incoming TCP connections so that others
  910. * can fetch our "xml files" from us.
  911. */
  912. if (web_listener_start(sm))
  913. goto fail;
  914. /* Set up for receiving discovery (UDP) packets */
  915. if (ssdp_listener_start(sm))
  916. goto fail;
  917. /* Set up for sending multicast */
  918. if (ssdp_open_multicast(sm) < 0)
  919. goto fail;
  920. /*
  921. * Broadcast NOTIFY messages to let the world know we exist.
  922. * This is done via a state machine since the messages should not be
  923. * all sent out at once.
  924. */
  925. if (advertisement_state_machine_start(sm))
  926. goto fail;
  927. return 0;
  928. fail:
  929. upnp_wps_device_stop(sm);
  930. return -1;
  931. }
  932. /**
  933. * upnp_wps_device_deinit - Deinitialize WPS UPnP
  934. * @sm: WPS UPnP state machine from upnp_wps_device_init()
  935. */
  936. void upnp_wps_device_deinit(struct upnp_wps_device_sm *sm)
  937. {
  938. if (!sm)
  939. return;
  940. upnp_wps_device_stop(sm);
  941. if (sm->peer.wps)
  942. wps_deinit(sm->peer.wps);
  943. os_free(sm->root_dir);
  944. os_free(sm->desc_url);
  945. os_free(sm->ctx);
  946. os_free(sm);
  947. }
  948. /**
  949. * upnp_wps_device_init - Initialize WPS UPnP
  950. * @ctx: callback table; we must eventually free it
  951. * @wps: Pointer to longterm WPS context
  952. * @priv: External context data that will be used in callbacks
  953. * Returns: WPS UPnP state or %NULL on failure
  954. */
  955. struct upnp_wps_device_sm *
  956. upnp_wps_device_init(struct upnp_wps_device_ctx *ctx, struct wps_context *wps,
  957. void *priv)
  958. {
  959. struct upnp_wps_device_sm *sm;
  960. sm = os_zalloc(sizeof(*sm));
  961. if (!sm) {
  962. wpa_printf(MSG_ERROR, "WPS UPnP: upnp_wps_device_init failed");
  963. return NULL;
  964. }
  965. sm->ctx = ctx;
  966. sm->wps = wps;
  967. sm->priv = priv;
  968. return sm;
  969. }
  970. /**
  971. * upnp_wps_subscribers - Check whether there are any event subscribers
  972. * @sm: WPS UPnP state machine from upnp_wps_device_init()
  973. * Returns: 0 if no subscribers, 1 if subscribers
  974. */
  975. int upnp_wps_subscribers(struct upnp_wps_device_sm *sm)
  976. {
  977. return sm->subscriptions != NULL;
  978. }