wps_er_ssdp.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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. wpa_printf(MSG_DEBUG, "WPS ER: Received SSDP from %s",
  40. inet_ntoa(addr.sin_addr));
  41. wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Received SSDP contents",
  42. (u8 *) buf, nread);
  43. if (sd == er->multicast_sd) {
  44. /* Reply to M-SEARCH */
  45. if (os_strncmp(buf, "HTTP/1.1 200 OK", 15) != 0)
  46. return; /* unexpected response header */
  47. } else {
  48. /* Unsolicited message (likely NOTIFY or M-SEARCH) */
  49. if (os_strncmp(buf, "NOTIFY ", 7) != 0)
  50. return; /* only process notifications */
  51. }
  52. os_memset(uuid, 0, sizeof(uuid));
  53. for (start = buf; start && *start; start = pos) {
  54. pos = os_strchr(start, '\n');
  55. if (pos) {
  56. if (pos[-1] == '\r')
  57. pos[-1] = '\0';
  58. *pos++ = '\0';
  59. }
  60. if (os_strstr(start, "schemas-wifialliance-org:device:"
  61. "WFADevice:1"))
  62. wfa = 1;
  63. if (os_strstr(start, "schemas-wifialliance-org:service:"
  64. "WFAWLANConfig:1"))
  65. wfa = 1;
  66. if (os_strncasecmp(start, "LOCATION:", 9) == 0) {
  67. start += 9;
  68. while (*start == ' ')
  69. start++;
  70. location = start;
  71. } else if (os_strncasecmp(start, "NTS:", 4) == 0) {
  72. if (os_strstr(start, "ssdp:byebye"))
  73. byebye = 1;
  74. } else if (os_strncasecmp(start, "CACHE-CONTROL:", 14) == 0) {
  75. start += 9;
  76. while (*start == ' ')
  77. start++;
  78. pos2 = os_strstr(start, "max-age=");
  79. if (pos2 == NULL)
  80. continue;
  81. pos2 += 8;
  82. max_age = atoi(pos2);
  83. } else if (os_strncasecmp(start, "USN:", 4) == 0) {
  84. start += 4;
  85. pos2 = os_strstr(start, "uuid:");
  86. if (pos2) {
  87. pos2 += 5;
  88. while (*pos2 == ' ')
  89. pos2++;
  90. uuid_str2bin(pos2, uuid);
  91. }
  92. }
  93. }
  94. if (!wfa)
  95. return; /* Not WPS advertisement/reply */
  96. if (byebye) {
  97. wps_er_ap_remove(er, &addr.sin_addr);
  98. return;
  99. }
  100. if (!location)
  101. return; /* Unknown location */
  102. if (max_age < 1)
  103. return; /* No max-age reported */
  104. wpa_printf(MSG_DEBUG, "WPS ER: AP discovered: %s "
  105. "(packet source: %s max-age: %d)",
  106. location, inet_ntoa(addr.sin_addr), max_age);
  107. wps_er_ap_add(er, uuid, &addr.sin_addr, location, max_age);
  108. }
  109. void wps_er_send_ssdp_msearch(struct wps_er *er)
  110. {
  111. struct wpabuf *msg;
  112. struct sockaddr_in dest;
  113. msg = wpabuf_alloc(500);
  114. if (msg == NULL)
  115. return;
  116. wpabuf_put_str(msg,
  117. "M-SEARCH * HTTP/1.1\r\n"
  118. "HOST: 239.255.255.250:1900\r\n"
  119. "MAN: \"ssdp:discover\"\r\n"
  120. "MX: 3\r\n"
  121. "ST: urn:schemas-wifialliance-org:device:WFADevice:1"
  122. "\r\n"
  123. "\r\n");
  124. os_memset(&dest, 0, sizeof(dest));
  125. dest.sin_family = AF_INET;
  126. dest.sin_addr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS);
  127. dest.sin_port = htons(UPNP_MULTICAST_PORT);
  128. if (sendto(er->multicast_sd, wpabuf_head(msg), wpabuf_len(msg), 0,
  129. (struct sockaddr *) &dest, sizeof(dest)) < 0)
  130. wpa_printf(MSG_DEBUG, "WPS ER: M-SEARCH sendto failed: "
  131. "%d (%s)", errno, strerror(errno));
  132. wpabuf_free(msg);
  133. }
  134. int wps_er_ssdp_init(struct wps_er *er)
  135. {
  136. if (add_ssdp_network(er->ifname))
  137. return -1;
  138. er->multicast_sd = ssdp_open_multicast_sock(er->ip_addr);
  139. if (er->multicast_sd < 0)
  140. return -1;
  141. er->ssdp_sd = ssdp_listener_open();
  142. if (er->ssdp_sd < 0)
  143. return -1;
  144. if (eloop_register_sock(er->multicast_sd, EVENT_TYPE_READ,
  145. wps_er_ssdp_rx, er, NULL) ||
  146. eloop_register_sock(er->ssdp_sd, EVENT_TYPE_READ,
  147. wps_er_ssdp_rx, er, NULL))
  148. return -1;
  149. wps_er_send_ssdp_msearch(er);
  150. return 0;
  151. }
  152. void wps_er_ssdp_deinit(struct wps_er *er)
  153. {
  154. if (er->multicast_sd >= 0) {
  155. eloop_unregister_sock(er->multicast_sd, EVENT_TYPE_READ);
  156. close(er->multicast_sd);
  157. }
  158. if (er->ssdp_sd >= 0) {
  159. eloop_unregister_sock(er->ssdp_sd, EVENT_TYPE_READ);
  160. close(er->ssdp_sd);
  161. }
  162. }