139beb93cSSam Leffler /*
239beb93cSSam Leffler * UPnP WPS Device - Event processing
339beb93cSSam Leffler * Copyright (c) 2000-2003 Intel Corporation
439beb93cSSam Leffler * Copyright (c) 2006-2007 Sony Corporation
539beb93cSSam Leffler * Copyright (c) 2008-2009 Atheros Communications
6f05cddf9SRui Paulo * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
739beb93cSSam Leffler *
839beb93cSSam Leffler * See wps_upnp.c for more details on licensing and code history.
939beb93cSSam Leffler */
1039beb93cSSam Leffler
1139beb93cSSam Leffler #include "includes.h"
1239beb93cSSam Leffler #include <assert.h>
1339beb93cSSam Leffler
1439beb93cSSam Leffler #include "common.h"
1539beb93cSSam Leffler #include "eloop.h"
1639beb93cSSam Leffler #include "uuid.h"
17e28a4053SRui Paulo #include "http_client.h"
1839beb93cSSam Leffler #include "wps_defs.h"
1939beb93cSSam Leffler #include "wps_upnp.h"
2039beb93cSSam Leffler #include "wps_upnp_i.h"
2139beb93cSSam Leffler
2239beb93cSSam Leffler /*
2339beb93cSSam Leffler * Event message generation (to subscribers)
2439beb93cSSam Leffler *
2539beb93cSSam Leffler * We make a separate copy for each message for each subscriber. This memory
2639beb93cSSam Leffler * wasted could be limited (adding code complexity) by sharing copies, keeping
2739beb93cSSam Leffler * a usage count and freeing when zero.
2839beb93cSSam Leffler *
2939beb93cSSam Leffler * Sending a message requires using a HTTP over TCP NOTIFY
3039beb93cSSam Leffler * (like a PUT) which requires a number of states..
3139beb93cSSam Leffler */
3239beb93cSSam Leffler
3339beb93cSSam Leffler #define MAX_EVENTS_QUEUED 20 /* How far behind queued events */
34f05cddf9SRui Paulo #define MAX_FAILURES 10 /* Drop subscription after this many failures */
3539beb93cSSam Leffler
3639beb93cSSam Leffler /* How long to wait before sending event */
3739beb93cSSam Leffler #define EVENT_DELAY_SECONDS 0
3839beb93cSSam Leffler #define EVENT_DELAY_MSEC 0
3939beb93cSSam Leffler
4039beb93cSSam Leffler /*
4139beb93cSSam Leffler * Event information that we send to each subscriber is remembered in this
4239beb93cSSam Leffler * struct. The event cannot be sent by simple UDP; it has to be sent by a HTTP
4339beb93cSSam Leffler * over TCP transaction which requires various states.. It may also need to be
4439beb93cSSam Leffler * retried at a different address (if more than one is available).
4539beb93cSSam Leffler *
4639beb93cSSam Leffler * TODO: As an optimization we could share data between subscribers.
4739beb93cSSam Leffler */
4839beb93cSSam Leffler struct wps_event_ {
49e28a4053SRui Paulo struct dl_list list;
5039beb93cSSam Leffler struct subscription *s; /* parent */
5139beb93cSSam Leffler unsigned subscriber_sequence; /* which event for this subscription*/
52e28a4053SRui Paulo unsigned int retry; /* which retry */
5339beb93cSSam Leffler struct subscr_addr *addr; /* address to connect to */
5439beb93cSSam Leffler struct wpabuf *data; /* event data to send */
55e28a4053SRui Paulo struct http_client *http_event;
5639beb93cSSam Leffler };
5739beb93cSSam Leffler
5839beb93cSSam Leffler
5939beb93cSSam Leffler /* event_clean -- clean sockets etc. of event
6039beb93cSSam Leffler * Leaves data, retry count etc. alone.
6139beb93cSSam Leffler */
event_clean(struct wps_event_ * e)6239beb93cSSam Leffler static void event_clean(struct wps_event_ *e)
6339beb93cSSam Leffler {
64e28a4053SRui Paulo if (e->s->current_event == e)
6539beb93cSSam Leffler e->s->current_event = NULL;
66e28a4053SRui Paulo http_client_free(e->http_event);
67e28a4053SRui Paulo e->http_event = NULL;
6839beb93cSSam Leffler }
6939beb93cSSam Leffler
7039beb93cSSam Leffler
7139beb93cSSam Leffler /* event_delete -- delete single unqueued event
7239beb93cSSam Leffler * (be sure to dequeue first if need be)
7339beb93cSSam Leffler */
event_delete(struct wps_event_ * e)743157ba21SRui Paulo static void event_delete(struct wps_event_ *e)
7539beb93cSSam Leffler {
76f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS UPnP: Delete event %p", e);
7739beb93cSSam Leffler event_clean(e);
7839beb93cSSam Leffler wpabuf_free(e->data);
7939beb93cSSam Leffler os_free(e);
8039beb93cSSam Leffler }
8139beb93cSSam Leffler
8239beb93cSSam Leffler
8339beb93cSSam Leffler /* event_dequeue -- get next event from the queue
8439beb93cSSam Leffler * Returns NULL if empty.
8539beb93cSSam Leffler */
event_dequeue(struct subscription * s)8639beb93cSSam Leffler static struct wps_event_ *event_dequeue(struct subscription *s)
8739beb93cSSam Leffler {
88e28a4053SRui Paulo struct wps_event_ *e;
89e28a4053SRui Paulo e = dl_list_first(&s->event_queue, struct wps_event_, list);
90f05cddf9SRui Paulo if (e) {
91f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS UPnP: Dequeue event %p for "
92f05cddf9SRui Paulo "subscription %p", e, s);
93e28a4053SRui Paulo dl_list_del(&e->list);
94f05cddf9SRui Paulo }
9539beb93cSSam Leffler return e;
9639beb93cSSam Leffler }
9739beb93cSSam Leffler
9839beb93cSSam Leffler
99*c1d255d3SCy Schubert /* wps_upnp_event_delete_all -- delete entire event queue and current event */
wps_upnp_event_delete_all(struct subscription * s)100*c1d255d3SCy Schubert void wps_upnp_event_delete_all(struct subscription *s)
10139beb93cSSam Leffler {
10239beb93cSSam Leffler struct wps_event_ *e;
10339beb93cSSam Leffler while ((e = event_dequeue(s)) != NULL)
10439beb93cSSam Leffler event_delete(e);
10539beb93cSSam Leffler if (s->current_event) {
10639beb93cSSam Leffler event_delete(s->current_event);
10739beb93cSSam Leffler /* will set: s->current_event = NULL; */
10839beb93cSSam Leffler }
10939beb93cSSam Leffler }
11039beb93cSSam Leffler
11139beb93cSSam Leffler
11239beb93cSSam Leffler /**
11339beb93cSSam Leffler * event_retry - Called when we had a failure delivering event msg
11439beb93cSSam Leffler * @e: Event
11539beb93cSSam Leffler * @do_next_address: skip address e.g. on connect fail
11639beb93cSSam Leffler */
event_retry(struct wps_event_ * e,int do_next_address)11739beb93cSSam Leffler static void event_retry(struct wps_event_ *e, int do_next_address)
11839beb93cSSam Leffler {
11939beb93cSSam Leffler struct subscription *s = e->s;
12039beb93cSSam Leffler struct upnp_wps_device_sm *sm = s->sm;
12139beb93cSSam Leffler
122f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS UPnP: Retry event %p for subscription %p",
123f05cddf9SRui Paulo e, s);
12439beb93cSSam Leffler event_clean(e);
12539beb93cSSam Leffler /* will set: s->current_event = NULL; */
12639beb93cSSam Leffler
127f05cddf9SRui Paulo if (do_next_address) {
12839beb93cSSam Leffler e->retry++;
129f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS UPnP: Try address %d", e->retry);
130f05cddf9SRui Paulo }
131e28a4053SRui Paulo if (e->retry >= dl_list_len(&s->addr_list)) {
13239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS UPnP: Giving up on sending event "
13339beb93cSSam Leffler "for %s", e->addr->domain_and_port);
134f05cddf9SRui Paulo event_delete(e);
135f05cddf9SRui Paulo s->last_event_failed = 1;
136f05cddf9SRui Paulo if (!dl_list_empty(&s->event_queue))
137*c1d255d3SCy Schubert wps_upnp_event_send_all_later(s->sm);
13839beb93cSSam Leffler return;
13939beb93cSSam Leffler }
140e28a4053SRui Paulo dl_list_add(&s->event_queue, &e->list);
141*c1d255d3SCy Schubert wps_upnp_event_send_all_later(sm);
14239beb93cSSam Leffler }
14339beb93cSSam Leffler
14439beb93cSSam Leffler
event_build_message(struct wps_event_ * e)145e28a4053SRui Paulo static struct wpabuf * event_build_message(struct wps_event_ *e)
14639beb93cSSam Leffler {
14739beb93cSSam Leffler struct wpabuf *buf;
14839beb93cSSam Leffler char *b;
14939beb93cSSam Leffler
150b266d2f2SCy Schubert buf = wpabuf_alloc(1000 + os_strlen(e->addr->path) +
151b266d2f2SCy Schubert wpabuf_len(e->data));
152e28a4053SRui Paulo if (buf == NULL)
153e28a4053SRui Paulo return NULL;
15439beb93cSSam Leffler wpabuf_printf(buf, "NOTIFY %s HTTP/1.1\r\n", e->addr->path);
15539beb93cSSam Leffler wpabuf_put_str(buf, "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n");
15639beb93cSSam Leffler wpabuf_printf(buf, "HOST: %s\r\n", e->addr->domain_and_port);
15739beb93cSSam Leffler wpabuf_put_str(buf, "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n"
15839beb93cSSam Leffler "NT: upnp:event\r\n"
15939beb93cSSam Leffler "NTS: upnp:propchange\r\n");
16039beb93cSSam Leffler wpabuf_put_str(buf, "SID: uuid:");
16139beb93cSSam Leffler b = wpabuf_put(buf, 0);
162e28a4053SRui Paulo uuid_bin2str(e->s->uuid, b, 80);
16339beb93cSSam Leffler wpabuf_put(buf, os_strlen(b));
16439beb93cSSam Leffler wpabuf_put_str(buf, "\r\n");
16539beb93cSSam Leffler wpabuf_printf(buf, "SEQ: %u\r\n", e->subscriber_sequence);
16639beb93cSSam Leffler wpabuf_printf(buf, "CONTENT-LENGTH: %d\r\n",
16739beb93cSSam Leffler (int) wpabuf_len(e->data));
16839beb93cSSam Leffler wpabuf_put_str(buf, "\r\n"); /* terminating empty line */
16939beb93cSSam Leffler wpabuf_put_buf(buf, e->data);
170e28a4053SRui Paulo return buf;
17139beb93cSSam Leffler }
17239beb93cSSam Leffler
17339beb93cSSam Leffler
event_addr_failure(struct wps_event_ * e)174f05cddf9SRui Paulo static void event_addr_failure(struct wps_event_ *e)
175f05cddf9SRui Paulo {
176f05cddf9SRui Paulo struct subscription *s = e->s;
177f05cddf9SRui Paulo
178f05cddf9SRui Paulo e->addr->num_failures++;
179f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS UPnP: Failed to send event %p to %s "
180f05cddf9SRui Paulo "(num_failures=%u)",
181f05cddf9SRui Paulo e, e->addr->domain_and_port, e->addr->num_failures);
182f05cddf9SRui Paulo
183f05cddf9SRui Paulo if (e->addr->num_failures < MAX_FAILURES) {
184f05cddf9SRui Paulo /* Try other addresses, if available */
185f05cddf9SRui Paulo event_retry(e, 1);
186f05cddf9SRui Paulo return;
187f05cddf9SRui Paulo }
188f05cddf9SRui Paulo
189f05cddf9SRui Paulo /*
190f05cddf9SRui Paulo * If other side doesn't like what we say, forget about them.
191f05cddf9SRui Paulo * (There is no way to tell other side that we are dropping them...).
192f05cddf9SRui Paulo */
193f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS UPnP: Deleting subscription %p "
194f05cddf9SRui Paulo "address %s due to errors", s, e->addr->domain_and_port);
195f05cddf9SRui Paulo dl_list_del(&e->addr->list);
196f05cddf9SRui Paulo subscr_addr_delete(e->addr);
197f05cddf9SRui Paulo e->addr = NULL;
198f05cddf9SRui Paulo
199f05cddf9SRui Paulo if (dl_list_empty(&s->addr_list)) {
200f05cddf9SRui Paulo /* if we've given up on all addresses */
201f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS UPnP: Removing subscription %p "
202f05cddf9SRui Paulo "with no addresses", s);
203f05cddf9SRui Paulo dl_list_del(&s->list);
204f05cddf9SRui Paulo subscription_destroy(s);
205f05cddf9SRui Paulo return;
206f05cddf9SRui Paulo }
207f05cddf9SRui Paulo
208f05cddf9SRui Paulo /* Try other addresses, if available */
209f05cddf9SRui Paulo event_retry(e, 0);
210f05cddf9SRui Paulo }
211f05cddf9SRui Paulo
212f05cddf9SRui Paulo
event_http_cb(void * ctx,struct http_client * c,enum http_client_event event)213e28a4053SRui Paulo static void event_http_cb(void *ctx, struct http_client *c,
214e28a4053SRui Paulo enum http_client_event event)
215e28a4053SRui Paulo {
216e28a4053SRui Paulo struct wps_event_ *e = ctx;
217e28a4053SRui Paulo struct subscription *s = e->s;
218e28a4053SRui Paulo
219f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP client callback: e=%p c=%p "
220f05cddf9SRui Paulo "event=%d", e, c, event);
221e28a4053SRui Paulo switch (event) {
222e28a4053SRui Paulo case HTTP_CLIENT_OK:
223e28a4053SRui Paulo wpa_printf(MSG_DEBUG,
224f05cddf9SRui Paulo "WPS UPnP: Got event %p reply OK from %s",
225f05cddf9SRui Paulo e, e->addr->domain_and_port);
226f05cddf9SRui Paulo e->addr->num_failures = 0;
227f05cddf9SRui Paulo s->last_event_failed = 0;
228e28a4053SRui Paulo event_delete(e);
229e28a4053SRui Paulo
23039beb93cSSam Leffler /* Schedule sending more if there is more to send */
231e28a4053SRui Paulo if (!dl_list_empty(&s->event_queue))
232*c1d255d3SCy Schubert wps_upnp_event_send_all_later(s->sm);
233e28a4053SRui Paulo break;
234e28a4053SRui Paulo case HTTP_CLIENT_FAILED:
235f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS UPnP: Event send failure");
236f05cddf9SRui Paulo event_addr_failure(e);
237f05cddf9SRui Paulo break;
238e28a4053SRui Paulo case HTTP_CLIENT_INVALID_REPLY:
239f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS UPnP: Invalid reply");
240f05cddf9SRui Paulo event_addr_failure(e);
241e28a4053SRui Paulo break;
242e28a4053SRui Paulo case HTTP_CLIENT_TIMEOUT:
243e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "WPS UPnP: Event send timeout");
244f05cddf9SRui Paulo event_addr_failure(e);
245f05cddf9SRui Paulo break;
246e28a4053SRui Paulo }
24739beb93cSSam Leffler }
24839beb93cSSam Leffler
24939beb93cSSam Leffler
25039beb93cSSam Leffler /* event_send_start -- prepare to send a event message to subscriber
25139beb93cSSam Leffler *
25239beb93cSSam Leffler * This gets complicated because:
25339beb93cSSam Leffler * -- The message is sent via TCP and we have to keep the stream open
25439beb93cSSam Leffler * for 30 seconds to get a response... then close it.
25539beb93cSSam Leffler * -- But we might have other event happen in the meantime...
25639beb93cSSam Leffler * we have to queue them, if we lose them then the subscriber will
25739beb93cSSam Leffler * be forced to unsubscribe and subscribe again.
25839beb93cSSam Leffler * -- If multiple URLs are provided then we are supposed to try successive
25939beb93cSSam Leffler * ones after 30 second timeout.
26039beb93cSSam Leffler * -- The URLs might use domain names instead of dotted decimal addresses,
26139beb93cSSam Leffler * and resolution of those may cause unwanted sleeping.
26239beb93cSSam Leffler * -- Doing the initial TCP connect can take a while, so we have to come
26339beb93cSSam Leffler * back after connection and then send the data.
26439beb93cSSam Leffler *
26539beb93cSSam Leffler * Returns nonzero on error;
26639beb93cSSam Leffler *
26739beb93cSSam Leffler * Prerequisite: No current event send (s->current_event == NULL)
26839beb93cSSam Leffler * and non-empty queue.
26939beb93cSSam Leffler */
event_send_start(struct subscription * s)27039beb93cSSam Leffler static int event_send_start(struct subscription *s)
27139beb93cSSam Leffler {
27239beb93cSSam Leffler struct wps_event_ *e;
273e28a4053SRui Paulo unsigned int itry;
274e28a4053SRui Paulo struct wpabuf *buf;
27539beb93cSSam Leffler
27639beb93cSSam Leffler /*
27739beb93cSSam Leffler * Assume we are called ONLY with no current event and ONLY with
27839beb93cSSam Leffler * nonempty event queue and ONLY with at least one address to send to.
27939beb93cSSam Leffler */
280325151a3SRui Paulo if (dl_list_empty(&s->addr_list) ||
281325151a3SRui Paulo s->current_event ||
282325151a3SRui Paulo dl_list_empty(&s->event_queue))
283f05cddf9SRui Paulo return -1;
28439beb93cSSam Leffler
28539beb93cSSam Leffler s->current_event = e = event_dequeue(s);
28639beb93cSSam Leffler
287e28a4053SRui Paulo /* Use address according to number of retries */
288e28a4053SRui Paulo itry = 0;
289e28a4053SRui Paulo dl_list_for_each(e->addr, &s->addr_list, struct subscr_addr, list)
290e28a4053SRui Paulo if (itry++ == e->retry)
291e28a4053SRui Paulo break;
292e28a4053SRui Paulo if (itry < e->retry)
293e28a4053SRui Paulo return -1;
29439beb93cSSam Leffler
295e28a4053SRui Paulo buf = event_build_message(e);
296e28a4053SRui Paulo if (buf == NULL) {
2977d748adcSCy Schubert event_addr_failure(e);
29839beb93cSSam Leffler return -1;
29939beb93cSSam Leffler }
300e28a4053SRui Paulo
301e28a4053SRui Paulo e->http_event = http_client_addr(&e->addr->saddr, buf, 0,
302e28a4053SRui Paulo event_http_cb, e);
303e28a4053SRui Paulo if (e->http_event == NULL) {
304e28a4053SRui Paulo wpabuf_free(buf);
3057d748adcSCy Schubert event_addr_failure(e);
30639beb93cSSam Leffler return -1;
30739beb93cSSam Leffler }
308e28a4053SRui Paulo
30939beb93cSSam Leffler return 0;
31039beb93cSSam Leffler }
31139beb93cSSam Leffler
31239beb93cSSam Leffler
31339beb93cSSam Leffler /* event_send_all_later_handler -- actually send events as needed */
event_send_all_later_handler(void * eloop_data,void * user_ctx)3143157ba21SRui Paulo static void event_send_all_later_handler(void *eloop_data, void *user_ctx)
31539beb93cSSam Leffler {
31639beb93cSSam Leffler struct upnp_wps_device_sm *sm = user_ctx;
317e28a4053SRui Paulo struct subscription *s, *tmp;
31839beb93cSSam Leffler int nerrors = 0;
31939beb93cSSam Leffler
32039beb93cSSam Leffler sm->event_send_all_queued = 0;
321e28a4053SRui Paulo dl_list_for_each_safe(s, tmp, &sm->subscriptions, struct subscription,
322e28a4053SRui Paulo list) {
32339beb93cSSam Leffler if (s->current_event == NULL /* not busy */ &&
324e28a4053SRui Paulo !dl_list_empty(&s->event_queue) /* more to do */) {
32539beb93cSSam Leffler if (event_send_start(s))
32639beb93cSSam Leffler nerrors++;
32739beb93cSSam Leffler }
32839beb93cSSam Leffler }
32939beb93cSSam Leffler
33039beb93cSSam Leffler if (nerrors) {
33139beb93cSSam Leffler /* Try again later */
332*c1d255d3SCy Schubert wps_upnp_event_send_all_later(sm);
33339beb93cSSam Leffler }
33439beb93cSSam Leffler }
33539beb93cSSam Leffler
33639beb93cSSam Leffler
337*c1d255d3SCy Schubert /* wps_upnp_event_send_all_later -- schedule sending events to all subscribers
33839beb93cSSam Leffler * that need it.
33939beb93cSSam Leffler * This avoids two problems:
34039beb93cSSam Leffler * -- After getting a subscription, we should not send the first event
34139beb93cSSam Leffler * until after our reply is fully queued to be sent back,
34239beb93cSSam Leffler * -- Possible stack depth or infinite recursion issues.
34339beb93cSSam Leffler */
wps_upnp_event_send_all_later(struct upnp_wps_device_sm * sm)344*c1d255d3SCy Schubert void wps_upnp_event_send_all_later(struct upnp_wps_device_sm *sm)
34539beb93cSSam Leffler {
34639beb93cSSam Leffler /*
34739beb93cSSam Leffler * The exact time in the future isn't too important. Waiting a bit
34839beb93cSSam Leffler * might let us do several together.
34939beb93cSSam Leffler */
35039beb93cSSam Leffler if (sm->event_send_all_queued)
35139beb93cSSam Leffler return;
35239beb93cSSam Leffler sm->event_send_all_queued = 1;
35339beb93cSSam Leffler eloop_register_timeout(EVENT_DELAY_SECONDS, EVENT_DELAY_MSEC,
35439beb93cSSam Leffler event_send_all_later_handler, NULL, sm);
35539beb93cSSam Leffler }
35639beb93cSSam Leffler
35739beb93cSSam Leffler
358*c1d255d3SCy Schubert /* wps_upnp_event_send_stop_all -- cleanup */
wps_upnp_event_send_stop_all(struct upnp_wps_device_sm * sm)359*c1d255d3SCy Schubert void wps_upnp_event_send_stop_all(struct upnp_wps_device_sm *sm)
36039beb93cSSam Leffler {
36139beb93cSSam Leffler if (sm->event_send_all_queued)
36239beb93cSSam Leffler eloop_cancel_timeout(event_send_all_later_handler, NULL, sm);
36339beb93cSSam Leffler sm->event_send_all_queued = 0;
36439beb93cSSam Leffler }
36539beb93cSSam Leffler
36639beb93cSSam Leffler
36739beb93cSSam Leffler /**
368*c1d255d3SCy Schubert * wps_upnp_event_add - Add a new event to a queue
36939beb93cSSam Leffler * @s: Subscription
37039beb93cSSam Leffler * @data: Event data (is copied; caller retains ownership)
371f05cddf9SRui Paulo * @probereq: Whether this is a Probe Request event
372f05cddf9SRui Paulo * Returns: 0 on success, -1 on error, 1 on max event queue limit reached
37339beb93cSSam Leffler */
wps_upnp_event_add(struct subscription * s,const struct wpabuf * data,int probereq)374*c1d255d3SCy Schubert int wps_upnp_event_add(struct subscription *s, const struct wpabuf *data,
375*c1d255d3SCy Schubert int probereq)
37639beb93cSSam Leffler {
37739beb93cSSam Leffler struct wps_event_ *e;
378f05cddf9SRui Paulo unsigned int len;
37939beb93cSSam Leffler
380f05cddf9SRui Paulo len = dl_list_len(&s->event_queue);
381f05cddf9SRui Paulo if (len >= MAX_EVENTS_QUEUED) {
38239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS UPnP: Too many events queued for "
383f05cddf9SRui Paulo "subscriber %p", s);
384f05cddf9SRui Paulo if (probereq)
38539beb93cSSam Leffler return 1;
386f05cddf9SRui Paulo
387f05cddf9SRui Paulo /* Drop oldest entry to allow EAP event to be stored. */
388f05cddf9SRui Paulo e = event_dequeue(s);
389f05cddf9SRui Paulo if (!e)
390f05cddf9SRui Paulo return 1;
391f05cddf9SRui Paulo event_delete(e);
392f05cddf9SRui Paulo }
393f05cddf9SRui Paulo
394f05cddf9SRui Paulo if (s->last_event_failed && probereq && len > 0) {
395f05cddf9SRui Paulo /*
396f05cddf9SRui Paulo * Avoid queuing frames for subscribers that may have left
397f05cddf9SRui Paulo * without unsubscribing.
398f05cddf9SRui Paulo */
399f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS UPnP: Do not queue more Probe "
400f05cddf9SRui Paulo "Request frames for subscription %p since last "
401f05cddf9SRui Paulo "delivery failed", s);
402f05cddf9SRui Paulo return -1;
40339beb93cSSam Leffler }
40439beb93cSSam Leffler
40539beb93cSSam Leffler e = os_zalloc(sizeof(*e));
40639beb93cSSam Leffler if (e == NULL)
407f05cddf9SRui Paulo return -1;
408e28a4053SRui Paulo dl_list_init(&e->list);
40939beb93cSSam Leffler e->s = s;
41039beb93cSSam Leffler e->data = wpabuf_dup(data);
41139beb93cSSam Leffler if (e->data == NULL) {
41239beb93cSSam Leffler os_free(e);
413f05cddf9SRui Paulo return -1;
41439beb93cSSam Leffler }
41539beb93cSSam Leffler e->subscriber_sequence = s->next_subscriber_sequence++;
41639beb93cSSam Leffler if (s->next_subscriber_sequence == 0)
41739beb93cSSam Leffler s->next_subscriber_sequence++;
418f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS UPnP: Queue event %p for subscriber %p "
419f05cddf9SRui Paulo "(queue len %u)", e, s, len + 1);
420e28a4053SRui Paulo dl_list_add_tail(&s->event_queue, &e->list);
421*c1d255d3SCy Schubert wps_upnp_event_send_all_later(s->sm);
42239beb93cSSam Leffler return 0;
42339beb93cSSam Leffler }
424