⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wps_upnp_ssdp.c

📁 最新的Host AP 新添加了许多pcmcia 的驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * UPnP SSDP for WPS * Copyright (c) 2000-2003 Intel Corporation * Copyright (c) 2006-2007 Sony Corporation * Copyright (c) 2008-2009 Atheros Communications * Copyright (c) 2009, Jouni Malinen <j@w1.fi> * * See wps_upnp.c for more details on licensing and code history. */#include "includes.h"#include <fcntl.h>#include <sys/ioctl.h>#include <net/route.h>#include "common.h"#include "uuid.h"#include "eloop.h"#include "wps.h"#include "wps_upnp.h"#include "wps_upnp_i.h"#define UPNP_CACHE_SEC (UPNP_CACHE_SEC_MIN + 1) /* cache time we use */#define UPNP_CACHE_SEC_MIN 1800 /* min cachable time per UPnP standard */#define UPNP_ADVERTISE_REPEAT 2 /* no more than 3 */#define MULTICAST_MAX_READ 1600 /* max bytes we'll read for UPD request */#define MAX_MSEARCH 20          /* max simultaneous M-SEARCH replies ongoing */#define SSDP_TARGET  "239.0.0.0"#define SSDP_NETMASK "255.0.0.0"/* Check tokens for equality, where tokens consist of letters, digits, * underscore and hyphen, and are matched case insensitive. */static int token_eq(const char *s1, const char *s2){	int c1;	int c2;	int end1 = 0;	int end2 = 0;	for (;;) {		c1 = *s1++;		c2 = *s2++;		if (isalpha(c1) && isupper(c1))			c1 = tolower(c1);		if (isalpha(c2) && isupper(c2))			c2 = tolower(c2);		end1 = !(isalnum(c1) || c1 == '_' || c1 == '-');		end2 = !(isalnum(c2) || c2 == '_' || c2 == '-');		if (end1 || end2 || c1 != c2)			break;	}	return end1 && end2; /* reached end of both words? */}/* Return length of token (see above for definition of token) */static int token_length(const char *s){	const char *begin = s;	for (;; s++) {		int c = *s;		int end = !(isalnum(c) || c == '_' || c == '-');		if (end)			break;	}	return s - begin;}/* return length of interword separation. * This accepts only spaces/tabs and thus will not traverse a line * or buffer ending. */static int word_separation_length(const char *s){	const char *begin = s;	for (;; s++) {		int c = *s;		if (c == ' ' || c == '\t')			continue;		break;	}	return s - begin;}/* No. of chars through (including) end of line */static int line_length(const char *l){	const char *lp = l;	while (*lp && *lp != '\n')		lp++;	if (*lp == '\n')		lp++;	return lp - l;}/* No. of chars excluding trailing whitespace */static int line_length_stripped(const char *l){	const char *lp = l + line_length(l);	while (lp > l && !isgraph(lp[-1]))		lp--;	return lp - l;}static int str_starts(const char *str, const char *start){	return os_strncmp(str, start, os_strlen(start)) == 0;}/*************************************************************************** * Advertisements. * These are multicast to the world to tell them we are here. * The individual packets are spread out in time to limit loss, * and then after a much longer period of time the whole sequence * is repeated again (for NOTIFYs only). **************************************************************************//** * next_advertisement - Build next message and advance the state machine * @a: Advertisement state * @islast: Buffer for indicating whether this is the last message (= 1) * Returns: The new message (caller is responsible for freeing this) * * Note: next_advertisement is shared code with msearchreply_* functions */static struct wpabuf *next_advertisement(struct advertisement_state_machine *a, int *islast){	struct wpabuf *msg;	char *NTString = "";	char uuid_string[80];	*islast = 0;	uuid_bin2str(a->sm->wps->uuid, uuid_string, sizeof(uuid_string));	msg = wpabuf_alloc(800); /* more than big enough */	if (msg == NULL)		goto fail;	switch (a->type) {	case ADVERTISE_UP:	case ADVERTISE_DOWN:		NTString = "NT";		wpabuf_put_str(msg, "NOTIFY * HTTP/1.1\r\n");		wpabuf_printf(msg, "HOST: %s:%d\r\n",			      UPNP_MULTICAST_ADDRESS, UPNP_MULTICAST_PORT);		wpabuf_printf(msg, "CACHE-CONTROL: max-age=%d\r\n",			      UPNP_CACHE_SEC);		wpabuf_printf(msg, "NTS: %s\r\n",			      (a->type == ADVERTISE_UP ?			       "ssdp:alive" : "ssdp:byebye"));		break;	case MSEARCH_REPLY:		NTString = "ST";		wpabuf_put_str(msg, "HTTP/1.1 200 OK\r\n");		wpabuf_printf(msg, "CACHE-CONTROL: max-age=%d\r\n",			      UPNP_CACHE_SEC);		wpabuf_put_str(msg, "DATE: ");		format_date(msg);		wpabuf_put_str(msg, "\r\n");		wpabuf_put_str(msg, "EXT:\r\n");		break;	}	if (a->type != ADVERTISE_DOWN) {		/* Where others may get our XML files from */		wpabuf_printf(msg, "LOCATION: http://%s:%d/%s\r\n",			      a->sm->ip_addr_text, a->sm->web_port,			      UPNP_WPS_DEVICE_XML_FILE);	}	/* The SERVER line has three comma-separated fields:	 *      operating system / version	 *      upnp version	 *      software package / version	 * However, only the UPnP version is really required, the	 * others can be place holders... for security reasons	 * it is better to NOT provide extra information.	 */	wpabuf_put_str(msg, "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n");	switch (a->state / UPNP_ADVERTISE_REPEAT) {	case 0:		wpabuf_printf(msg, "%s: upnp:rootdevice\r\n", NTString);		wpabuf_printf(msg, "USN: uuid:%s::upnp:rootdevice\r\n",			      uuid_string);		break;	case 1:		wpabuf_printf(msg, "%s: uuid:%s\r\n", NTString, uuid_string);		wpabuf_printf(msg, "USN: uuid:%s\r\n", uuid_string);		break;	case 2:		wpabuf_printf(msg, "%s: urn:schemas-wifialliance-org:device:"			      "WFADevice:1\r\n", NTString);		wpabuf_printf(msg, "USN: uuid:%s::urn:schemas-wifialliance-"			      "org:device:WFADevice:1\r\n", uuid_string);		break;	case 3:		wpabuf_printf(msg, "%s: urn:schemas-wifialliance-org:service:"			      "WFAWLANConfig:1\r\n", NTString);		wpabuf_printf(msg, "USN: uuid:%s::urn:schemas-wifialliance-"			      "org:service:WFAWLANConfig:1\r\n", uuid_string);		break;	}	wpabuf_put_str(msg, "\r\n");	if (a->state + 1 >= 4 * UPNP_ADVERTISE_REPEAT)		*islast = 1;	return msg;fail:	wpabuf_free(msg);	return NULL;}static void advertisement_state_machine_handler(void *eloop_data,						void *user_ctx);/** * advertisement_state_machine_stop - Stop SSDP advertisements * @sm: WPS UPnP state machine from upnp_wps_device_init() */void advertisement_state_machine_stop(struct upnp_wps_device_sm *sm){	eloop_cancel_timeout(advertisement_state_machine_handler, NULL, sm);}static void advertisement_state_machine_handler(void *eloop_data,						void *user_ctx){	struct upnp_wps_device_sm *sm = user_ctx;	struct advertisement_state_machine *a = &sm->advertisement;	struct wpabuf *msg;	int next_timeout_msec = 100;	int next_timeout_sec = 0;	struct sockaddr_in dest;	int islast = 0;	/*	 * Each is sent twice (in case lost) w/ 100 msec delay between;	 * spec says no more than 3 times.	 * One pair for rootdevice, one pair for uuid, and a pair each for	 * each of the two urns.	 * The entire sequence must be repeated before cache control timeout	 * (which  is min  1800 seconds),	 * recommend random portion of half of the advertised cache control age	 * to ensure against loss... perhaps 1800/4 + rand*1800/4 ?	 * Delay random interval < 100 msec prior to initial sending.	 * TTL of 4	 */	wpa_printf(MSG_MSGDUMP, "WPS UPnP: Advertisement state=%d", a->state);	msg = next_advertisement(a, &islast);	if (msg == NULL)		return;	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(sm->multicast_sd, wpabuf_head(msg), wpabuf_len(msg), 0,		   (struct sockaddr *) &dest, sizeof(dest)) == -1) {		wpa_printf(MSG_ERROR, "WPS UPnP: Advertisement sendto failed:"			   "%d (%s)", errno, strerror(errno));		next_timeout_msec = 0;		next_timeout_sec = 10; /* ... later */	} else if (islast) {		a->state = 0; /* wrap around */		if (a->type == ADVERTISE_DOWN) {			wpa_printf(MSG_DEBUG, "WPS UPnP: ADVERTISE_DOWN->UP");			a->type = ADVERTISE_UP;			/* do it all over again right away */		} else {			u16 r;			/*			 * Start over again after a long timeout			 * (see notes above)			 */			next_timeout_msec = 0;			os_get_random((void *) &r, sizeof(r));			next_timeout_sec = UPNP_CACHE_SEC / 4 +				(((UPNP_CACHE_SEC / 4) * r) >> 16);			sm->advertise_count++;			wpa_printf(MSG_DEBUG, "WPS UPnP: ADVERTISE_UP (#%u); "				   "next in %d sec",				   sm->advertise_count, next_timeout_sec);		}	} else {		a->state++;	}	wpabuf_free(msg);	eloop_register_timeout(next_timeout_sec, next_timeout_msec,			       advertisement_state_machine_handler, NULL, sm);}/** * advertisement_state_machine_start - Start SSDP advertisements * @sm: WPS UPnP state machine from upnp_wps_device_init() * Returns: 0 on success, -1 on failure */int advertisement_state_machine_start(struct upnp_wps_device_sm *sm){	struct advertisement_state_machine *a = &sm->advertisement;	int next_timeout_msec;	advertisement_state_machine_stop(sm);	/*	 * Start out advertising down, this automatically switches	 * to advertising up which signals our restart.	 */	a->type = ADVERTISE_DOWN;	a->state = 0;	a->sm = sm;	/* (other fields not used here) */	/* First timeout should be random interval < 100 msec */	next_timeout_msec = (100 * (os_random() & 0xFF)) >> 8;	return eloop_register_timeout(0, next_timeout_msec,				      advertisement_state_machine_handler,				      NULL, sm);}/*************************************************************************** * M-SEARCH replies * These are very similar to the multicast advertisements, with some * small changes in data content; and they are sent (UDP) to a specific * unicast address instead of multicast. * They are sent in response to a UDP M-SEARCH packet. **************************************************************************/static void msearchreply_state_machine_handler(void *eloop_data,					       void *user_ctx);/** * msearchreply_state_machine_stop - Stop M-SEARCH reply state machine * @a: Selected advertisement/reply state */void msearchreply_state_machine_stop(struct advertisement_state_machine *a){	struct upnp_wps_device_sm *sm = a->sm;	wpa_printf(MSG_DEBUG, "WPS UPnP: M-SEARCH stop");	if (a->next == a) {		sm->msearch_replies = NULL;	} else {		if (sm->msearch_replies == a)			sm->msearch_replies = a->next;		a->next->prev = a->prev;		a->prev->next = a->next;	}	os_free(a);	sm->n_msearch_replies--;}static void msearchreply_state_machine_handler(void *eloop_data,					       void *user_ctx){	struct advertisement_state_machine *a = user_ctx;	struct upnp_wps_device_sm *sm = a->sm;	struct wpabuf *msg;	int next_timeout_msec = 100;	int next_timeout_sec = 0;	int islast = 0;	/*	 * Each response is sent twice (in case lost) w/ 100 msec delay	 * between; spec says no more than 3 times.	 * One pair for rootdevice, one pair for uuid, and a pair each for	 * each of the two urns.	 */	/* TODO: should only send the requested response types */	wpa_printf(MSG_MSGDUMP, "WPS UPnP: M-SEARCH reply state=%d (%s:%d)",		   a->state, inet_ntoa(a->client.sin_addr),		   ntohs(a->client.sin_port));	msg = next_advertisement(a, &islast);	if (msg == NULL)		return;	/*	 * Send it on the multicast socket to avoid having to set up another	 * socket.	 */	if (sendto(sm->multicast_sd, wpabuf_head(msg), wpabuf_len(msg), 0,		   (struct sockaddr *) &a->client, sizeof(a->client)) < 0) {		wpa_printf(MSG_DEBUG, "WPS UPnP: M-SEARCH reply sendto "			   "errno %d (%s) for %s:%d",			   errno, strerror(errno),			   inet_ntoa(a->client.sin_addr),			   ntohs(a->client.sin_port));		/* Ignore error and hope for the best */	}	wpabuf_free(msg);	if (islast) {		wpa_printf(MSG_DEBUG, "WPS UPnP: M-SEARCH reply done");		msearchreply_state_machine_stop(a);		return;	}	a->state++;	wpa_printf(MSG_MSGDUMP, "WPS UPnP: M-SEARCH reply in %d.%03d sec",		   next_timeout_sec, next_timeout_msec);	eloop_register_timeout(next_timeout_sec, next_timeout_msec,			       msearchreply_state_machine_handler, sm, a);}/** * msearchreply_state_machine_start - Reply to M-SEARCH discovery request * @sm: WPS UPnP state machine from upnp_wps_device_init() * @client: Client address * @mx: Maximum delay in seconds * * Use TTL of 4 (this was done when socket set up). * A response should be given in randomized portion of min(MX,120) seconds * * UPnP-arch-DeviceArchitecture, 1.2.3: * To be found, a device must send a UDP response to the source IP address and * port that sent the request to the multicast channel. Devices respond if the * ST header of the M-SEARCH request is "ssdp:all", "upnp:rootdevice", "uuid:" * followed by a UUID that exactly matches one advertised by the device. */static void msearchreply_state_machine_start(struct upnp_wps_device_sm *sm,					     struct sockaddr_in *client,					     int mx){	struct advertisement_state_machine *a;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -