18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * UPnP WPS Device - Event processing
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2000-2003 Intel Corporation
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2006-2007 Sony Corporation
58d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2008-2009 Atheros Communications
68d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * See wps_upnp.c for more details on licensing and code history.
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <assert.h>
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eloop.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "uuid.h"
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "http_client.h"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps_defs.h"
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps_upnp.h"
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wps_upnp_i.h"
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Event message generation (to subscribers)
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * We make a separate copy for each message for each subscriber. This memory
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wasted could be limited (adding code complexity) by sharing copies, keeping
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * a usage count and freeing when zero.
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Sending a message requires using a HTTP over TCP NOTIFY
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * (like a PUT) which requires a number of states..
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define MAX_EVENTS_QUEUED 20   /* How far behind queued events */
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define MAX_FAILURES 10 /* Drop subscription after this many failures */
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* How long to wait before sending event */
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define EVENT_DELAY_SECONDS 0
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define EVENT_DELAY_MSEC 0
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Event information that we send to each subscriber is remembered in this
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * struct. The event cannot be sent by simple UDP; it has to be sent by a HTTP
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * over TCP transaction which requires various states.. It may also need to be
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * retried at a different address (if more than one is available).
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * TODO: As an optimization we could share data between subscribers.
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wps_event_ {
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct dl_list list;
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct subscription *s;         /* parent */
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned subscriber_sequence;   /* which event for this subscription*/
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int retry;             /* which retry */
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct subscr_addr *addr;       /* address to connect to */
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *data;            /* event data to send */
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct http_client *http_event;
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* event_clean -- clean sockets etc. of event
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Leaves data, retry count etc. alone.
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void event_clean(struct wps_event_ *e)
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (e->s->current_event == e)
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		e->s->current_event = NULL;
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	http_client_free(e->http_event);
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	e->http_event = NULL;
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* event_delete -- delete single unqueued event
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * (be sure to dequeue first if need be)
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void event_delete(struct wps_event_ *e)
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS UPnP: Delete event %p", e);
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event_clean(e);
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(e->data);
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(e);
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* event_dequeue -- get next event from the queue
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns NULL if empty.
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wps_event_ *event_dequeue(struct subscription *s)
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_event_ *e;
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	e = dl_list_first(&s->event_queue, struct wps_event_, list);
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (e) {
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS UPnP: Dequeue event %p for "
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "subscription %p", e, s);
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dl_list_del(&e->list);
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return e;
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* event_delete_all -- delete entire event queue and current event */
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid event_delete_all(struct subscription *s)
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_event_ *e;
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while ((e = event_dequeue(s)) != NULL)
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event_delete(e);
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (s->current_event) {
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event_delete(s->current_event);
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* will set: s->current_event = NULL;  */
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * event_retry - Called when we had a failure delivering event msg
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @e: Event
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @do_next_address: skip address e.g. on connect fail
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void event_retry(struct wps_event_ *e, int do_next_address)
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct subscription *s = e->s;
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct upnp_wps_device_sm *sm = s->sm;
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS UPnP: Retry event %p for subscription %p",
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   e, s);
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event_clean(e);
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* will set: s->current_event = NULL; */
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (do_next_address) {
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		e->retry++;
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS UPnP: Try address %d", e->retry);
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (e->retry >= dl_list_len(&s->addr_list)) {
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS UPnP: Giving up on sending event "
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "for %s", e->addr->domain_and_port);
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event_delete(e);
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		s->last_event_failed = 1;
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!dl_list_empty(&s->event_queue))
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			event_send_all_later(s->sm);
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_add(&s->event_queue, &e->list);
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event_send_all_later(sm);
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * event_build_message(struct wps_event_ *e)
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *buf;
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char *b;
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf = wpabuf_alloc(1000 + wpabuf_len(e->data));
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL)
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_printf(buf, "NOTIFY %s HTTP/1.1\r\n", e->addr->path);
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_str(buf, "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n");
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_printf(buf, "HOST: %s\r\n", e->addr->domain_and_port);
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_str(buf, "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n"
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       "NT: upnp:event\r\n"
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       "NTS: upnp:propchange\r\n");
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_str(buf, "SID: uuid:");
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	b = wpabuf_put(buf, 0);
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	uuid_bin2str(e->s->uuid, b, 80);
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put(buf, os_strlen(b));
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_str(buf, "\r\n");
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_printf(buf, "SEQ: %u\r\n", e->subscriber_sequence);
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_printf(buf, "CONTENT-LENGTH: %d\r\n",
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      (int) wpabuf_len(e->data));
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_str(buf, "\r\n"); /* terminating empty line */
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_put_buf(buf, e->data);
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return buf;
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void event_addr_failure(struct wps_event_ *e)
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct subscription *s = e->s;
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	e->addr->num_failures++;
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS UPnP: Failed to send event %p to %s "
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "(num_failures=%u)",
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   e, e->addr->domain_and_port, e->addr->num_failures);
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (e->addr->num_failures < MAX_FAILURES) {
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Try other addresses, if available */
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event_retry(e, 1);
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * If other side doesn't like what we say, forget about them.
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * (There is no way to tell other side that we are dropping them...).
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS UPnP: Deleting subscription %p "
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "address %s due to errors", s, e->addr->domain_and_port);
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_del(&e->addr->list);
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	subscr_addr_delete(e->addr);
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	e->addr = NULL;
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (dl_list_empty(&s->addr_list)) {
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* if we've given up on all addresses */
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS UPnP: Removing subscription %p "
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "with no addresses", s);
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dl_list_del(&s->list);
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		subscription_destroy(s);
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Try other addresses, if available */
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event_retry(e, 0);
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void event_http_cb(void *ctx, struct http_client *c,
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  enum http_client_event event)
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_event_ *e = ctx;
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct subscription *s = e->s;
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP client callback: e=%p c=%p "
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "event=%d", e, c, event);
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (event) {
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_OK:
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG,
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "WPS UPnP: Got event %p reply OK from %s",
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   e, e->addr->domain_and_port);
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		e->addr->num_failures = 0;
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		s->last_event_failed = 0;
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event_delete(e);
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Schedule sending more if there is more to send */
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!dl_list_empty(&s->event_queue))
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			event_send_all_later(s->sm);
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_FAILED:
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS UPnP: Event send failure");
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event_addr_failure(e);
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_INVALID_REPLY:
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS UPnP: Invalid reply");
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event_addr_failure(e);
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case HTTP_CLIENT_TIMEOUT:
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS UPnP: Event send timeout");
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event_addr_failure(e);
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* event_send_start -- prepare to send a event message to subscriber
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This gets complicated because:
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * -- The message is sent via TCP and we have to keep the stream open
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *      for 30 seconds to get a response... then close it.
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * -- But we might have other event happen in the meantime...
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *      we have to queue them, if we lose them then the subscriber will
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *      be forced to unsubscribe and subscribe again.
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * -- If multiple URLs are provided then we are supposed to try successive
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *      ones after 30 second timeout.
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * -- The URLs might use domain names instead of dotted decimal addresses,
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *      and resolution of those may cause unwanted sleeping.
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * -- Doing the initial TCP connect can take a while, so we have to come
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *      back after connection and then send the data.
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns nonzero on error;
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Prerequisite: No current event send (s->current_event == NULL)
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *      and non-empty queue.
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int event_send_start(struct subscription *s)
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_event_ *e;
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int itry;
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *buf;
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Assume we are called ONLY with no current event and ONLY with
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * nonempty event queue and ONLY with at least one address to send to.
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (dl_list_empty(&s->addr_list))
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (s->current_event)
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (dl_list_empty(&s->event_queue))
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	s->current_event = e = event_dequeue(s);
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Use address according to number of retries */
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	itry = 0;
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each(e->addr, &s->addr_list, struct subscr_addr, list)
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (itry++ == e->retry)
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (itry < e->retry)
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf = event_build_message(e);
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL) {
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event_retry(e, 0);
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	e->http_event = http_client_addr(&e->addr->saddr, buf, 0,
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 event_http_cb, e);
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (e->http_event == NULL) {
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(buf);
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event_retry(e, 0);
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* event_send_all_later_handler -- actually send events as needed */
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void event_send_all_later_handler(void *eloop_data, void *user_ctx)
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct upnp_wps_device_sm *sm = user_ctx;
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct subscription *s, *tmp;
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int nerrors = 0;
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->event_send_all_queued = 0;
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each_safe(s, tmp, &sm->subscriptions, struct subscription,
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      list) {
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (s->current_event == NULL /* not busy */ &&
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    !dl_list_empty(&s->event_queue) /* more to do */) {
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (event_send_start(s))
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				nerrors++;
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nerrors) {
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Try again later */
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event_send_all_later(sm);
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* event_send_all_later -- schedule sending events to all subscribers
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * that need it.
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This avoids two problems:
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * -- After getting a subscription, we should not send the first event
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *      until after our reply is fully queued to be sent back,
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * -- Possible stack depth or infinite recursion issues.
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid event_send_all_later(struct upnp_wps_device_sm *sm)
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * The exact time in the future isn't too important. Waiting a bit
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * might let us do several together.
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->event_send_all_queued)
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->event_send_all_queued = 1;
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_timeout(EVENT_DELAY_SECONDS, EVENT_DELAY_MSEC,
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       event_send_all_later_handler, NULL, sm);
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* event_send_stop_all -- cleanup */
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid event_send_stop_all(struct upnp_wps_device_sm *sm)
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->event_send_all_queued)
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_cancel_timeout(event_send_all_later_handler, NULL, sm);
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->event_send_all_queued = 0;
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * event_add - Add a new event to a queue
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @s: Subscription
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @data: Event data (is copied; caller retains ownership)
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @probereq: Whether this is a Probe Request event
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on error, 1 on max event queue limit reached
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint event_add(struct subscription *s, const struct wpabuf *data, int probereq)
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wps_event_ *e;
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int len;
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len = dl_list_len(&s->event_queue);
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len >= MAX_EVENTS_QUEUED) {
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS UPnP: Too many events queued for "
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "subscriber %p", s);
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (probereq)
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 1;
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Drop oldest entry to allow EAP event to be stored. */
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		e = event_dequeue(s);
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!e)
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 1;
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event_delete(e);
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (s->last_event_failed && probereq && len > 0) {
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Avoid queuing frames for subscribers that may have left
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * without unsubscribing.
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "WPS UPnP: Do not queue more Probe "
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Request frames for subscription %p since last "
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "delivery failed", s);
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	e = os_zalloc(sizeof(*e));
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (e == NULL)
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_init(&e->list);
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	e->s = s;
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	e->data = wpabuf_dup(data);
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (e->data == NULL) {
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(e);
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	e->subscriber_sequence = s->next_subscriber_sequence++;
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (s->next_subscriber_sequence == 0)
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		s->next_subscriber_sequence++;
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "WPS UPnP: Queue event %p for subscriber %p "
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "(queue len %u)", e, s, len + 1);
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_add_tail(&s->event_queue, &e->list);
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event_send_all_later(s->sm);
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
424