static struct wpabuf * event_build_message(struct wps_event_ *e) { struct wpabuf *buf; char *b; buf = wpabuf_alloc(1000 + wpabuf_len(e->data)); if (buf == NULL) return NULL; wpabuf_printf(buf, "NOTIFY %s HTTP/1.1\r\n", e->addr->path); wpabuf_put_str(buf, "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n"); wpabuf_printf(buf, "HOST: %s\r\n", e->addr->domain_and_port); wpabuf_put_str(buf, "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n" "NT: upnp:event\r\n" "NTS: upnp:propchange\r\n"); wpabuf_put_str(buf, "SID: uuid:"); b = wpabuf_put(buf, 0); uuid_bin2str(e->s->uuid, b, 80); wpabuf_put(buf, os_strlen(b)); wpabuf_put_str(buf, "\r\n"); wpabuf_printf(buf, "SEQ: %u\r\n", e->subscriber_sequence); wpabuf_printf(buf, "CONTENT-LENGTH: %d\r\n", (int) wpabuf_len(e->data)); wpabuf_put_str(buf, "\r\n"); /* terminating empty line */ wpabuf_put_buf(buf, e->data); return buf; }
static void wps_er_http_req(void *ctx, struct http_request *req) { struct wps_er *er = ctx; struct sockaddr_in *cli = http_request_get_cli_addr(req); enum httpread_hdr_type type = http_request_get_type(req); struct wpabuf *buf; wpa_printf(MSG_DEBUG, "WPS ER: HTTP request: '%s' (type %d) from " "%s:%d", http_request_get_uri(req), type, inet_ntoa(cli->sin_addr), ntohs(cli->sin_port)); switch (type) { case HTTPREAD_HDR_TYPE_NOTIFY: wps_er_http_notify(er, req); break; default: wpa_printf(MSG_DEBUG, "WPS ER: Unsupported HTTP request type " "%d", type); buf = wpabuf_alloc(200); if (buf == NULL) { http_request_deinit(req); return; } wpabuf_put_str(buf, "HTTP/1.1 501 Unimplemented\r\n" "Connection: close\r\n"); http_put_date(buf); wpabuf_put_str(buf, "\r\n"); http_request_send_and_deinit(req, buf); break; } }
/* xml_data_encode -- format data for xml file, escaping special characters. * * Note that we assume we are using utf8 both as input and as output! * In utf8, characters may be classed as follows: * 0xxxxxxx(2) -- 1 byte ascii char * 11xxxxxx(2) -- 1st byte of multi-byte char w/ unicode value >= 0x80 * 110xxxxx(2) -- 1st byte of 2 byte sequence (5 payload bits here) * 1110xxxx(2) -- 1st byte of 3 byte sequence (4 payload bits here) * 11110xxx(2) -- 1st byte of 4 byte sequence (3 payload bits here) * 10xxxxxx(2) -- extension byte (6 payload bits per byte) * Some values implied by the above are however illegal because they * do not represent unicode chars or are not the shortest encoding. * Actually, we can almost entirely ignore the above and just do * text processing same as for ascii text. * * XML is written with arbitrary unicode characters, except that five * characters have special meaning and so must be escaped where they * appear in payload data... which we do here. */ void xml_data_encode(struct wpabuf *buf, const char *data, int len) { int i; for (i = 0; i < len; i++) { u8 c = ((u8 *) data)[i]; if (c == '<') { wpabuf_put_str(buf, "<"); continue; } if (c == '>') { wpabuf_put_str(buf, ">"); continue; } if (c == '&') { wpabuf_put_str(buf, "&"); continue; } if (c == '\'') { wpabuf_put_str(buf, "'"); continue; } if (c == '"') { wpabuf_put_str(buf, """); continue; } /* * We could try to represent control characters using the * sequence: &#x; where x is replaced by a hex numeral, but not * clear why we would do this. */ wpabuf_put_u8(buf, c); } }
static void http_put_empty(struct wpabuf *buf, enum http_reply_code code) { http_put_reply_code(buf, code); wpabuf_put_str(buf, http_server_hdr); wpabuf_put_str(buf, http_connection_close); wpabuf_put_str(buf, "Content-Length: 0\r\n" "\r\n"); }
/* format_wps_device_xml -- produce content of "file" wps_device.xml * (UPNP_WPS_DEVICE_XML_FILE) */ static void format_wps_device_xml(struct upnp_wps_device_interface *iface, struct upnp_wps_device_sm *sm, struct wpabuf *buf) { const char *s; char uuid_string[80]; wpabuf_put_str(buf, wps_device_xml_prefix); /* * Add required fields with default values if not configured. Add * optional and recommended fields only if configured. */ s = iface->wps->friendly_name; s = ((s && *s) ? s : "WPS Access Point"); xml_add_tagged_data(buf, "friendlyName", s); s = iface->wps->dev.manufacturer; s = ((s && *s) ? s : ""); xml_add_tagged_data(buf, "manufacturer", s); if (iface->wps->manufacturer_url) xml_add_tagged_data(buf, "manufacturerURL", iface->wps->manufacturer_url); if (iface->wps->model_description) xml_add_tagged_data(buf, "modelDescription", iface->wps->model_description); s = iface->wps->dev.model_name; s = ((s && *s) ? s : ""); xml_add_tagged_data(buf, "modelName", s); if (iface->wps->dev.model_number) xml_add_tagged_data(buf, "modelNumber", iface->wps->dev.model_number); if (iface->wps->model_url) xml_add_tagged_data(buf, "modelURL", iface->wps->model_url); if (iface->wps->dev.serial_number) xml_add_tagged_data(buf, "serialNumber", iface->wps->dev.serial_number); uuid_bin2str(iface->wps->uuid, uuid_string, sizeof(uuid_string)); s = uuid_string; /* Need "uuid:" prefix, thus we can't use xml_add_tagged_data() * easily... */ wpabuf_put_str(buf, "<UDN>uuid:"); xml_data_encode(buf, s, os_strlen(s)); wpabuf_put_str(buf, "</UDN>\n"); if (iface->wps->upc) xml_add_tagged_data(buf, "UPC", iface->wps->upc); wpabuf_put_str(buf, wps_device_xml_postfix); }
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"); }
static struct wpabuf * wps_er_soap_hdr(const struct wpabuf *msg, const char *name, const char *arg_name, const char *path, const struct sockaddr_in *dst, char **len_ptr, char **body_ptr) { unsigned char *encoded; size_t encoded_len; struct wpabuf *buf; if (msg) { encoded = base64_encode(wpabuf_head(msg), wpabuf_len(msg), &encoded_len); if (encoded == NULL) return NULL; } else { encoded = NULL; encoded_len = 0; } buf = wpabuf_alloc(1000 + encoded_len); if (buf == NULL) { os_free(encoded); return NULL; } wpabuf_printf(buf, "POST %s HTTP/1.1\r\n" "Host: %s:%d\r\n" "Content-Type: text/xml; charset=\"utf-8\"\r\n" "Content-Length: ", path, inet_ntoa(dst->sin_addr), ntohs(dst->sin_port)); *len_ptr = wpabuf_put(buf, 0); wpabuf_printf(buf, " \r\n" "SOAPACTION: \"%s#%s\"\r\n" "\r\n", urn_wfawlanconfig, name); *body_ptr = wpabuf_put(buf, 0); wpabuf_put_str(buf, soap_prefix); wpabuf_printf(buf, "<u:%s xmlns:u=\"", name); wpabuf_put_str(buf, urn_wfawlanconfig); wpabuf_put_str(buf, "\">\n"); if (encoded) { wpabuf_printf(buf, "<%s>%s</%s>\n", arg_name, (char *) encoded, arg_name); os_free(encoded); } return buf; }
static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf, const u8 *home_realm, size_t home_realm_len, int nai_realm, int nai_home_realm) { if (nai_realm && hapd->conf->nai_realm_data) { u8 *len; unsigned int i, j; len = gas_anqp_add_element(buf, ANQP_NAI_REALM); wpabuf_put_le16(buf, hapd->conf->nai_realm_count); for (i = 0; i < hapd->conf->nai_realm_count; i++) { u8 *realm_data_len, *realm_len; struct hostapd_nai_realm_data *realm; realm = &hapd->conf->nai_realm_data[i]; realm_data_len = wpabuf_put(buf, 2); wpabuf_put_u8(buf, realm->encoding); realm_len = wpabuf_put(buf, 1); for (j = 0; realm->realm[j]; j++) { if (j > 0) wpabuf_put_u8(buf, ';'); wpabuf_put_str(buf, realm->realm[j]); } *realm_len = (u8 *) wpabuf_put(buf, 0) - realm_len - 1; anqp_add_nai_realm_eap(buf, realm); gas_anqp_set_element_len(buf, realm_data_len); } gas_anqp_set_element_len(buf, len); } else if (nai_home_realm && hapd->conf->nai_realm_data) { hs20_add_nai_home_realm_matches(hapd, buf, home_realm, home_realm_len); } }
static void anqp_add_nai_realm_data(struct wpabuf *buf, struct hostapd_nai_realm_data *realm, unsigned int realm_idx) { u8 *realm_data_len; unsigned int i; wpa_printf(MSG_DEBUG, "realm=%s, len=%d", realm->realm[realm_idx], (int) os_strlen(realm->realm[realm_idx])); realm_data_len = wpabuf_put(buf, 2); wpabuf_put_u8(buf, realm->encoding); wpabuf_put_u8(buf, os_strlen(realm->realm[realm_idx])); wpabuf_put_str(buf, realm->realm[realm_idx]); if (realm->num_auths) { wpabuf_put_u8(buf, 1); /* EAP method count */ wpabuf_put_u8(buf, 2 + (3 * realm->num_auths)); wpabuf_put_u8(buf, realm->eap_method); wpabuf_put_u8(buf, realm->num_auths); for (i = 0; i < realm->num_auths; i++) { wpabuf_put_u8(buf, realm->auth_id[i]); wpabuf_put_u8(buf, 1); wpabuf_put_u8(buf, realm->auth_val[i]); } } else { wpabuf_put_u8(buf, 0); /* EAP method count */ } gas_anqp_set_element_len(buf, realm_data_len); }
static void http_req(void *ctx, struct http_request *req) { struct browser_data *data = ctx; struct wpabuf *resp; const char *url; int done = 0; url = http_request_get_uri(req); wpa_printf(MSG_INFO, "Browser response received: %s", url); if (os_strcmp(url, "/") == 0) { data->success = 1; done = 1; } else if (os_strncmp(url, "/osu/", 5) == 0) { data->success = atoi(url + 5); done = 1; } resp = wpabuf_alloc(100); if (resp == NULL) { http_request_deinit(req); if (done) eloop_terminate(); return; } wpabuf_put_str(resp, "User input completed"); if (done) { eloop_cancel_timeout(browser_timeout, NULL, NULL); eloop_register_timeout(0, 500000, browser_timeout, &data, NULL); } http_request_send_and_deinit(req, resp); }
void wps_er_send_ssdp_msearch(struct wps_er *er) { struct wpabuf *msg; struct sockaddr_in dest; msg = wpabuf_alloc(500); if (msg == NULL) return; wpabuf_put_str(msg, "M-SEARCH * HTTP/1.1\r\n" "HOST: 239.255.255.250:1900\r\n" "MAN: \"ssdp:discover\"\r\n" "MX: 3\r\n" "ST: urn:schemas-wifialliance-org:device:WFADevice:1" "\r\n" "\r\n"); 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(er->multicast_sd, wpabuf_head(msg), wpabuf_len(msg), 0, (struct sockaddr *) &dest, sizeof(dest)) < 0) wpa_printf(MSG_DEBUG, "WPS ER: M-SEARCH sendto failed: " "%d (%s)", errno, strerror(errno)); wpabuf_free(msg); }
static void wps_er_http_resp_not_found(struct http_request *req) { struct wpabuf *buf; buf = wpabuf_alloc(200); if (buf == NULL) { http_request_deinit(req); return; } wpabuf_put_str(buf, "HTTP/1.1 404 Not Found\r\n" "Server: unspecified, UPnP/1.0, unspecified\r\n" "Connection: close\r\n"); http_put_date(buf); wpabuf_put_str(buf, "\r\n"); http_request_send_and_deinit(req, buf); }
/** * 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, *tmp; /* 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 (dl_list_empty(&sm->subscriptions)) { /* 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)); dl_list_for_each_safe(s, tmp, &sm->subscriptions, struct subscription, list) { if (event_add(s, buf)) { wpa_printf(MSG_INFO, "WPS UPnP: Dropping " "subscriber due to event backlog"); dl_list_del(&s->list); subscription_destroy(s); } } wpabuf_free(buf); }
static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf, struct gas_dialog_info *di, struct anqp_query_info *qi, int nai_realm, int nai_home_realm) { /* dynamically set nai_realm_list overrides static configuration */ if (nai_realm && hapd->conf->hs20_nai_realm_list) { wpabuf_put_le16(buf, ANQP_NAI_REALM); wpabuf_put_le16(buf, hapd->conf->hs20_nai_realm_list_len); wpabuf_put_data(buf, hapd->conf->hs20_nai_realm_list, hapd->conf->hs20_nai_realm_list_len); } else if (nai_realm && hapd->conf->nai_realm_data) { u8 *len; unsigned int i, j; len = gas_anqp_add_element(buf, ANQP_NAI_REALM); wpabuf_put_le16(buf, hapd->conf->nai_realm_count); for (i = 0; i < hapd->conf->nai_realm_count; i++) { u8 *realm_data_len, *realm_len; struct hostapd_nai_realm_data *realm; realm = &hapd->conf->nai_realm_data[i]; realm_data_len = wpabuf_put(buf, 2); wpabuf_put_u8(buf, realm->encoding); realm_len = wpabuf_put(buf, 1); for (j = 0; realm->realm[j]; j++) { if (j > 0) wpabuf_put_u8(buf, ';'); wpabuf_put_str(buf, realm->realm[j]); } *realm_len = (u8 *) wpabuf_put(buf, 0) - realm_len - 1; if (realm->num_auths) { wpabuf_put_u8(buf, 1); /* EAP method count */ wpabuf_put_u8(buf, 2 + (3 * realm->num_auths)); wpabuf_put_u8(buf, realm->eap_method); wpabuf_put_u8(buf, realm->num_auths); for (j = 0; j < realm->num_auths; j++) { wpabuf_put_u8(buf, realm->auth_id[j]); wpabuf_put_u8(buf, 1); wpabuf_put_u8(buf, realm->auth_val[j]); } } else { wpabuf_put_u8(buf, 0); /* EAP method count */ } gas_anqp_set_element_len(buf, realm_data_len); } gas_anqp_set_element_len(buf, len); } else if (nai_home_realm && hapd->conf->nai_realm_data) { process_hs_nai_home_realm(hapd, buf, qi); } else if (di) { if (nai_realm) wpabuf_put_data(buf, di->nai_realm, di->nai_realm_len); if (nai_home_realm) wpabuf_put_data(buf, di->nai_home_realm, di->nai_home_realm_len); } }
static void wps_er_soap_end(struct wpabuf *buf, const char *name, char *len_ptr, char *body_ptr) { char len_buf[10]; wpabuf_printf(buf, "</u:%s>\n", name); wpabuf_put_str(buf, soap_postfix); os_snprintf(len_buf, sizeof(len_buf), "%d", (int) ((char *) wpabuf_put(buf, 0) - body_ptr)); os_memcpy(len_ptr, len_buf, os_strlen(len_buf)); }
static void anqp_add_icon_binary_file(struct hostapd_data *hapd, struct wpabuf *buf, const u8 *name, size_t name_len) { struct hs20_icon *icon; size_t i; u8 *len; wpa_hexdump_ascii(MSG_DEBUG, "HS 2.0: Requested Icon Filename", name, name_len); for (i = 0; i < hapd->conf->hs20_icons_count; i++) { icon = &hapd->conf->hs20_icons[i]; if (name_len == os_strlen(icon->name) && os_memcmp(name, icon->name, name_len) == 0) break; } if (i < hapd->conf->hs20_icons_count) icon = &hapd->conf->hs20_icons[i]; else icon = NULL; len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); wpabuf_put_be24(buf, OUI_WFA); wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); wpabuf_put_u8(buf, HS20_STYPE_ICON_BINARY_FILE); wpabuf_put_u8(buf, 0); /* Reserved */ if (icon) { char *data; size_t data_len; data = os_readfile(icon->file, &data_len); if (data == NULL || data_len > 65535) { wpabuf_put_u8(buf, 2); /* Download Status: * Unspecified file error */ wpabuf_put_u8(buf, 0); wpabuf_put_le16(buf, 0); } else { wpabuf_put_u8(buf, 0); /* Download Status: Success */ wpabuf_put_u8(buf, os_strlen(icon->type)); wpabuf_put_str(buf, icon->type); wpabuf_put_le16(buf, data_len); wpabuf_put_data(buf, data, data_len); } os_free(data); } else { wpabuf_put_u8(buf, 1); /* Download Status: File not found */ wpabuf_put_u8(buf, 0); wpabuf_put_le16(buf, 0); } gas_anqp_set_element_len(buf, len); }
static void anqp_add_nai_realm_data(struct wpabuf *buf, struct hostapd_nai_realm_data *realm, unsigned int realm_idx) { u8 *realm_data_len; wpa_printf(MSG_DEBUG, "realm=%s, len=%d", realm->realm[realm_idx], (int) os_strlen(realm->realm[realm_idx])); realm_data_len = wpabuf_put(buf, 2); wpabuf_put_u8(buf, realm->encoding); wpabuf_put_u8(buf, os_strlen(realm->realm[realm_idx])); wpabuf_put_str(buf, realm->realm[realm_idx]); anqp_add_nai_realm_eap(buf, realm); gas_anqp_set_element_len(buf, realm_data_len); }
struct wpabuf * ndef_build_wifi_hc(int begin) { struct wpabuf *hc, *carrier; carrier = wpabuf_alloc(2 + os_strlen(wifi_handover_type)); if (carrier == NULL) return NULL; wpabuf_put_u8(carrier, 0x02); /* Carrier Type Format */ wpabuf_put_u8(carrier, os_strlen(wifi_handover_type)); wpabuf_put_str(carrier, wifi_handover_type); hc = ndef_build_record((begin ? FLAG_MESSAGE_BEGIN : 0) | FLAG_MESSAGE_END | FLAG_TNF_NFC_FORUM, "Hc", 2, "0", 1, carrier); wpabuf_free(carrier); return hc; }
int hs20_send_wnm_notification_t_c(struct hostapd_data *hapd, const u8 *addr, const char *url) { struct wpabuf *buf; int ret; size_t url_len; if (!url) { wpa_printf(MSG_INFO, "HS 2.0: No T&C Server URL available"); return -1; } url_len = os_strlen(url); if (5 + url_len > 255) { wpa_printf(MSG_INFO, "HS 2.0: Too long T&C Server URL for WNM-Notification: '%s'", url); return -1; } buf = wpabuf_alloc(4 + 7 + url_len); if (!buf) return -1; wpabuf_put_u8(buf, WLAN_ACTION_WNM); wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ); wpabuf_put_u8(buf, 1); /* Dialog token */ wpabuf_put_u8(buf, 1); /* Type - 1 reserved for WFA */ /* Terms and Conditions Acceptance subelement */ wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC); wpabuf_put_u8(buf, 4 + 1 + url_len); wpabuf_put_be24(buf, OUI_WFA); wpabuf_put_u8(buf, HS20_WNM_T_C_ACCEPTANCE); wpabuf_put_u8(buf, url_len); wpabuf_put_str(buf, url); ret = hostapd_drv_send_action(hapd, hapd->iface->freq, 0, addr, wpabuf_head(buf), wpabuf_len(buf)); wpabuf_free(buf); return ret; }
static struct wpabuf * build_fake_wsc_ack(void) { struct wpabuf *msg = wpabuf_alloc(100); if (msg == NULL) return NULL; wpabuf_put_u8(msg, UPNP_WPS_WLANEVENT_TYPE_EAP); wpabuf_put_str(msg, "00:00:00:00:00:00"); if (wps_build_version(msg) || wps_build_msg_type(msg, WPS_WSC_ACK)) { wpabuf_free(msg); return NULL; } /* Enrollee Nonce */ wpabuf_put_be16(msg, ATTR_ENROLLEE_NONCE); wpabuf_put_be16(msg, WPS_NONCE_LEN); wpabuf_put(msg, WPS_NONCE_LEN); /* Registrar Nonce */ wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE); wpabuf_put_be16(msg, WPS_NONCE_LEN); wpabuf_put(msg, WPS_NONCE_LEN); return msg; }
static void http_put_reply_code(struct wpabuf *buf, enum http_reply_code code) { wpabuf_put_str(buf, "HTTP/1.1 "); switch (code) { case HTTP_OK: wpabuf_put_str(buf, "200 OK\r\n"); break; case HTTP_BAD_REQUEST: wpabuf_put_str(buf, "400 Bad request\r\n"); break; case HTTP_PRECONDITION_FAILED: wpabuf_put_str(buf, "412 Precondition failed\r\n"); break; case HTTP_UNIMPLEMENTED: wpabuf_put_str(buf, "501 Unimplemented\r\n"); break; case HTTP_INTERNAL_SERVER_ERROR: default: wpabuf_put_str(buf, "500 Internal server error\r\n"); break; } }
static void web_connection_send_reply(struct http_request *req, enum http_reply_code ret, const char *action, int action_len, const struct wpabuf *reply, const char *replyname) { struct wpabuf *buf; char *replydata; char *put_length_here = NULL; char *body_start = NULL; if (reply) { size_t len; replydata = (char *) base64_encode(wpabuf_head(reply), wpabuf_len(reply), &len); } else replydata = NULL; /* Parameters of the response: * action(action_len) -- action we are responding to * replyname -- a name we need for the reply * replydata -- NULL or null-terminated string */ buf = wpabuf_alloc(1000 + (replydata ? os_strlen(replydata) : 0U) + (action_len > 0 ? action_len * 2 : 0)); if (buf == NULL) { wpa_printf(MSG_INFO, "WPS UPnP: Cannot allocate reply to " "POST"); os_free(replydata); http_request_deinit(req); return; } /* * Assuming we will be successful, put in the output header first. * Note: we do not keep connections alive (and httpread does * not support it)... therefore we must have Connection: close. */ if (ret == HTTP_OK) { wpabuf_put_str(buf, "HTTP/1.1 200 OK\r\n" "Content-Type: text/xml; " "charset=\"utf-8\"\r\n"); } else { wpabuf_printf(buf, "HTTP/1.1 %d Error\r\n", ret); } wpabuf_put_str(buf, http_connection_close); wpabuf_put_str(buf, "Content-Length: "); /* * We will paste the length in later, leaving some extra whitespace. * HTTP code is supposed to be tolerant of extra whitespace. */ put_length_here = wpabuf_put(buf, 0); wpabuf_put_str(buf, " \r\n"); http_put_date(buf); /* terminating empty line */ wpabuf_put_str(buf, "\r\n"); body_start = wpabuf_put(buf, 0); if (ret == HTTP_OK) { wpabuf_put_str(buf, soap_prefix); wpabuf_put_str(buf, "<u:"); wpabuf_put_data(buf, action, action_len); wpabuf_put_str(buf, "Response xmlns:u=\""); wpabuf_put_str(buf, urn_wfawlanconfig); wpabuf_put_str(buf, "\">\n"); if (replydata && replyname) { /* TODO: might possibly need to escape part of reply * data? ... * probably not, unlikely to have ampersand(&) or left * angle bracket (<) in it... */ wpabuf_printf(buf, "<%s>", replyname); wpabuf_put_str(buf, replydata); wpabuf_printf(buf, "</%s>\n", replyname); } wpabuf_put_str(buf, "</u:"); wpabuf_put_data(buf, action, action_len); wpabuf_put_str(buf, "Response>\n"); wpabuf_put_str(buf, soap_postfix); } else { /* Error case */ wpabuf_put_str(buf, soap_prefix); wpabuf_put_str(buf, soap_error_prefix); wpabuf_printf(buf, "<errorCode>%d</errorCode>\n", ret); wpabuf_put_str(buf, soap_error_postfix); wpabuf_put_str(buf, soap_postfix); } os_free(replydata); /* Now patch in the content length at the end */ if (body_start && put_length_here) { int body_length = (char *) wpabuf_put(buf, 0) - body_start; char len_buf[10]; os_snprintf(len_buf, sizeof(len_buf), "%d", body_length); os_memcpy(put_length_here, len_buf, os_strlen(len_buf)); } http_request_send_and_deinit(req, buf); }
/* Given that we have received a header w/ GET, act upon it * * Format of GET (case-insensitive): * * First line must be: * GET /<file> HTTP/1.1 * Since we don't do anything fancy we just ignore other lines. * * Our response (if no error) which includes only required lines is: * HTTP/1.1 200 OK * Connection: close * Content-Type: text/xml * Date: <rfc1123-date> * * Header lines must end with \r\n * Per RFC 2616, content-length: is not required but connection:close * would appear to be required (given that we will be closing it!). */ static void web_connection_parse_get(struct upnp_wps_device_sm *sm, struct http_request *hreq, char *filename) { struct wpabuf *buf; /* output buffer, allocated */ char *put_length_here; char *body_start; enum { GET_DEVICE_XML_FILE, GET_SCPD_XML_FILE } req; size_t extra_len = 0; int body_length; char len_buf[10]; struct upnp_wps_device_interface *iface; iface = dl_list_first(&sm->interfaces, struct upnp_wps_device_interface, list); if (iface == NULL) { http_request_deinit(hreq); return; } /* * It is not required that filenames be case insensitive but it is * allowed and cannot hurt here. */ if (os_strcasecmp(filename, UPNP_WPS_DEVICE_XML_FILE) == 0) { wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for device XML"); req = GET_DEVICE_XML_FILE; extra_len = 3000; if (iface->wps->friendly_name) extra_len += os_strlen(iface->wps->friendly_name); if (iface->wps->manufacturer_url) extra_len += os_strlen(iface->wps->manufacturer_url); if (iface->wps->model_description) extra_len += os_strlen(iface->wps->model_description); if (iface->wps->model_url) extra_len += os_strlen(iface->wps->model_url); if (iface->wps->upc) extra_len += os_strlen(iface->wps->upc); } else if (!os_strcasecmp(filename, UPNP_WPS_SCPD_XML_FILE)) { wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET for SCPD XML"); req = GET_SCPD_XML_FILE; extra_len = os_strlen(wps_scpd_xml); } else { /* File not found */ wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP GET file not found: %s", filename); buf = wpabuf_alloc(200); if (buf == NULL) { http_request_deinit(hreq); return; } wpabuf_put_str(buf, "HTTP/1.1 404 Not Found\r\n" "Connection: close\r\n"); http_put_date(buf); /* terminating empty line */ wpabuf_put_str(buf, "\r\n"); goto send_buf; } buf = wpabuf_alloc(1000 + extra_len); if (buf == NULL) { http_request_deinit(hreq); return; } wpabuf_put_str(buf, "HTTP/1.1 200 OK\r\n" "Content-Type: text/xml; charset=\"utf-8\"\r\n"); wpabuf_put_str(buf, "Server: Unspecified, UPnP/1.0, Unspecified\r\n"); wpabuf_put_str(buf, "Connection: close\r\n"); wpabuf_put_str(buf, "Content-Length: "); /* * We will paste the length in later, leaving some extra whitespace. * HTTP code is supposed to be tolerant of extra whitespace. */ put_length_here = wpabuf_put(buf, 0); wpabuf_put_str(buf, " \r\n"); http_put_date(buf); /* terminating empty line */ wpabuf_put_str(buf, "\r\n"); body_start = wpabuf_put(buf, 0); switch (req) { case GET_DEVICE_XML_FILE: format_wps_device_xml(iface, sm, buf); break; case GET_SCPD_XML_FILE: wpabuf_put_str(buf, wps_scpd_xml); break; } /* Now patch in the content length at the end */ body_length = (char *) wpabuf_put(buf, 0) - body_start; os_snprintf(len_buf, 10, "%d", body_length); os_memcpy(put_length_here, len_buf, os_strlen(len_buf)); send_buf: http_request_send_and_deinit(hreq, buf); }
static void http_put_date(struct wpabuf *buf) { wpabuf_put_str(buf, "Date: "); format_date(buf); wpabuf_put_str(buf, "\r\n"); }
/* event_send_tx_ready -- actually write event message * * Prequisite: subscription socket descriptor has become ready to * write (because connection to subscriber has been made). * * It is also possible that we are called because the connect has failed; * it is possible to test for this, or we can just go ahead and then * the write will fail. */ static void event_send_tx_ready(int sock, void *eloop_ctx, void *sock_ctx) { struct wps_event_ *e = sock_ctx; struct subscription *s = e->s; struct wpabuf *buf; char *b; assert(e == s->current_event); assert(e->sd == sock); buf = wpabuf_alloc(1000 + wpabuf_len(e->data)); if (buf == NULL) { event_retry(e, 0); goto bad; } wpabuf_printf(buf, "NOTIFY %s HTTP/1.1\r\n", e->addr->path); wpabuf_put_str(buf, "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n"); wpabuf_printf(buf, "HOST: %s\r\n", e->addr->domain_and_port); wpabuf_put_str(buf, "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n" "NT: upnp:event\r\n" "NTS: upnp:propchange\r\n"); wpabuf_put_str(buf, "SID: uuid:"); b = wpabuf_put(buf, 0); uuid_bin2str(s->uuid, b, 80); wpabuf_put(buf, os_strlen(b)); wpabuf_put_str(buf, "\r\n"); wpabuf_printf(buf, "SEQ: %u\r\n", e->subscriber_sequence); wpabuf_printf(buf, "CONTENT-LENGTH: %d\r\n", (int) wpabuf_len(e->data)); wpabuf_put_str(buf, "\r\n"); /* terminating empty line */ wpabuf_put_buf(buf, e->data); /* Since the message size is pretty small, we should be * able to get the operating system to buffer what we give it * and not have to come back again later to write more... */ #if 0 /* we could: Turn blocking back on? */ fcntl(e->sd, F_SETFL, 0); #endif wpa_printf(MSG_DEBUG, "WPS UPnP: Sending event to %s", e->addr->domain_and_port); if (send_wpabuf(e->sd, buf) < 0) { event_retry(e, 1); goto bad; } wpabuf_free(buf); buf = NULL; if (e->sd_registered) { e->sd_registered = 0; eloop_unregister_sock(e->sd, EVENT_TYPE_WRITE); } /* Set up to read the reply */ e->hread = httpread_create(e->sd, event_got_response_handler, e /* cookie */, 0 /* no data expected */, EVENT_TIMEOUT_SEC); if (e->hread == NULL) { wpa_printf(MSG_ERROR, "WPS UPnP: httpread_create failed"); event_retry(e, 0); goto bad; } return; bad: /* Schedule sending more if there is more to send */ if (s->event_queue) event_send_all_later(s->sm); wpabuf_free(buf); }
static void anqp_add_osu_provider(struct wpabuf *buf, struct hostapd_bss_config *bss, struct hs20_osu_provider *p) { u8 *len, *len2, *count; unsigned int i; len = wpabuf_put(buf, 2); /* OSU Provider Length to be filled */ /* OSU Friendly Name Duples */ len2 = wpabuf_put(buf, 2); for (i = 0; i < p->friendly_name_count; i++) { struct hostapd_lang_string *s = &p->friendly_name[i]; wpabuf_put_u8(buf, 3 + s->name_len); wpabuf_put_data(buf, s->lang, 3); wpabuf_put_data(buf, s->name, s->name_len); } WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2); /* OSU Server URI */ if (p->server_uri) { wpabuf_put_u8(buf, os_strlen(p->server_uri)); wpabuf_put_str(buf, p->server_uri); } else wpabuf_put_u8(buf, 0); /* OSU Method List */ count = wpabuf_put(buf, 1); for (i = 0; p->method_list[i] >= 0; i++) wpabuf_put_u8(buf, p->method_list[i]); *count = i; /* Icons Available */ len2 = wpabuf_put(buf, 2); for (i = 0; i < p->icons_count; i++) { size_t j; struct hs20_icon *icon = NULL; for (j = 0; j < bss->hs20_icons_count && !icon; j++) { if (os_strcmp(p->icons[i], bss->hs20_icons[j].name) == 0) icon = &bss->hs20_icons[j]; } if (!icon) continue; /* icon info not found */ wpabuf_put_le16(buf, icon->width); wpabuf_put_le16(buf, icon->height); wpabuf_put_data(buf, icon->language, 3); wpabuf_put_u8(buf, os_strlen(icon->type)); wpabuf_put_str(buf, icon->type); wpabuf_put_u8(buf, os_strlen(icon->name)); wpabuf_put_str(buf, icon->name); } WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2); /* OSU_NAI */ if (p->osu_nai) { wpabuf_put_u8(buf, os_strlen(p->osu_nai)); wpabuf_put_str(buf, p->osu_nai); } else wpabuf_put_u8(buf, 0); /* OSU Service Description Duples */ len2 = wpabuf_put(buf, 2); for (i = 0; i < p->service_desc_count; i++) { struct hostapd_lang_string *s = &p->service_desc[i]; wpabuf_put_u8(buf, 3 + s->name_len); wpabuf_put_data(buf, s->lang, 3); wpabuf_put_data(buf, s->name, s->name_len); } WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2); WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2); }
/** * 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, *tmp; /* 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"; struct os_time now; if (dl_list_empty(&sm->subscriptions)) { /* optimize */ return; } if (os_get_time(&now) == 0) { if (now.sec != sm->last_event_sec) { sm->last_event_sec = now.sec; sm->num_events_in_sec = 1; } else { sm->num_events_in_sec++; /* * In theory, this should apply to all WLANEvent * notifications, but EAP messages are of much higher * priority and Probe Request notifications should not * be allowed to drop EAP messages, so only throttle * Probe Request notifications. */ if (sm->num_events_in_sec > MAX_EVENTS_PER_SEC && sm->wlanevent_type == UPNP_WPS_WLANEVENT_TYPE_PROBE) { wpa_printf(MSG_DEBUG, "WPS UPnP: Throttle " "event notifications (%u seen " "during one second)", sm->num_events_in_sec); 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)); dl_list_for_each_safe(s, tmp, &sm->subscriptions, struct subscription, list) { event_add(s, buf, sm->wlanevent_type == UPNP_WPS_WLANEVENT_TYPE_PROBE); } wpabuf_free(buf); }
/* 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]; int ret; if (s->sm->wlanevent == NULL) { /* * There has been no events before the subscription. However, * UPnP device architecture specification requires all the * evented variables to be included, so generate a dummy event * for this particular case using a WSC_ACK and all-zeros * nonces. The ER (UPnP control point) will ignore this, but at * least it will learn that WLANEvent variable will be used in * event notifications in the future. */ struct wpabuf *msg; wpa_printf(MSG_DEBUG, "WPS UPnP: Use a fake WSC_ACK as the " "initial WLANEvent"); msg = build_fake_wsc_ack(); if (msg) { s->sm->wlanevent = (char *) base64_encode(wpabuf_head(msg), wpabuf_len(msg), NULL); wpabuf_free(msg); } } 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); ret = event_add(s, buf, 0); if (ret) { wpabuf_free(buf); return ret; } wpabuf_free(buf); return 0; }