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 6*f05cddf9SRui 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 */ 34*f05cddf9SRui 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 */ 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 */ 743157ba21SRui Paulo static void event_delete(struct wps_event_ *e) 7539beb93cSSam Leffler { 76*f05cddf9SRui 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 */ 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); 90*f05cddf9SRui Paulo if (e) { 91*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS UPnP: Dequeue event %p for " 92*f05cddf9SRui Paulo "subscription %p", e, s); 93e28a4053SRui Paulo dl_list_del(&e->list); 94*f05cddf9SRui Paulo } 9539beb93cSSam Leffler return e; 9639beb93cSSam Leffler } 9739beb93cSSam Leffler 9839beb93cSSam Leffler 9939beb93cSSam Leffler /* event_delete_all -- delete entire event queue and current event */ 10039beb93cSSam Leffler void 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 */ 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 122*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS UPnP: Retry event %p for subscription %p", 123*f05cddf9SRui Paulo e, s); 12439beb93cSSam Leffler event_clean(e); 12539beb93cSSam Leffler /* will set: s->current_event = NULL; */ 12639beb93cSSam Leffler 127*f05cddf9SRui Paulo if (do_next_address) { 12839beb93cSSam Leffler e->retry++; 129*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS UPnP: Try address %d", e->retry); 130*f05cddf9SRui 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); 134*f05cddf9SRui Paulo event_delete(e); 135*f05cddf9SRui Paulo s->last_event_failed = 1; 136*f05cddf9SRui Paulo if (!dl_list_empty(&s->event_queue)) 137*f05cddf9SRui Paulo event_send_all_later(s->sm); 13839beb93cSSam Leffler return; 13939beb93cSSam Leffler } 140e28a4053SRui Paulo dl_list_add(&s->event_queue, &e->list); 14139beb93cSSam Leffler event_send_all_later(sm); 14239beb93cSSam Leffler } 14339beb93cSSam Leffler 14439beb93cSSam Leffler 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 15039beb93cSSam Leffler buf = wpabuf_alloc(1000 + wpabuf_len(e->data)); 151e28a4053SRui Paulo if (buf == NULL) 152e28a4053SRui Paulo return NULL; 15339beb93cSSam Leffler wpabuf_printf(buf, "NOTIFY %s HTTP/1.1\r\n", e->addr->path); 15439beb93cSSam Leffler wpabuf_put_str(buf, "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n"); 15539beb93cSSam Leffler wpabuf_printf(buf, "HOST: %s\r\n", e->addr->domain_and_port); 15639beb93cSSam Leffler wpabuf_put_str(buf, "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n" 15739beb93cSSam Leffler "NT: upnp:event\r\n" 15839beb93cSSam Leffler "NTS: upnp:propchange\r\n"); 15939beb93cSSam Leffler wpabuf_put_str(buf, "SID: uuid:"); 16039beb93cSSam Leffler b = wpabuf_put(buf, 0); 161e28a4053SRui Paulo uuid_bin2str(e->s->uuid, b, 80); 16239beb93cSSam Leffler wpabuf_put(buf, os_strlen(b)); 16339beb93cSSam Leffler wpabuf_put_str(buf, "\r\n"); 16439beb93cSSam Leffler wpabuf_printf(buf, "SEQ: %u\r\n", e->subscriber_sequence); 16539beb93cSSam Leffler wpabuf_printf(buf, "CONTENT-LENGTH: %d\r\n", 16639beb93cSSam Leffler (int) wpabuf_len(e->data)); 16739beb93cSSam Leffler wpabuf_put_str(buf, "\r\n"); /* terminating empty line */ 16839beb93cSSam Leffler wpabuf_put_buf(buf, e->data); 169e28a4053SRui Paulo return buf; 17039beb93cSSam Leffler } 17139beb93cSSam Leffler 17239beb93cSSam Leffler 173*f05cddf9SRui Paulo static void event_addr_failure(struct wps_event_ *e) 174*f05cddf9SRui Paulo { 175*f05cddf9SRui Paulo struct subscription *s = e->s; 176*f05cddf9SRui Paulo 177*f05cddf9SRui Paulo e->addr->num_failures++; 178*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS UPnP: Failed to send event %p to %s " 179*f05cddf9SRui Paulo "(num_failures=%u)", 180*f05cddf9SRui Paulo e, e->addr->domain_and_port, e->addr->num_failures); 181*f05cddf9SRui Paulo 182*f05cddf9SRui Paulo if (e->addr->num_failures < MAX_FAILURES) { 183*f05cddf9SRui Paulo /* Try other addresses, if available */ 184*f05cddf9SRui Paulo event_retry(e, 1); 185*f05cddf9SRui Paulo return; 186*f05cddf9SRui Paulo } 187*f05cddf9SRui Paulo 188*f05cddf9SRui Paulo /* 189*f05cddf9SRui Paulo * If other side doesn't like what we say, forget about them. 190*f05cddf9SRui Paulo * (There is no way to tell other side that we are dropping them...). 191*f05cddf9SRui Paulo */ 192*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS UPnP: Deleting subscription %p " 193*f05cddf9SRui Paulo "address %s due to errors", s, e->addr->domain_and_port); 194*f05cddf9SRui Paulo dl_list_del(&e->addr->list); 195*f05cddf9SRui Paulo subscr_addr_delete(e->addr); 196*f05cddf9SRui Paulo e->addr = NULL; 197*f05cddf9SRui Paulo 198*f05cddf9SRui Paulo if (dl_list_empty(&s->addr_list)) { 199*f05cddf9SRui Paulo /* if we've given up on all addresses */ 200*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS UPnP: Removing subscription %p " 201*f05cddf9SRui Paulo "with no addresses", s); 202*f05cddf9SRui Paulo dl_list_del(&s->list); 203*f05cddf9SRui Paulo subscription_destroy(s); 204*f05cddf9SRui Paulo return; 205*f05cddf9SRui Paulo } 206*f05cddf9SRui Paulo 207*f05cddf9SRui Paulo /* Try other addresses, if available */ 208*f05cddf9SRui Paulo event_retry(e, 0); 209*f05cddf9SRui Paulo } 210*f05cddf9SRui Paulo 211*f05cddf9SRui Paulo 212e28a4053SRui Paulo static void event_http_cb(void *ctx, struct http_client *c, 213e28a4053SRui Paulo enum http_client_event event) 214e28a4053SRui Paulo { 215e28a4053SRui Paulo struct wps_event_ *e = ctx; 216e28a4053SRui Paulo struct subscription *s = e->s; 217e28a4053SRui Paulo 218*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP client callback: e=%p c=%p " 219*f05cddf9SRui Paulo "event=%d", e, c, event); 220e28a4053SRui Paulo switch (event) { 221e28a4053SRui Paulo case HTTP_CLIENT_OK: 222e28a4053SRui Paulo wpa_printf(MSG_DEBUG, 223*f05cddf9SRui Paulo "WPS UPnP: Got event %p reply OK from %s", 224*f05cddf9SRui Paulo e, e->addr->domain_and_port); 225*f05cddf9SRui Paulo e->addr->num_failures = 0; 226*f05cddf9SRui Paulo s->last_event_failed = 0; 227e28a4053SRui Paulo event_delete(e); 228e28a4053SRui Paulo 22939beb93cSSam Leffler /* Schedule sending more if there is more to send */ 230e28a4053SRui Paulo if (!dl_list_empty(&s->event_queue)) 23139beb93cSSam Leffler event_send_all_later(s->sm); 232e28a4053SRui Paulo break; 233e28a4053SRui Paulo case HTTP_CLIENT_FAILED: 234*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS UPnP: Event send failure"); 235*f05cddf9SRui Paulo event_addr_failure(e); 236*f05cddf9SRui Paulo break; 237e28a4053SRui Paulo case HTTP_CLIENT_INVALID_REPLY: 238*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS UPnP: Invalid reply"); 239*f05cddf9SRui Paulo event_addr_failure(e); 240e28a4053SRui Paulo break; 241e28a4053SRui Paulo case HTTP_CLIENT_TIMEOUT: 242e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "WPS UPnP: Event send timeout"); 243*f05cddf9SRui Paulo event_addr_failure(e); 244*f05cddf9SRui Paulo break; 245e28a4053SRui Paulo } 24639beb93cSSam Leffler } 24739beb93cSSam Leffler 24839beb93cSSam Leffler 24939beb93cSSam Leffler /* event_send_start -- prepare to send a event message to subscriber 25039beb93cSSam Leffler * 25139beb93cSSam Leffler * This gets complicated because: 25239beb93cSSam Leffler * -- The message is sent via TCP and we have to keep the stream open 25339beb93cSSam Leffler * for 30 seconds to get a response... then close it. 25439beb93cSSam Leffler * -- But we might have other event happen in the meantime... 25539beb93cSSam Leffler * we have to queue them, if we lose them then the subscriber will 25639beb93cSSam Leffler * be forced to unsubscribe and subscribe again. 25739beb93cSSam Leffler * -- If multiple URLs are provided then we are supposed to try successive 25839beb93cSSam Leffler * ones after 30 second timeout. 25939beb93cSSam Leffler * -- The URLs might use domain names instead of dotted decimal addresses, 26039beb93cSSam Leffler * and resolution of those may cause unwanted sleeping. 26139beb93cSSam Leffler * -- Doing the initial TCP connect can take a while, so we have to come 26239beb93cSSam Leffler * back after connection and then send the data. 26339beb93cSSam Leffler * 26439beb93cSSam Leffler * Returns nonzero on error; 26539beb93cSSam Leffler * 26639beb93cSSam Leffler * Prerequisite: No current event send (s->current_event == NULL) 26739beb93cSSam Leffler * and non-empty queue. 26839beb93cSSam Leffler */ 26939beb93cSSam Leffler static int event_send_start(struct subscription *s) 27039beb93cSSam Leffler { 27139beb93cSSam Leffler struct wps_event_ *e; 272e28a4053SRui Paulo unsigned int itry; 273e28a4053SRui Paulo struct wpabuf *buf; 27439beb93cSSam Leffler 27539beb93cSSam Leffler /* 27639beb93cSSam Leffler * Assume we are called ONLY with no current event and ONLY with 27739beb93cSSam Leffler * nonempty event queue and ONLY with at least one address to send to. 27839beb93cSSam Leffler */ 279*f05cddf9SRui Paulo if (dl_list_empty(&s->addr_list)) 280*f05cddf9SRui Paulo return -1; 281*f05cddf9SRui Paulo if (s->current_event) 282*f05cddf9SRui Paulo return -1; 283*f05cddf9SRui Paulo if (dl_list_empty(&s->event_queue)) 284*f05cddf9SRui Paulo return -1; 28539beb93cSSam Leffler 28639beb93cSSam Leffler s->current_event = e = event_dequeue(s); 28739beb93cSSam Leffler 288e28a4053SRui Paulo /* Use address according to number of retries */ 289e28a4053SRui Paulo itry = 0; 290e28a4053SRui Paulo dl_list_for_each(e->addr, &s->addr_list, struct subscr_addr, list) 291e28a4053SRui Paulo if (itry++ == e->retry) 292e28a4053SRui Paulo break; 293e28a4053SRui Paulo if (itry < e->retry) 294e28a4053SRui Paulo return -1; 29539beb93cSSam Leffler 296e28a4053SRui Paulo buf = event_build_message(e); 297e28a4053SRui Paulo if (buf == NULL) { 29839beb93cSSam Leffler event_retry(e, 0); 29939beb93cSSam Leffler return -1; 30039beb93cSSam Leffler } 301e28a4053SRui Paulo 302e28a4053SRui Paulo e->http_event = http_client_addr(&e->addr->saddr, buf, 0, 303e28a4053SRui Paulo event_http_cb, e); 304e28a4053SRui Paulo if (e->http_event == NULL) { 305e28a4053SRui Paulo wpabuf_free(buf); 30639beb93cSSam Leffler event_retry(e, 0); 30739beb93cSSam Leffler return -1; 30839beb93cSSam Leffler } 309e28a4053SRui Paulo 31039beb93cSSam Leffler return 0; 31139beb93cSSam Leffler } 31239beb93cSSam Leffler 31339beb93cSSam Leffler 31439beb93cSSam Leffler /* event_send_all_later_handler -- actually send events as needed */ 3153157ba21SRui Paulo static void event_send_all_later_handler(void *eloop_data, void *user_ctx) 31639beb93cSSam Leffler { 31739beb93cSSam Leffler struct upnp_wps_device_sm *sm = user_ctx; 318e28a4053SRui Paulo struct subscription *s, *tmp; 31939beb93cSSam Leffler int nerrors = 0; 32039beb93cSSam Leffler 32139beb93cSSam Leffler sm->event_send_all_queued = 0; 322e28a4053SRui Paulo dl_list_for_each_safe(s, tmp, &sm->subscriptions, struct subscription, 323e28a4053SRui Paulo list) { 32439beb93cSSam Leffler if (s->current_event == NULL /* not busy */ && 325e28a4053SRui Paulo !dl_list_empty(&s->event_queue) /* more to do */) { 32639beb93cSSam Leffler if (event_send_start(s)) 32739beb93cSSam Leffler nerrors++; 32839beb93cSSam Leffler } 32939beb93cSSam Leffler } 33039beb93cSSam Leffler 33139beb93cSSam Leffler if (nerrors) { 33239beb93cSSam Leffler /* Try again later */ 33339beb93cSSam Leffler event_send_all_later(sm); 33439beb93cSSam Leffler } 33539beb93cSSam Leffler } 33639beb93cSSam Leffler 33739beb93cSSam Leffler 33839beb93cSSam Leffler /* event_send_all_later -- schedule sending events to all subscribers 33939beb93cSSam Leffler * that need it. 34039beb93cSSam Leffler * This avoids two problems: 34139beb93cSSam Leffler * -- After getting a subscription, we should not send the first event 34239beb93cSSam Leffler * until after our reply is fully queued to be sent back, 34339beb93cSSam Leffler * -- Possible stack depth or infinite recursion issues. 34439beb93cSSam Leffler */ 34539beb93cSSam Leffler void event_send_all_later(struct upnp_wps_device_sm *sm) 34639beb93cSSam Leffler { 34739beb93cSSam Leffler /* 34839beb93cSSam Leffler * The exact time in the future isn't too important. Waiting a bit 34939beb93cSSam Leffler * might let us do several together. 35039beb93cSSam Leffler */ 35139beb93cSSam Leffler if (sm->event_send_all_queued) 35239beb93cSSam Leffler return; 35339beb93cSSam Leffler sm->event_send_all_queued = 1; 35439beb93cSSam Leffler eloop_register_timeout(EVENT_DELAY_SECONDS, EVENT_DELAY_MSEC, 35539beb93cSSam Leffler event_send_all_later_handler, NULL, sm); 35639beb93cSSam Leffler } 35739beb93cSSam Leffler 35839beb93cSSam Leffler 35939beb93cSSam Leffler /* event_send_stop_all -- cleanup */ 36039beb93cSSam Leffler void event_send_stop_all(struct upnp_wps_device_sm *sm) 36139beb93cSSam Leffler { 36239beb93cSSam Leffler if (sm->event_send_all_queued) 36339beb93cSSam Leffler eloop_cancel_timeout(event_send_all_later_handler, NULL, sm); 36439beb93cSSam Leffler sm->event_send_all_queued = 0; 36539beb93cSSam Leffler } 36639beb93cSSam Leffler 36739beb93cSSam Leffler 36839beb93cSSam Leffler /** 36939beb93cSSam Leffler * event_add - Add a new event to a queue 37039beb93cSSam Leffler * @s: Subscription 37139beb93cSSam Leffler * @data: Event data (is copied; caller retains ownership) 372*f05cddf9SRui Paulo * @probereq: Whether this is a Probe Request event 373*f05cddf9SRui Paulo * Returns: 0 on success, -1 on error, 1 on max event queue limit reached 37439beb93cSSam Leffler */ 375*f05cddf9SRui Paulo int event_add(struct subscription *s, const struct wpabuf *data, int probereq) 37639beb93cSSam Leffler { 37739beb93cSSam Leffler struct wps_event_ *e; 378*f05cddf9SRui Paulo unsigned int len; 37939beb93cSSam Leffler 380*f05cddf9SRui Paulo len = dl_list_len(&s->event_queue); 381*f05cddf9SRui Paulo if (len >= MAX_EVENTS_QUEUED) { 38239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "WPS UPnP: Too many events queued for " 383*f05cddf9SRui Paulo "subscriber %p", s); 384*f05cddf9SRui Paulo if (probereq) 38539beb93cSSam Leffler return 1; 386*f05cddf9SRui Paulo 387*f05cddf9SRui Paulo /* Drop oldest entry to allow EAP event to be stored. */ 388*f05cddf9SRui Paulo e = event_dequeue(s); 389*f05cddf9SRui Paulo if (!e) 390*f05cddf9SRui Paulo return 1; 391*f05cddf9SRui Paulo event_delete(e); 392*f05cddf9SRui Paulo } 393*f05cddf9SRui Paulo 394*f05cddf9SRui Paulo if (s->last_event_failed && probereq && len > 0) { 395*f05cddf9SRui Paulo /* 396*f05cddf9SRui Paulo * Avoid queuing frames for subscribers that may have left 397*f05cddf9SRui Paulo * without unsubscribing. 398*f05cddf9SRui Paulo */ 399*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS UPnP: Do not queue more Probe " 400*f05cddf9SRui Paulo "Request frames for subscription %p since last " 401*f05cddf9SRui Paulo "delivery failed", s); 402*f05cddf9SRui Paulo return -1; 40339beb93cSSam Leffler } 40439beb93cSSam Leffler 40539beb93cSSam Leffler e = os_zalloc(sizeof(*e)); 40639beb93cSSam Leffler if (e == NULL) 407*f05cddf9SRui 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); 413*f05cddf9SRui 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++; 418*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "WPS UPnP: Queue event %p for subscriber %p " 419*f05cddf9SRui Paulo "(queue len %u)", e, s, len + 1); 420e28a4053SRui Paulo dl_list_add_tail(&s->event_queue, &e->list); 42139beb93cSSam Leffler event_send_all_later(s->sm); 42239beb93cSSam Leffler return 0; 42339beb93cSSam Leffler } 424