📄 wps_upnp.c
字号:
domain = mem; strcpy(domain, domain_and_port); delim = strchr(domain, ':'); if (delim) { *delim++ = 0; /* null terminate domain */ if (isdigit(*delim)) port = atol(delim); } /* * getaddrinfo does the right thing with dotted decimal notations, or * will resolve domain names. Resolving domain names will unfortunately * hang the entire program until it is resolved or it times out * internal to getaddrinfo; fortunately we think that the use of actual * domain names (vs. dotted decimal notations) should be uncommon. */ os_memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET; /* IPv4 */ hints.ai_socktype = SOCK_STREAM;#if NO_DOMAIN_NAME_RESOLUTION /* Suppress domain name resolutions that would halt * the program for periods of time */ hints.ai_flags = AI_NUMERICHOST;#else /* Allow domain name resolution. */ hints.ai_flags = 0;#endif hints.ai_protocol = 0; /* Any protocol? */ rerr = getaddrinfo(domain, NULL /* fill in port ourselves */, &hints, &result); if (rerr) { wpa_printf(MSG_INFO, "WPS UPnP: Resolve error %d (%s) on: %s", rerr, gai_strerror(rerr), domain); goto fail; } for (rp = result; rp; rp = rp->ai_next) { /* Limit no. of address to avoid denial of service attack */ if (s->n_addr >= MAX_ADDR_PER_SUBSCRIPTION) { wpa_printf(MSG_INFO, "WPS UPnP: subscr_addr_add_url: " "Ignoring excessive addresses"); break; } a = os_zalloc(sizeof(*a) + alloc_len); if (a == NULL) continue; a->s = s; mem = (void *) (a + 1); a->domain_and_port = mem; strcpy(mem, domain_and_port); mem += 1 + strlen(mem); a->path = mem; if (path[0] != '/') *mem++ = '/'; strcpy(mem, path); mem += 1 + strlen(mem); os_memcpy(&a->saddr, rp->ai_addr, sizeof(a->saddr)); a->saddr.sin_port = htons(port); subscr_addr_link(s, a); a = NULL; /* don't free it below */ }fail: if (result) freeaddrinfo(result); os_free(scratch_mem); os_free(a);}/* subscr_addr_list_create -- create list from urls in string. * Each url is enclosed by angle brackets. */static void subscr_addr_list_create(struct subscription *s, const char *url_list){ char *end; for (;;) { while (*url_list == ' ' || *url_list == '\t') url_list++; if (*url_list != '<') break; url_list++; end = os_strchr(url_list, '>'); if (end == NULL) break; *end++ = 0; subscr_addr_add_url(s, url_list); url_list = end; }}int send_wpabuf(int fd, struct wpabuf *buf){ wpa_printf(MSG_DEBUG, "WPS UPnP: Send %lu byte message", (unsigned long) wpabuf_len(buf)); errno = 0; if (write(fd, wpabuf_head(buf), wpabuf_len(buf)) != (int) wpabuf_len(buf)) { wpa_printf(MSG_ERROR, "WPS UPnP: Failed to send buffer: " "errno=%d (%s)", errno, strerror(errno)); return -1; } return 0;}static void wpabuf_put_property(struct wpabuf *buf, const char *name, const char *value){ wpabuf_put_str(buf, "<e:property>"); wpabuf_printf(buf, "<%s>", name); if (value) wpabuf_put_str(buf, value); wpabuf_printf(buf, "</%s>", name); wpabuf_put_str(buf, "</e:property>\n");}/** * upnp_wps_device_send_event - Queue event messages for subscribers * @sm: WPS UPnP state machine from upnp_wps_device_init() * * This function queues the last WLANEvent to be sent for all currently * subscribed UPnP control points. sm->wlanevent must have been set with the * encoded data before calling this function. */static void upnp_wps_device_send_event(struct upnp_wps_device_sm *sm){ /* Enqueue event message for all subscribers */ struct wpabuf *buf; /* holds event message */ int buf_size = 0; struct subscription *s; /* Actually, utf-8 is the default, but it doesn't hurt to specify it */ const char *format_head = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">\n"; const char *format_tail = "</e:propertyset>\n"; if (sm->subscriptions == NULL) { /* optimize */ return; } /* Determine buffer size needed first */ buf_size += os_strlen(format_head); buf_size += 50 + 2 * os_strlen("WLANEvent"); if (sm->wlanevent) buf_size += os_strlen(sm->wlanevent); buf_size += os_strlen(format_tail); buf = wpabuf_alloc(buf_size); if (buf == NULL) return; wpabuf_put_str(buf, format_head); wpabuf_put_property(buf, "WLANEvent", sm->wlanevent); wpabuf_put_str(buf, format_tail); wpa_printf(MSG_MSGDUMP, "WPS UPnP: WLANEvent message:\n%s", (char *) wpabuf_head(buf)); s = sm->subscriptions; do { if (event_add(s, buf)) { struct subscription *s_old = s; wpa_printf(MSG_INFO, "WPS UPnP: Dropping " "subscriber due to event backlog"); s = s_old->next; subscription_unlink(s_old); subscription_destroy(s_old); } else { s = s->next; } } while (s != sm->subscriptions); wpabuf_free(buf);}/* * Event subscription (subscriber machines register with us to receive event * messages). * This is the result of an incoming HTTP over TCP SUBSCRIBE request. *//* subscription_unlink -- remove from the active list */void subscription_unlink(struct subscription *s){ struct upnp_wps_device_sm *sm = s->sm; if (s->next == s) { /* only one? */ sm->subscriptions = NULL; } else { if (sm->subscriptions == s) sm->subscriptions = s->next; s->next->prev = s->prev; s->prev->next = s->next; } sm->n_subscriptions--;}/* subscription_link_to_end -- link to end of active list * (should have high expiry time!) */static void subscription_link_to_end(struct subscription *s){ struct upnp_wps_device_sm *sm = s->sm; if (sm->subscriptions) { s->next = sm->subscriptions; s->prev = s->next->prev; s->prev->next = s; s->next->prev = s; } else { sm->subscriptions = s->next = s->prev = s; } sm->n_subscriptions++;}/* subscription_destroy -- destroy an unlinked subscription * Be sure to unlink first if necessary. */void subscription_destroy(struct subscription *s){ wpa_printf(MSG_DEBUG, "WPS UPnP: Destroy subscription %p", s); if (s->addr_list) subscr_addr_free_all(s); event_delete_all(s); os_free(s);}/* subscription_list_age -- remove expired subscriptions */static void subscription_list_age(struct upnp_wps_device_sm *sm, time_t now){ struct subscription *s; while ((s = sm->subscriptions) != NULL && s->timeout_time < now) { wpa_printf(MSG_DEBUG, "WPS UPnP: Removing aged subscription"); subscription_unlink(s); subscription_destroy(s); }}/* subscription_find -- return existing subscription matching uuid, if any * returns NULL if not found */struct subscription * subscription_find(struct upnp_wps_device_sm *sm, const u8 uuid[UUID_LEN]){ struct subscription *s0 = sm->subscriptions; struct subscription *s = s0; if (s0 == NULL) return NULL; do { if (os_memcmp(s->uuid, uuid, UUID_LEN) == 0) return s; /* Found match */ s = s->next; } while (s != s0); return NULL;}/* subscription_first_event -- send format/queue event that is automatically * sent on a new subscription. */static int subscription_first_event(struct subscription *s){ /* * Actually, utf-8 is the default, but it doesn't hurt to specify it. * * APStatus is apparently a bit set, * 0x1 = configuration change (but is always set?) * 0x10 = ap is locked * * Per UPnP spec, we send out the last value of each variable, even * for WLANEvent, whatever it was. */ char *wlan_event; struct wpabuf *buf; int ap_status = 1; /* TODO: add 0x10 if access point is locked */ const char *head = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">\n"; const char *tail = "</e:propertyset>\n"; char txt[10]; wlan_event = s->sm->wlanevent; if (wlan_event == NULL || *wlan_event == '\0') { wpa_printf(MSG_DEBUG, "WPS UPnP: WLANEvent not known for " "initial event message"); wlan_event = ""; } buf = wpabuf_alloc(500 + os_strlen(wlan_event)); if (buf == NULL) return 1; wpabuf_put_str(buf, head); wpabuf_put_property(buf, "STAStatus", "1"); os_snprintf(txt, sizeof(txt), "%d", ap_status); wpabuf_put_property(buf, "APStatus", txt); if (*wlan_event) wpabuf_put_property(buf, "WLANEvent", wlan_event); wpabuf_put_str(buf, tail); if (event_add(s, buf)) { wpabuf_free(buf); return 1; } wpabuf_free(buf); return 0;}/** * subscription_start - Rremember a UPnP control point to send events to. * @sm: WPS UPnP state machine from upnp_wps_device_init() * @callback_urls: malloc' mem given to the subscription * Returns: %NULL on error, or pointer to new subscription structure. */struct subscription * subscription_start(struct upnp_wps_device_sm *sm, char *callback_urls){ struct subscription *s; time_t now = time(NULL); time_t expire = now + UPNP_SUBSCRIBE_SEC; /* Get rid of expired subscriptions so we have room */ subscription_list_age(sm, now); /* If too many subscriptions, remove oldest */ if (sm->n_subscriptions >= MAX_SUBSCRIPTIONS) { s = sm->subscriptions; wpa_printf(MSG_INFO, "WPS UPnP: Too many subscriptions, " "trashing oldest"); subscription_unlink(s); subscription_destroy(s); } s = os_zalloc(sizeof(*s)); if (s == NULL) return NULL; s->sm = sm; s->timeout_time = expire; uuid_make(s->uuid); subscr_addr_list_create(s, callback_urls); /* Add to end of list, since it has the highest expiration time */ subscription_link_to_end(s); /* Queue up immediate event message (our last event) * as required by UPnP spec. */ if (subscription_first_event(s)) { wpa_printf(MSG_INFO, "WPS UPnP: Dropping subscriber due to " "event backlog"); subscription_unlink(s); subscription_destroy(s); return NULL; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -