$search
00001 /* 00002 * Wi-Fi Protected Setup - External Registrar (SSDP) 00003 * Copyright (c) 2009, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 */ 00014 00015 #include "includes.h" 00016 00017 #include "common.h" 00018 #include "uuid.h" 00019 #include "eloop.h" 00020 #include "wps_i.h" 00021 #include "wps_upnp.h" 00022 #include "wps_upnp_i.h" 00023 #include "wps_er.h" 00024 00025 00026 static void wps_er_ssdp_rx(int sd, void *eloop_ctx, void *sock_ctx) 00027 { 00028 struct wps_er *er = eloop_ctx; 00029 struct sockaddr_in addr; /* client address */ 00030 socklen_t addr_len; 00031 int nread; 00032 char buf[MULTICAST_MAX_READ], *pos, *pos2, *start; 00033 int wfa = 0, byebye = 0; 00034 int max_age = -1; 00035 char *location = NULL; 00036 u8 uuid[WPS_UUID_LEN]; 00037 00038 addr_len = sizeof(addr); 00039 nread = recvfrom(sd, buf, sizeof(buf) - 1, 0, 00040 (struct sockaddr *) &addr, &addr_len); 00041 if (nread <= 0) 00042 return; 00043 buf[nread] = '\0'; 00044 00045 wpa_printf(MSG_DEBUG, "WPS ER: Received SSDP from %s", 00046 inet_ntoa(addr.sin_addr)); 00047 wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Received SSDP contents", 00048 (u8 *) buf, nread); 00049 00050 if (sd == er->multicast_sd) { 00051 /* Reply to M-SEARCH */ 00052 if (os_strncmp(buf, "HTTP/1.1 200 OK", 15) != 0) 00053 return; /* unexpected response header */ 00054 } else { 00055 /* Unsolicited message (likely NOTIFY or M-SEARCH) */ 00056 if (os_strncmp(buf, "NOTIFY ", 7) != 0) 00057 return; /* only process notifications */ 00058 } 00059 00060 os_memset(uuid, 0, sizeof(uuid)); 00061 00062 for (start = buf; start && *start; start = pos) { 00063 pos = os_strchr(start, '\n'); 00064 if (pos) { 00065 if (pos[-1] == '\r') 00066 pos[-1] = '\0'; 00067 *pos++ = '\0'; 00068 } 00069 if (os_strstr(start, "schemas-wifialliance-org:device:" 00070 "WFADevice:1")) 00071 wfa = 1; 00072 if (os_strstr(start, "schemas-wifialliance-org:service:" 00073 "WFAWLANConfig:1")) 00074 wfa = 1; 00075 if (os_strncasecmp(start, "LOCATION:", 9) == 0) { 00076 start += 9; 00077 while (*start == ' ') 00078 start++; 00079 location = start; 00080 } else if (os_strncasecmp(start, "NTS:", 4) == 0) { 00081 if (os_strstr(start, "ssdp:byebye")) 00082 byebye = 1; 00083 } else if (os_strncasecmp(start, "CACHE-CONTROL:", 14) == 0) { 00084 start += 9; 00085 while (*start == ' ') 00086 start++; 00087 pos2 = os_strstr(start, "max-age="); 00088 if (pos2 == NULL) 00089 continue; 00090 pos2 += 8; 00091 max_age = atoi(pos2); 00092 } else if (os_strncasecmp(start, "USN:", 4) == 0) { 00093 start += 4; 00094 pos2 = os_strstr(start, "uuid:"); 00095 if (pos2) { 00096 pos2 += 5; 00097 while (*pos2 == ' ') 00098 pos2++; 00099 if (uuid_str2bin(pos2, uuid) < 0) { 00100 wpa_printf(MSG_DEBUG, "WPS ER: " 00101 "Invalid UUID in USN: %s", 00102 pos2); 00103 return; 00104 } 00105 } 00106 } 00107 } 00108 00109 if (!wfa) 00110 return; /* Not WPS advertisement/reply */ 00111 00112 if (byebye) { 00113 wps_er_ap_remove(er, &addr.sin_addr); 00114 return; 00115 } 00116 00117 if (!location) 00118 return; /* Unknown location */ 00119 00120 if (max_age < 1) 00121 return; /* No max-age reported */ 00122 00123 wpa_printf(MSG_DEBUG, "WPS ER: AP discovered: %s " 00124 "(packet source: %s max-age: %d)", 00125 location, inet_ntoa(addr.sin_addr), max_age); 00126 00127 wps_er_ap_add(er, uuid, &addr.sin_addr, location, max_age); 00128 } 00129 00130 00131 void wps_er_send_ssdp_msearch(struct wps_er *er) 00132 { 00133 struct wpabuf *msg; 00134 struct sockaddr_in dest; 00135 00136 msg = wpabuf_alloc(500); 00137 if (msg == NULL) 00138 return; 00139 00140 wpabuf_put_str(msg, 00141 "M-SEARCH * HTTP/1.1\r\n" 00142 "HOST: 239.255.255.250:1900\r\n" 00143 "MAN: \"ssdp:discover\"\r\n" 00144 "MX: 3\r\n" 00145 "ST: urn:schemas-wifialliance-org:device:WFADevice:1" 00146 "\r\n" 00147 "\r\n"); 00148 00149 os_memset(&dest, 0, sizeof(dest)); 00150 dest.sin_family = AF_INET; 00151 dest.sin_addr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS); 00152 dest.sin_port = htons(UPNP_MULTICAST_PORT); 00153 00154 if (sendto(er->multicast_sd, wpabuf_head(msg), wpabuf_len(msg), 0, 00155 (struct sockaddr *) &dest, sizeof(dest)) < 0) 00156 wpa_printf(MSG_DEBUG, "WPS ER: M-SEARCH sendto failed: " 00157 "%d (%s)", errno, strerror(errno)); 00158 00159 wpabuf_free(msg); 00160 } 00161 00162 00163 int wps_er_ssdp_init(struct wps_er *er) 00164 { 00165 if (add_ssdp_network(er->ifname)) 00166 return -1; 00167 00168 er->multicast_sd = ssdp_open_multicast_sock(er->ip_addr); 00169 if (er->multicast_sd < 0) 00170 return -1; 00171 00172 er->ssdp_sd = ssdp_listener_open(); 00173 if (er->ssdp_sd < 0) 00174 return -1; 00175 00176 if (eloop_register_sock(er->multicast_sd, EVENT_TYPE_READ, 00177 wps_er_ssdp_rx, er, NULL) || 00178 eloop_register_sock(er->ssdp_sd, EVENT_TYPE_READ, 00179 wps_er_ssdp_rx, er, NULL)) 00180 return -1; 00181 00182 wps_er_send_ssdp_msearch(er); 00183 00184 return 0; 00185 } 00186 00187 00188 void wps_er_ssdp_deinit(struct wps_er *er) 00189 { 00190 if (er->multicast_sd >= 0) { 00191 eloop_unregister_sock(er->multicast_sd, EVENT_TYPE_READ); 00192 close(er->multicast_sd); 00193 } 00194 if (er->ssdp_sd >= 0) { 00195 eloop_unregister_sock(er->ssdp_sd, EVENT_TYPE_READ); 00196 close(er->ssdp_sd); 00197 } 00198 }