static struct wpabuf * p2p_build_sd_response(u8 dialog_token, u16 status_code, u16 comeback_delay, u16 update_indic, const struct wpabuf *tlvs) { struct wpabuf *buf; u8 *len_pos; buf = gas_anqp_build_initial_resp(dialog_token, status_code, comeback_delay, 100 + (tlvs ? wpabuf_len(tlvs) : 0)); if (buf == NULL) return NULL; if (tlvs) { /* ANQP Query Response Frame */ len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE); /* Service Update Indicator */ wpabuf_put_le16(buf, update_indic); wpabuf_put_buf(buf, tlvs); gas_anqp_set_element_len(buf, len_pos); } gas_anqp_set_len(buf); return buf; }
struct wpabuf * mbo_build_anqp_buf(struct wpa_supplicant *wpa_s, struct wpa_bss *bss) { struct wpabuf *anqp_buf; u8 *len_pos; if (!wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE)) { wpa_printf(MSG_INFO, "MBO: " MACSTR " does not support MBO - cannot request MBO ANQP elements from it", MAC2STR(bss->bssid)); return NULL; } anqp_buf = wpabuf_alloc(10); if (!anqp_buf) return NULL; len_pos = gas_anqp_add_element(anqp_buf, ANQP_VENDOR_SPECIFIC); wpabuf_put_be24(anqp_buf, OUI_WFA); wpabuf_put_u8(anqp_buf, MBO_ANQP_OUI_TYPE); wpabuf_put_u8(anqp_buf, MBO_ANQP_SUBTYPE_CELL_CONN_PREF); gas_anqp_set_element_len(anqp_buf, len_pos); return anqp_buf; }
static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf, struct gas_dialog_info *di) { if (hapd->conf->hs20_venue_name) { wpabuf_put_le16(buf, ANQP_VENUE_NAME); wpabuf_put_le16(buf, hapd->conf->hs20_venue_name_len); wpabuf_put_data(buf, hapd->conf->hs20_venue_name, hapd->conf->hs20_venue_name_len); } else if (hapd->conf->venue_name) { u8 *len; unsigned int i; len = gas_anqp_add_element(buf, ANQP_VENUE_NAME); wpabuf_put_u8(buf, hapd->conf->venue_group); wpabuf_put_u8(buf, hapd->conf->venue_type); for (i = 0; i < hapd->conf->venue_name_count; i++) { struct hostapd_venue_name *vn; vn = &hapd->conf->venue_name[i]; wpabuf_put_u8(buf, 3 + vn->name_len); wpabuf_put_data(buf, vn->lang, 3); wpabuf_put_data(buf, vn->name, vn->name_len); } gas_anqp_set_element_len(buf, len); } else if (di) { wpabuf_put_data(buf, di->venue_name, di->venue_name_len); } }
static void anqp_add_hs_capab_list(struct hostapd_data *hapd, struct wpabuf *buf) { u8 *len; 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_CAPABILITY_LIST); wpabuf_put_u8(buf, 0); /* Reserved */ wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST); if (hapd->conf->hs20_operator_friendly_name || (hapd->anqp_type_mask & ANQP_REQ_OPERATOR_FRIENDLY_NAME)) wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME); if (hapd->conf->hs20_wan_metrics || (hapd->anqp_type_mask & ANQP_REQ_WAN_METRICS)) wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS); if (hapd->conf->hs20_connection_capability || (hapd->anqp_type_mask & ANQP_REQ_CONNECTION_CAPABILITY)) wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY); if (hapd->anqp_type_mask & ANQP_REQ_NAI_HOME_REALM) wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY); if (hapd->conf->hs20_operating_class || (hapd->anqp_type_mask & ANQP_REQ_OPERATING_CLASS)) wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS); gas_anqp_set_element_len(buf, len); }
static void anqp_add_capab_list(struct hostapd_data *hapd, struct wpabuf *buf) { u8 *len; len = gas_anqp_add_element(buf, ANQP_CAPABILITY_LIST); wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST); if (hapd->conf->venue_name || hapd->conf->hs20_venue_name || (hapd->anqp_type_mask & ANQP_REQ_VENUE_NAME)) wpabuf_put_le16(buf, ANQP_VENUE_NAME); if (hapd->conf->hs20_network_auth_type || (hapd->anqp_type_mask & ANQP_REQ_NETWORK_AUTH_TYPE)) wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE); if (hapd->conf->roaming_consortium || (hapd->anqp_type_mask & ANQP_REQ_ROAMING_CONSORTIUM)) wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM); if (hapd->conf->hs20_ipaddr_type_configured || (hapd->anqp_type_mask & ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY)) wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY); if (hapd->conf->hs20_nai_realm_list || hapd->conf->nai_realm_data || (hapd->anqp_type_mask & ANQP_REQ_NAI_REALM)) wpabuf_put_le16(buf, ANQP_NAI_REALM); if (hapd->conf->hs20_3gpp_cellular_network || (hapd->anqp_type_mask & ANQP_REQ_3GPP_CELLULAR_NETWORK)) wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK); if (hapd->conf->hs20_domain_name_list_value || (hapd->anqp_type_mask & ANQP_REQ_DOMAIN_NAME)) wpabuf_put_le16(buf, ANQP_DOMAIN_NAME); anqp_add_hs_capab_list(hapd, buf); gas_anqp_set_element_len(buf, len); }
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); } }
void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len, struct wpabuf *buf) { u8 *len_pos; if (buf == NULL) return; len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); wpabuf_put_be24(buf, OUI_WFA); wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); if (stypes == BIT(HS20_STYPE_NAI_HOME_REALM_QUERY)) { wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY); wpabuf_put_u8(buf, 0); /* Reserved */ if (payload) wpabuf_put_data(buf, payload, payload_len); } else if (stypes == BIT(HS20_STYPE_ICON_REQUEST)) { wpabuf_put_u8(buf, HS20_STYPE_ICON_REQUEST); wpabuf_put_u8(buf, 0); /* Reserved */ if (payload) wpabuf_put_data(buf, payload, payload_len); } else { u8 i; wpabuf_put_u8(buf, HS20_STYPE_QUERY_LIST); wpabuf_put_u8(buf, 0); /* Reserved */ for (i = 0; i < 32; i++) { if (stypes & BIT(i)) wpabuf_put_u8(buf, i); } } gas_anqp_set_element_len(buf, len_pos); gas_anqp_set_len(buf); }
static void anqp_add_osu_providers_list(struct hostapd_data *hapd, struct wpabuf *buf) { if (hapd->conf->hs20_osu_providers_count) { size_t i; u8 *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_OSU_PROVIDERS_LIST); wpabuf_put_u8(buf, 0); /* Reserved */ /* OSU SSID */ wpabuf_put_u8(buf, hapd->conf->osu_ssid_len); wpabuf_put_data(buf, hapd->conf->osu_ssid, hapd->conf->osu_ssid_len); /* Number of OSU Providers */ wpabuf_put_u8(buf, hapd->conf->hs20_osu_providers_count); for (i = 0; i < hapd->conf->hs20_osu_providers_count; i++) { anqp_add_osu_provider( buf, hapd->conf, &hapd->conf->hs20_osu_providers[i]); } gas_anqp_set_element_len(buf, len); } }
static void anqp_add_hs_capab_list(struct hostapd_data *hapd, struct wpabuf *buf) { u8 *len; 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_CAPABILITY_LIST); wpabuf_put_u8(buf, 0); /* Reserved */ wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST); if (hapd->conf->hs20_oper_friendly_name) wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME); if (hapd->conf->hs20_wan_metrics) wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS); if (hapd->conf->hs20_connection_capability) wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY); if (hapd->conf->nai_realm_data) wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY); if (hapd->conf->hs20_operating_class) wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS); if (hapd->conf->hs20_osu_providers_count) wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_LIST); if (hapd->conf->hs20_icons_count) wpabuf_put_u8(buf, HS20_STYPE_ICON_REQUEST); gas_anqp_set_element_len(buf, len); }
static void anqp_add_capab_list(struct hostapd_data *hapd, struct wpabuf *buf) { u8 *len; len = gas_anqp_add_element(buf, ANQP_CAPABILITY_LIST); wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST); if (hapd->conf->venue_name) wpabuf_put_le16(buf, ANQP_VENUE_NAME); if (hapd->conf->network_auth_type) wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE); if (hapd->conf->roaming_consortium) wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM); if (hapd->conf->ipaddr_type_configured) wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY); if (hapd->conf->nai_realm_data) wpabuf_put_le16(buf, ANQP_NAI_REALM); if (hapd->conf->anqp_3gpp_cell_net) wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK); if (hapd->conf->domain_name) wpabuf_put_le16(buf, ANQP_DOMAIN_NAME); #ifdef CONFIG_HS20 anqp_add_hs_capab_list(hapd, buf); #endif /* CONFIG_HS20 */ gas_anqp_set_element_len(buf, len); }
static void anqp_add_capab_list(struct hostapd_data *hapd, struct wpabuf *buf) { u8 *len; u16 id; if (anqp_add_override(hapd, buf, ANQP_CAPABILITY_LIST)) return; len = gas_anqp_add_element(buf, ANQP_CAPABILITY_LIST); wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST); if (hapd->conf->venue_name || get_anqp_elem(hapd, ANQP_VENUE_NAME)) wpabuf_put_le16(buf, ANQP_VENUE_NAME); if (get_anqp_elem(hapd, ANQP_EMERGENCY_CALL_NUMBER)) wpabuf_put_le16(buf, ANQP_EMERGENCY_CALL_NUMBER); if (hapd->conf->network_auth_type || get_anqp_elem(hapd, ANQP_NETWORK_AUTH_TYPE)) wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE); if (hapd->conf->roaming_consortium || get_anqp_elem(hapd, ANQP_ROAMING_CONSORTIUM)) wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM); if (hapd->conf->ipaddr_type_configured || get_anqp_elem(hapd, ANQP_IP_ADDR_TYPE_AVAILABILITY)) wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY); if (hapd->conf->nai_realm_data || get_anqp_elem(hapd, ANQP_NAI_REALM)) wpabuf_put_le16(buf, ANQP_NAI_REALM); if (hapd->conf->anqp_3gpp_cell_net || get_anqp_elem(hapd, ANQP_3GPP_CELLULAR_NETWORK)) wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK); if (get_anqp_elem(hapd, ANQP_AP_GEOSPATIAL_LOCATION)) wpabuf_put_le16(buf, ANQP_AP_GEOSPATIAL_LOCATION); if (get_anqp_elem(hapd, ANQP_AP_CIVIC_LOCATION)) wpabuf_put_le16(buf, ANQP_AP_CIVIC_LOCATION); if (get_anqp_elem(hapd, ANQP_AP_LOCATION_PUBLIC_URI)) wpabuf_put_le16(buf, ANQP_AP_LOCATION_PUBLIC_URI); if (hapd->conf->domain_name || get_anqp_elem(hapd, ANQP_DOMAIN_NAME)) wpabuf_put_le16(buf, ANQP_DOMAIN_NAME); if (get_anqp_elem(hapd, ANQP_EMERGENCY_ALERT_URI)) wpabuf_put_le16(buf, ANQP_EMERGENCY_ALERT_URI); if (get_anqp_elem(hapd, ANQP_EMERGENCY_NAI)) wpabuf_put_le16(buf, ANQP_EMERGENCY_NAI); if (get_anqp_elem(hapd, ANQP_NEIGHBOR_REPORT)) wpabuf_put_le16(buf, ANQP_NEIGHBOR_REPORT); for (id = 273; id < 277; id++) { if (get_anqp_elem(hapd, id)) wpabuf_put_le16(buf, id); } if (get_anqp_elem(hapd, ANQP_VENUE_URL)) wpabuf_put_le16(buf, ANQP_VENUE_URL); if (get_anqp_elem(hapd, ANQP_ADVICE_OF_CHARGE)) wpabuf_put_le16(buf, ANQP_ADVICE_OF_CHARGE); if (get_anqp_elem(hapd, ANQP_LOCAL_CONTENT)) wpabuf_put_le16(buf, ANQP_LOCAL_CONTENT); #ifdef CONFIG_HS20 anqp_add_hs_capab_list(hapd, buf); #endif /* CONFIG_HS20 */ gas_anqp_set_element_len(buf, len); }
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 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_wan_metrics(struct hostapd_data *hapd, struct wpabuf *buf) { if (hapd->conf->hs20_wan_metrics) { u8 *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_WAN_METRICS); wpabuf_put_u8(buf, 0); /* Reserved */ wpabuf_put_data(buf, hapd->conf->hs20_wan_metrics, 13); gas_anqp_set_element_len(buf, len); } }
static void anqp_add_operating_class(struct hostapd_data *hapd, struct wpabuf *buf) { if (hapd->conf->hs20_operating_class) { u8 *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_OPERATING_CLASS); wpabuf_put_u8(buf, 0); /* Reserved */ wpabuf_put_data(buf, hapd->conf->hs20_operating_class, hapd->conf->hs20_operating_class_len); gas_anqp_set_element_len(buf, len); } }
static void anqp_add_connection_capability(struct hostapd_data *hapd, struct wpabuf *buf) { if (hapd->conf->hs20_connection_capability) { u8 *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_CONNECTION_CAPABILITY); wpabuf_put_u8(buf, 0); /* Reserved */ wpabuf_put_data(buf, hapd->conf->hs20_connection_capability, hapd->conf->hs20_connection_capability_len); gas_anqp_set_element_len(buf, len); } }
static void anqp_add_roaming_consortium(struct hostapd_data *hapd, struct wpabuf *buf) { unsigned int i; u8 *len; len = gas_anqp_add_element(buf, ANQP_ROAMING_CONSORTIUM); for (i = 0; i < hapd->conf->roaming_consortium_count; i++) { struct hostapd_roaming_consortium *rc; rc = &hapd->conf->roaming_consortium[i]; wpabuf_put_u8(buf, rc->len); wpabuf_put_data(buf, rc->oi, rc->len); } gas_anqp_set_element_len(buf, len); }
static void anqp_add_operator_friendly_name(struct hostapd_data *hapd, struct wpabuf *buf, struct gas_dialog_info *di) { if (hapd->conf->hs20_operator_friendly_name) { u8 *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_OPERATOR_FRIENDLY_NAME); wpabuf_put_u8(buf, 0); /* Reserved */ wpabuf_put_data(buf, hapd->conf->hs20_operator_friendly_name, hapd->conf->hs20_operator_friendly_name_len); gas_anqp_set_element_len(buf, len); } else if (di) { wpabuf_put_data(buf, di->oper_friendly_name, di->oper_friendly_name_len); } }
static struct wpabuf * p2p_build_sd_query(u16 update_indic, struct wpabuf *tlvs) { struct wpabuf *buf; u8 *len_pos; buf = gas_anqp_build_initial_req(0, 100 + wpabuf_len(tlvs)); if (buf == NULL) return NULL; /* ANQP Query Request Frame */ len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); wpabuf_put_be32(buf, P2P_IE_VENDOR_TYPE); wpabuf_put_le16(buf, update_indic); /* Service Update Indicator */ wpabuf_put_buf(buf, tlvs); gas_anqp_set_element_len(buf, len_pos); gas_anqp_set_len(buf); return buf; }
static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf) { if (anqp_add_override(hapd, buf, ANQP_VENUE_NAME)) return; if (hapd->conf->venue_name) { u8 *len; unsigned int i; len = gas_anqp_add_element(buf, ANQP_VENUE_NAME); wpabuf_put_u8(buf, hapd->conf->venue_group); wpabuf_put_u8(buf, hapd->conf->venue_type); for (i = 0; i < hapd->conf->venue_name_count; i++) { struct hostapd_lang_string *vn; vn = &hapd->conf->venue_name[i]; wpabuf_put_u8(buf, 3 + vn->name_len); wpabuf_put_data(buf, vn->lang, 3); wpabuf_put_data(buf, vn->name, vn->name_len); } gas_anqp_set_element_len(buf, len); } }
static void anqp_add_operator_friendly_name(struct hostapd_data *hapd, struct wpabuf *buf) { if (hapd->conf->hs20_oper_friendly_name) { u8 *len; unsigned int i; 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_OPERATOR_FRIENDLY_NAME); wpabuf_put_u8(buf, 0); /* Reserved */ for (i = 0; i < hapd->conf->hs20_oper_friendly_name_count; i++) { struct hostapd_lang_string *vn; vn = &hapd->conf->hs20_oper_friendly_name[i]; wpabuf_put_u8(buf, 3 + vn->name_len); wpabuf_put_data(buf, vn->lang, 3); wpabuf_put_data(buf, vn->name, vn->name_len); } gas_anqp_set_element_len(buf, len); } }
static struct wpabuf * anqp_build_req(u16 info_ids[], size_t num_ids, struct wpabuf *extra) { struct wpabuf *buf; size_t i; u8 *len_pos; buf = gas_anqp_build_initial_req(0, 4 + num_ids * 2 + (extra ? wpabuf_len(extra) : 0)); if (buf == NULL) return NULL; len_pos = gas_anqp_add_element(buf, ANQP_QUERY_LIST); for (i = 0; i < num_ids; i++) wpabuf_put_le16(buf, info_ids[i]); gas_anqp_set_element_len(buf, len_pos); if (extra) wpabuf_put_buf(buf, extra); gas_anqp_set_len(buf); return buf; }
static int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd, struct wpabuf *buf, const u8 *home_realm, size_t home_realm_len) { unsigned int i, j, k; u8 num_realms, num_matching = 0, encoding, realm_len, *realm_list_len; struct hostapd_nai_realm_data *realm; const u8 *pos, *realm_name, *end; struct { unsigned int realm_data_idx; unsigned int realm_idx; } matches[10]; pos = home_realm; end = pos + home_realm_len; if (pos + 1 > end) { wpa_hexdump(MSG_DEBUG, "Too short NAI Home Realm Query", home_realm, home_realm_len); return -1; } num_realms = *pos++; for (i = 0; i < num_realms && num_matching < 10; i++) { if (pos + 2 > end) { wpa_hexdump(MSG_DEBUG, "Truncated NAI Home Realm Query", home_realm, home_realm_len); return -1; } encoding = *pos++; realm_len = *pos++; if (pos + realm_len > end) { wpa_hexdump(MSG_DEBUG, "Truncated NAI Home Realm Query", home_realm, home_realm_len); return -1; } realm_name = pos; for (j = 0; j < hapd->conf->nai_realm_count && num_matching < 10; j++) { const u8 *rpos, *rend; realm = &hapd->conf->nai_realm_data[j]; if (encoding != realm->encoding) continue; rpos = realm_name; while (rpos < realm_name + realm_len && num_matching < 10) { for (rend = rpos; rend < realm_name + realm_len; rend++) { if (*rend == ';') break; } for (k = 0; k < MAX_NAI_REALMS && realm->realm[k] && num_matching < 10; k++) { if ((int) os_strlen(realm->realm[k]) != rend - rpos || os_strncmp((char *) rpos, realm->realm[k], rend - rpos) != 0) continue; matches[num_matching].realm_data_idx = j; matches[num_matching].realm_idx = k; num_matching++; } rpos = rend + 1; } } pos += realm_len; } realm_list_len = gas_anqp_add_element(buf, ANQP_NAI_REALM); wpabuf_put_le16(buf, num_matching); /* * There are two ways to format. 1. each realm in a NAI Realm Data unit * 2. all realms that share the same EAP methods in a NAI Realm Data * unit. The first format is likely to be bigger in size than the * second, but may be easier to parse and process by the receiver. */ for (i = 0; i < num_matching; i++) { wpa_printf(MSG_DEBUG, "realm_idx %d, realm_data_idx %d", matches[i].realm_data_idx, matches[i].realm_idx); realm = &hapd->conf->nai_realm_data[matches[i].realm_data_idx]; anqp_add_nai_realm_data(buf, realm, matches[i].realm_idx); } gas_anqp_set_element_len(buf, realm_list_len); return 0; }
static int process_hs_nai_home_realm(struct hostapd_data *hapd, struct wpabuf *buf, struct anqp_query_info *qi) { unsigned int i, j, k; u8 num_realms, num_matching = 0, encoding, realm_len, *realm_list_len; struct hostapd_nai_realm_data *realm; const u8 *pos, *realm_name, *end; struct { unsigned int realm_data_idx; unsigned int realm_idx; } matches[10]; pos = qi->param; end = pos + qi->param_arg; num_realms = *pos++; for (i = 0; i < num_realms && num_matching < 10; i++) { encoding = *pos++; realm_len = *pos++; realm_name = pos; for (j = 0; j < hapd->conf->nai_realm_count && num_matching < 10; j++) { realm = &hapd->conf->nai_realm_data[j]; if (encoding != realm->encoding) continue; for (k = 0; realm->realm[k] && num_matching < 10; k++) { if (os_strncmp((char *) realm_name, realm->realm[k], realm_len) != 0) continue; matches[num_matching].realm_data_idx = j; matches[num_matching].realm_idx = k; num_matching++; } } pos += realm_len; if (pos > end) { wpa_hexdump(MSG_ERROR, "NAI Home Realm processing " "error", qi->param, qi->param_arg); return -1; } } realm_list_len = gas_anqp_add_element(buf, ANQP_NAI_REALM); wpabuf_put_le16(buf, num_matching); /* * There are two ways to format. 1. each realm in a NAI Realm Data unit * 2. all realms that share the same EAP methods in a NAI Realm Data * unit. The first format is likely to be bigger in size than the * second, but may be easier to parse and process by the receiver. */ for (i = 0; i < num_matching; i++) { wpa_printf(MSG_DEBUG, "realm_idx %d, realm_data_idx %d", matches[i].realm_data_idx, matches[i].realm_idx); realm = &hapd->conf->nai_realm_data[matches[i].realm_data_idx]; anqp_add_nai_realm_data(buf, realm, matches[i].realm_idx); } gas_anqp_set_element_len(buf, realm_list_len); return 0; }