wps_er_ssdp.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /*
  2. * Wi-Fi Protected Setup - External Registrar (SSDP)
  3. * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. *
  9. * Alternatively, this software may be distributed under the terms of BSD
  10. * license.
  11. *
  12. * See README and COPYING for more details.
  13. */
  14. #include "includes.h"
  15. #include "common.h"
  16. #include "uuid.h"
  17. #include "eloop.h"
  18. #include "wps_i.h"
  19. #include "wps_upnp.h"
  20. #include "wps_upnp_i.h"
  21. #include "wps_er.h"
  22. static void wps_er_ssdp_rx(int sd, void *eloop_ctx, void *sock_ctx)
  23. {
  24. struct wps_er *er = eloop_ctx;
  25. struct sockaddr_in addr; /* client address */
  26. socklen_t addr_len;
  27. int nread;
  28. char buf[MULTICAST_MAX_READ], *pos, *pos2, *start;
  29. int wfa = 0, byebye = 0;
  30. int max_age = -1;
  31. char *location = NULL;
  32. u8 uuid[WPS_UUID_LEN];
  33. addr_len = sizeof(addr);
  34. nread = recvfrom(sd, buf, sizeof(buf) - 1, 0,
  35. (struct sockaddr *) &addr, &addr_len);
  36. if (nread <= 0)
  37. return;
  38. buf[nread] = '\0';
  39. if (er->filter_addr.s_addr &&
  40. er->filter_addr.s_addr != addr.sin_addr.s_addr)
  41. return;
  42. wpa_printf(MSG_DEBUG, "WPS ER: Received SSDP from %s",
  43. inet_ntoa(addr.sin_addr));
  44. wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Received SSDP contents",
  45. (u8 *) buf, nread);
  46. if (sd == er->multicast_sd) {
  47. /* Reply to M-SEARCH */
  48. if (os_strncmp(buf, "HTTP/1.1 200 OK", 15) != 0)
  49. return; /* unexpected response header */
  50. } else {
  51. /* Unsolicited message (likely NOTIFY or M-SEARCH) */
  52. if (os_strncmp(buf, "NOTIFY ", 7) != 0)
  53. return; /* only process notifications */
  54. }
  55. os_memset(uuid, 0, sizeof(uuid));
  56. for (start = buf; start && *start; start = pos) {
  57. pos = os_strchr(start, '\n');
  58. if (pos) {
  59. if (pos[-1] == '\r')
  60. pos[-1] = '\0';
  61. *pos++ = '\0';
  62. }
  63. if (os_strstr(start, "schemas-wifialliance-org:device:"
  64. "WFADevice:1"))
  65. wfa = 1;
  66. if (os_strstr(start, "schemas-wifialliance-org:service:"
  67. "WFAWLANConfig:1"))
  68. wfa = 1;
  69. if (os_strncasecmp(start, "LOCATION:", 9) == 0) {
  70. start += 9;
  71. while (*start == ' ')
  72. start++;
  73. location = start;
  74. } else if (os_strncasecmp(start, "NTS:", 4) == 0) {
  75. if (os_strstr(start, "ssdp:byebye"))
  76. byebye = 1;
  77. } else if (os_strncasecmp(start, "CACHE-CONTROL:", 14) == 0) {
  78. start += 9;
  79. while (*start == ' ')
  80. start++;
  81. pos2 = os_strstr(start, "max-age=");
  82. if (pos2 == NULL)
  83. continue;
  84. pos2 += 8;
  85. max_age = atoi(pos2);
  86. } else if (os_strncasecmp(start, "USN:", 4) == 0) {
  87. start += 4;
  88. pos2 = os_strstr(start, "uuid:");
  89. if (pos2) {
  90. pos2 += 5;
  91. while (*pos2 == ' ')
  92. pos2++;
  93. if (uuid_str2bin(pos2, uuid) < 0) {
  94. wpa_printf(MSG_DEBUG, "WPS ER: "
  95. "Invalid UUID in USN: %s",
  96. pos2);
  97. return;
  98. }
  99. }
  100. }
  101. }
  102. if (!wfa)
  103. return; /* Not WPS advertisement/reply */
  104. if (byebye) {
  105. wps_er_ap_remove(er, &addr.sin_addr);
  106. return;
  107. }
  108. if (!location)
  109. return; /* Unknown location */
  110. if (max_age < 1)
  111. return; /* No max-age reported */
  112. wpa_printf(MSG_DEBUG, "WPS ER: AP discovered: %s "
  113. "(packet source: %s max-age: %d)",
  114. location, inet_ntoa(addr.sin_addr), max_age);
  115. wps_er_ap_add(er, uuid, &addr.sin_addr, location, max_age);
  116. }
  117. void wps_er_send_ssdp_msearch(struct wps_er *er)
  118. {
  119. struct wpabuf *msg;
  120. struct sockaddr_in dest;
  121. msg = wpabuf_alloc(500);
  122. if (msg == NULL)
  123. return;
  124. wpabuf_put_str(msg,
  125. "M-SEARCH * HTTP/1.1\r\n"
  126. "HOST: 239.255.255.250:1900\r\n"
  127. "MAN: \"ssdp:discover\"\r\n"
  128. "MX: 3\r\n"
  129. "ST: urn:schemas-wifialliance-org:device:WFADevice:1"
  130. "\r\n"
  131. "\r\n");
  132. os_memset(&dest, 0, sizeof(dest));
  133. dest.sin_family = AF_INET;
  134. dest.sin_addr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS);
  135. dest.sin_port = htons(UPNP_MULTICAST_PORT);
  136. if (sendto(er->multicast_sd, wpabuf_head(msg), wpabuf_len(msg), 0,
  137. (struct sockaddr *) &dest, sizeof(dest)) < 0)
  138. wpa_printf(MSG_DEBUG, "WPS ER: M-SEARCH sendto failed: "
  139. "%d (%s)", errno, strerror(errno));
  140. wpabuf_free(msg);
  141. }
  142. int wps_er_ssdp_init(struct wps_er *er)
  143. {
  144. if (add_ssdp_network(er->ifname)) {
  145. wpa_printf(MSG_INFO, "WPS ER: Failed to add routing entry for "
  146. "SSDP");
  147. return -1;
  148. }
  149. er->multicast_sd = ssdp_open_multicast_sock(er->ip_addr);
  150. if (er->multicast_sd < 0) {
  151. wpa_printf(MSG_INFO, "WPS ER: Failed to open multicast socket "
  152. "for SSDP");
  153. return -1;
  154. }
  155. er->ssdp_sd = ssdp_listener_open();
  156. if (er->ssdp_sd < 0) {
  157. wpa_printf(MSG_INFO, "WPS ER: Failed to open SSDP listener "
  158. "socket");
  159. return -1;
  160. }
  161. if (eloop_register_sock(er->multicast_sd, EVENT_TYPE_READ,
  162. wps_er_ssdp_rx, er, NULL) ||
  163. eloop_register_sock(er->ssdp_sd, EVENT_TYPE_READ,
  164. wps_er_ssdp_rx, er, NULL))
  165. return -1;
  166. wps_er_send_ssdp_msearch(er);
  167. return 0;
  168. }
  169. void wps_er_ssdp_deinit(struct wps_er *er)
  170. {
  171. if (er->multicast_sd >= 0) {
  172. eloop_unregister_sock(er->multicast_sd, EVENT_TYPE_READ);
  173. close(er->multicast_sd);
  174. }
  175. if (er->ssdp_sd >= 0) {
  176. eloop_unregister_sock(er->ssdp_sd, EVENT_TYPE_READ);
  177. close(er->ssdp_sd);
  178. }
  179. }