From ec72bd0c77ca2e4a778d2962a81a00f41e6b6386 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sat, 21 Nov 2009 17:26:23 +0200 Subject: [PATCH] WPS ER: Move SSDP functionality into a separate file --- src/wps/wps_er.c | 251 +--------------------------------------- src/wps/wps_er.h | 84 ++++++++++++++ src/wps/wps_er_ssdp.c | 193 ++++++++++++++++++++++++++++++ wpa_supplicant/Makefile | 1 + 4 files changed, 284 insertions(+), 245 deletions(-) create mode 100644 src/wps/wps_er.h create mode 100644 src/wps/wps_er_ssdp.c diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c index 21fec3d4e..3c94bec35 100644 --- a/src/wps/wps_er.c +++ b/src/wps/wps_er.c @@ -25,89 +25,11 @@ #include "wps_i.h" #include "wps_upnp.h" #include "wps_upnp_i.h" +#include "wps_er.h" -/* TODO: - * send notification of new AP device with wpa_msg - * re-send notifications with wpa_msg if ER re-started (to update wpa_gui-qt4) - * (also re-send SSDP M-SEARCH in this case to find new APs) - * parse UPnP event messages - */ - static void wps_er_ap_timeout(void *eloop_data, void *user_ctx); static void wps_er_sta_timeout(void *eloop_data, void *user_ctx); - - -struct wps_er_sta { - struct wps_er_sta *next; - struct wps_er_ap *ap; - u8 addr[ETH_ALEN]; - u16 config_methods; - u8 uuid[WPS_UUID_LEN]; - u8 pri_dev_type[8]; - u16 dev_passwd_id; - int m1_received; - char *manufacturer; - char *model_name; - char *model_number; - char *serial_number; - char *dev_name; - struct wps_data *wps; - struct http_client *http; -}; - -struct wps_er_ap { - struct wps_er_ap *next; - struct wps_er *er; - struct wps_er_sta *sta; /* list of STAs/Enrollees using this AP */ - struct in_addr addr; - char *location; - struct http_client *http; - struct wps_data *wps; - - u8 uuid[WPS_UUID_LEN]; - u8 pri_dev_type[8]; - u8 wps_state; - u8 mac_addr[ETH_ALEN]; - char *friendly_name; - char *manufacturer; - char *manufacturer_url; - char *model_description; - char *model_name; - char *model_number; - char *model_url; - char *serial_number; - char *udn; - char *upc; - - char *scpd_url; - char *control_url; - char *event_sub_url; - - int subscribed; - unsigned int id; - - struct wps_credential *ap_settings; - - void (*m1_handler)(struct wps_er_ap *ap, struct wpabuf *m1); -}; - -struct wps_er { - struct wps_context *wps; - char ifname[17]; - char *mac_addr_text; /* mac addr of network i.f. we use */ - u8 mac_addr[ETH_ALEN]; /* mac addr of network i.f. we use */ - char *ip_addr_text; /* IP address of network i.f. we use */ - unsigned ip_addr; /* IP address of network i.f. we use (host order) */ - int multicast_sd; - int ssdp_sd; - struct wps_er_ap *ap; - struct http_server *http_srv; - int http_port; - unsigned int next_ap_id; -}; - - static void wps_er_ap_process(struct wps_er_ap *ap, struct wpabuf *msg); static int wps_er_send_get_device_info(struct wps_er_ap *ap, void (*m1_handler)(struct wps_er_ap *ap, @@ -502,9 +424,8 @@ static void wps_er_http_dev_desc_cb(void *ctx, struct http_client *c, } -static void wps_er_ap_add(struct wps_er *er, const u8 *uuid, - struct in_addr *addr, - const char *location, int max_age) +void wps_er_ap_add(struct wps_er *er, const u8 *uuid, struct in_addr *addr, + const char *location, int max_age) { struct wps_er_ap *ap; @@ -542,7 +463,7 @@ static void wps_er_ap_add(struct wps_er *er, const u8 *uuid, } -static void wps_er_ap_remove(struct wps_er *er, struct in_addr *addr) +void wps_er_ap_remove(struct wps_er *er, struct in_addr *addr) { struct wps_er_ap *prev = NULL, *ap = er->ap; @@ -576,138 +497,6 @@ static void wps_er_ap_remove_all(struct wps_er *er) } -static void wps_er_ssdp_rx(int sd, void *eloop_ctx, void *sock_ctx) -{ - struct wps_er *er = eloop_ctx; - struct sockaddr_in addr; /* client address */ - socklen_t addr_len; - int nread; - char buf[MULTICAST_MAX_READ], *pos, *pos2, *start; - int wfa = 0, byebye = 0; - int max_age = -1; - char *location = NULL; - u8 uuid[WPS_UUID_LEN]; - - addr_len = sizeof(addr); - nread = recvfrom(sd, buf, sizeof(buf) - 1, 0, - (struct sockaddr *) &addr, &addr_len); - if (nread <= 0) - return; - buf[nread] = '\0'; - - wpa_printf(MSG_DEBUG, "WPS ER: Received SSDP from %s", - inet_ntoa(addr.sin_addr)); - wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Received SSDP contents", - (u8 *) buf, nread); - - if (sd == er->multicast_sd) { - /* Reply to M-SEARCH */ - if (os_strncmp(buf, "HTTP/1.1 200 OK", 15) != 0) - return; /* unexpected response header */ - } else { - /* Unsolicited message (likely NOTIFY or M-SEARCH) */ - if (os_strncmp(buf, "NOTIFY ", 7) != 0) - return; /* only process notifications */ - } - - os_memset(uuid, 0, sizeof(uuid)); - - for (start = buf; start && *start; start = pos) { - pos = os_strchr(start, '\n'); - if (pos) { - if (pos[-1] == '\r') - pos[-1] = '\0'; - *pos++ = '\0'; - } - if (os_strstr(start, "schemas-wifialliance-org:device:" - "WFADevice:1")) - wfa = 1; - if (os_strstr(start, "schemas-wifialliance-org:service:" - "WFAWLANConfig:1")) - wfa = 1; - if (os_strncasecmp(start, "LOCATION:", 9) == 0) { - start += 9; - while (*start == ' ') - start++; - location = start; - } else if (os_strncasecmp(start, "NTS:", 4) == 0) { - if (os_strstr(start, "ssdp:byebye")) - byebye = 1; - } else if (os_strncasecmp(start, "CACHE-CONTROL:", 14) == 0) { - start += 9; - while (*start == ' ') - start++; - pos2 = os_strstr(start, "max-age="); - if (pos2 == NULL) - continue; - pos2 += 8; - max_age = atoi(pos2); - } else if (os_strncasecmp(start, "USN:", 4) == 0) { - start += 4; - pos2 = os_strstr(start, "uuid:"); - if (pos2) { - pos2 += 5; - while (*pos2 == ' ') - pos2++; - uuid_str2bin(pos2, uuid); - } - } - } - - if (!wfa) - return; /* Not WPS advertisement/reply */ - - if (byebye) { - wps_er_ap_remove(er, &addr.sin_addr); - return; - } - - if (!location) - return; /* Unknown location */ - - if (max_age < 1) - return; /* No max-age reported */ - - wpa_printf(MSG_DEBUG, "WPS ER: AP discovered: %s " - "(packet source: %s max-age: %d)", - location, inet_ntoa(addr.sin_addr), max_age); - - wps_er_ap_add(er, uuid, &addr.sin_addr, location, max_age); -} - - -static void wps_er_send_ssdp_msearch(struct wps_er *er) -{ - struct wpabuf *msg; - struct sockaddr_in dest; - - msg = wpabuf_alloc(500); - if (msg == NULL) - return; - - wpabuf_put_str(msg, - "M-SEARCH * HTTP/1.1\r\n" - "HOST: 239.255.255.250:1900\r\n" - "MAN: \"ssdp:discover\"\r\n" - "MX: 3\r\n" - "ST: urn:schemas-wifialliance-org:device:WFADevice:1" - "\r\n" - "\r\n"); - - os_memset(&dest, 0, sizeof(dest)); - dest.sin_family = AF_INET; - dest.sin_addr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS); - dest.sin_port = htons(UPNP_MULTICAST_PORT); - - if (sendto(er->multicast_sd, wpabuf_head(msg), wpabuf_len(msg), 0, - (struct sockaddr *) &dest, sizeof(dest)) < 0) - wpa_printf(MSG_DEBUG, "WPS ER: M-SEARCH sendto failed: " - "%d (%s)", errno, strerror(errno)); - - wpabuf_free(msg); -} - - static void http_put_date(struct wpabuf *buf) { wpabuf_put_str(buf, "Date: "); @@ -1261,26 +1050,7 @@ wps_er_init(struct wps_context *wps, const char *ifname) return NULL; } - if (add_ssdp_network(ifname)) { - wps_er_deinit(er); - return NULL; - } - - er->multicast_sd = ssdp_open_multicast_sock(er->ip_addr); - if (er->multicast_sd < 0) { - wps_er_deinit(er); - return NULL; - } - - er->ssdp_sd = ssdp_listener_open(); - if (er->ssdp_sd < 0) { - wps_er_deinit(er); - return NULL; - } - if (eloop_register_sock(er->multicast_sd, EVENT_TYPE_READ, - wps_er_ssdp_rx, er, NULL) || - eloop_register_sock(er->ssdp_sd, EVENT_TYPE_READ, - wps_er_ssdp_rx, er, NULL)) { + if (wps_er_ssdp_init(er) < 0) { wps_er_deinit(er); return NULL; } @@ -1297,8 +1067,6 @@ wps_er_init(struct wps_context *wps, const char *ifname) "mac_addr=%s)", er->ifname, er->ip_addr_text, er->mac_addr_text); - wps_er_send_ssdp_msearch(er); - return er; } @@ -1324,14 +1092,7 @@ void wps_er_deinit(struct wps_er *er) return; http_server_deinit(er->http_srv); wps_er_ap_remove_all(er); - if (er->multicast_sd >= 0) { - eloop_unregister_sock(er->multicast_sd, EVENT_TYPE_READ); - close(er->multicast_sd); - } - if (er->ssdp_sd >= 0) { - eloop_unregister_sock(er->ssdp_sd, EVENT_TYPE_READ); - close(er->ssdp_sd); - } + wps_er_ssdp_deinit(er); os_free(er->ip_addr_text); os_free(er->mac_addr_text); os_free(er); diff --git a/src/wps/wps_er.h b/src/wps/wps_er.h new file mode 100644 index 000000000..cf2048c8b --- /dev/null +++ b/src/wps/wps_er.h @@ -0,0 +1,84 @@ +#ifndef WPS_ER_H +#define WPS_ER_H + +struct wps_er_sta { + struct wps_er_sta *next; + struct wps_er_ap *ap; + u8 addr[ETH_ALEN]; + u16 config_methods; + u8 uuid[WPS_UUID_LEN]; + u8 pri_dev_type[8]; + u16 dev_passwd_id; + int m1_received; + char *manufacturer; + char *model_name; + char *model_number; + char *serial_number; + char *dev_name; + struct wps_data *wps; + struct http_client *http; +}; + +struct wps_er_ap { + struct wps_er_ap *next; + struct wps_er *er; + struct wps_er_sta *sta; /* list of STAs/Enrollees using this AP */ + struct in_addr addr; + char *location; + struct http_client *http; + struct wps_data *wps; + + u8 uuid[WPS_UUID_LEN]; + u8 pri_dev_type[8]; + u8 wps_state; + u8 mac_addr[ETH_ALEN]; + char *friendly_name; + char *manufacturer; + char *manufacturer_url; + char *model_description; + char *model_name; + char *model_number; + char *model_url; + char *serial_number; + char *udn; + char *upc; + + char *scpd_url; + char *control_url; + char *event_sub_url; + + int subscribed; + unsigned int id; + + struct wps_credential *ap_settings; + + void (*m1_handler)(struct wps_er_ap *ap, struct wpabuf *m1); +}; + +struct wps_er { + struct wps_context *wps; + char ifname[17]; + char *mac_addr_text; /* mac addr of network i.f. we use */ + u8 mac_addr[ETH_ALEN]; /* mac addr of network i.f. we use */ + char *ip_addr_text; /* IP address of network i.f. we use */ + unsigned ip_addr; /* IP address of network i.f. we use (host order) */ + int multicast_sd; + int ssdp_sd; + struct wps_er_ap *ap; + struct http_server *http_srv; + int http_port; + unsigned int next_ap_id; +}; + + +/* wps_er.c */ +void wps_er_ap_add(struct wps_er *er, const u8 *uuid, struct in_addr *addr, + const char *location, int max_age); +void wps_er_ap_remove(struct wps_er *er, struct in_addr *addr); + +/* wps_er_ssdp.c */ +int wps_er_ssdp_init(struct wps_er *er); +void wps_er_ssdp_deinit(struct wps_er *er); +void wps_er_send_ssdp_msearch(struct wps_er *er); + +#endif /* WPS_ER_H */ diff --git a/src/wps/wps_er_ssdp.c b/src/wps/wps_er_ssdp.c new file mode 100644 index 000000000..83879db22 --- /dev/null +++ b/src/wps/wps_er_ssdp.c @@ -0,0 +1,193 @@ +/* + * Wi-Fi Protected Setup - External Registrar (SSDP) + * Copyright (c) 2009, Jouni Malinen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of BSD + * license. + * + * See README and COPYING for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "uuid.h" +#include "eloop.h" +#include "wps_i.h" +#include "wps_upnp.h" +#include "wps_upnp_i.h" +#include "wps_er.h" + + +static void wps_er_ssdp_rx(int sd, void *eloop_ctx, void *sock_ctx) +{ + struct wps_er *er = eloop_ctx; + struct sockaddr_in addr; /* client address */ + socklen_t addr_len; + int nread; + char buf[MULTICAST_MAX_READ], *pos, *pos2, *start; + int wfa = 0, byebye = 0; + int max_age = -1; + char *location = NULL; + u8 uuid[WPS_UUID_LEN]; + + addr_len = sizeof(addr); + nread = recvfrom(sd, buf, sizeof(buf) - 1, 0, + (struct sockaddr *) &addr, &addr_len); + if (nread <= 0) + return; + buf[nread] = '\0'; + + wpa_printf(MSG_DEBUG, "WPS ER: Received SSDP from %s", + inet_ntoa(addr.sin_addr)); + wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Received SSDP contents", + (u8 *) buf, nread); + + if (sd == er->multicast_sd) { + /* Reply to M-SEARCH */ + if (os_strncmp(buf, "HTTP/1.1 200 OK", 15) != 0) + return; /* unexpected response header */ + } else { + /* Unsolicited message (likely NOTIFY or M-SEARCH) */ + if (os_strncmp(buf, "NOTIFY ", 7) != 0) + return; /* only process notifications */ + } + + os_memset(uuid, 0, sizeof(uuid)); + + for (start = buf; start && *start; start = pos) { + pos = os_strchr(start, '\n'); + if (pos) { + if (pos[-1] == '\r') + pos[-1] = '\0'; + *pos++ = '\0'; + } + if (os_strstr(start, "schemas-wifialliance-org:device:" + "WFADevice:1")) + wfa = 1; + if (os_strstr(start, "schemas-wifialliance-org:service:" + "WFAWLANConfig:1")) + wfa = 1; + if (os_strncasecmp(start, "LOCATION:", 9) == 0) { + start += 9; + while (*start == ' ') + start++; + location = start; + } else if (os_strncasecmp(start, "NTS:", 4) == 0) { + if (os_strstr(start, "ssdp:byebye")) + byebye = 1; + } else if (os_strncasecmp(start, "CACHE-CONTROL:", 14) == 0) { + start += 9; + while (*start == ' ') + start++; + pos2 = os_strstr(start, "max-age="); + if (pos2 == NULL) + continue; + pos2 += 8; + max_age = atoi(pos2); + } else if (os_strncasecmp(start, "USN:", 4) == 0) { + start += 4; + pos2 = os_strstr(start, "uuid:"); + if (pos2) { + pos2 += 5; + while (*pos2 == ' ') + pos2++; + uuid_str2bin(pos2, uuid); + } + } + } + + if (!wfa) + return; /* Not WPS advertisement/reply */ + + if (byebye) { + wps_er_ap_remove(er, &addr.sin_addr); + return; + } + + if (!location) + return; /* Unknown location */ + + if (max_age < 1) + return; /* No max-age reported */ + + wpa_printf(MSG_DEBUG, "WPS ER: AP discovered: %s " + "(packet source: %s max-age: %d)", + location, inet_ntoa(addr.sin_addr), max_age); + + wps_er_ap_add(er, uuid, &addr.sin_addr, location, max_age); +} + + +void wps_er_send_ssdp_msearch(struct wps_er *er) +{ + struct wpabuf *msg; + struct sockaddr_in dest; + + msg = wpabuf_alloc(500); + if (msg == NULL) + return; + + wpabuf_put_str(msg, + "M-SEARCH * HTTP/1.1\r\n" + "HOST: 239.255.255.250:1900\r\n" + "MAN: \"ssdp:discover\"\r\n" + "MX: 3\r\n" + "ST: urn:schemas-wifialliance-org:device:WFADevice:1" + "\r\n" + "\r\n"); + + os_memset(&dest, 0, sizeof(dest)); + dest.sin_family = AF_INET; + dest.sin_addr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS); + dest.sin_port = htons(UPNP_MULTICAST_PORT); + + if (sendto(er->multicast_sd, wpabuf_head(msg), wpabuf_len(msg), 0, + (struct sockaddr *) &dest, sizeof(dest)) < 0) + wpa_printf(MSG_DEBUG, "WPS ER: M-SEARCH sendto failed: " + "%d (%s)", errno, strerror(errno)); + + wpabuf_free(msg); +} + + +int wps_er_ssdp_init(struct wps_er *er) +{ + if (add_ssdp_network(er->ifname)) + return -1; + + er->multicast_sd = ssdp_open_multicast_sock(er->ip_addr); + if (er->multicast_sd < 0) + return -1; + + er->ssdp_sd = ssdp_listener_open(); + if (er->ssdp_sd < 0) + return -1; + + if (eloop_register_sock(er->multicast_sd, EVENT_TYPE_READ, + wps_er_ssdp_rx, er, NULL) || + eloop_register_sock(er->ssdp_sd, EVENT_TYPE_READ, + wps_er_ssdp_rx, er, NULL)) + return -1; + + wps_er_send_ssdp_msearch(er); + + return 0; +} + + +void wps_er_ssdp_deinit(struct wps_er *er) +{ + if (er->multicast_sd >= 0) { + eloop_unregister_sock(er->multicast_sd, EVENT_TYPE_READ); + close(er->multicast_sd); + } + if (er->ssdp_sd >= 0) { + eloop_unregister_sock(er->ssdp_sd, EVENT_TYPE_READ); + close(er->ssdp_sd); + } +} diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 08797749a..19621ecf2 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -501,6 +501,7 @@ ifdef CONFIG_WPS_ER CONFIG_WPS_UPNP=y CFLAGS += -DCONFIG_WPS_ER OBJS += ../src/wps/wps_er.o +OBJS += ../src/wps/wps_er_ssdp.o endif ifdef CONFIG_WPS_UPNP