struct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code, u16 comeback_delay, size_t size) { struct wpabuf *buf; buf = gas_build_initial_resp(dialog_token, status_code, comeback_delay, 4 + size); if (buf == NULL) return NULL; gas_add_adv_proto_anqp(buf, 0x7f, 0); wpabuf_put(buf, 2); /* Query Response Length to be filled */ return buf; }
static void gas_server_send_resp(struct gas_server *gas, struct gas_server_handler *handler, const u8 *da, int freq, u8 dialog_token, struct wpabuf *query_resp) { size_t max_len = (freq > 56160) ? 928 : 1400; size_t hdr_len = 24 + 2 + 5 + 3 + handler->adv_proto_id_len + 2; size_t resp_frag_len; struct wpabuf *resp; u16 comeback_delay; struct gas_server_response *response; if (!query_resp) return; response = os_zalloc(sizeof(*response)); if (!response) return; wpa_printf(MSG_DEBUG, "DPP: Allocated GAS response @%p", response); response->freq = freq; response->handler = handler; os_memcpy(response->dst, da, ETH_ALEN); response->dialog_token = dialog_token; if (hdr_len + wpabuf_len(query_resp) > max_len) { /* Need to use comeback to initiate fragmentation */ comeback_delay = 1; resp_frag_len = 0; } else { /* Full response fits into the initial response */ comeback_delay = 0; resp_frag_len = wpabuf_len(query_resp); } resp = gas_build_initial_resp(dialog_token, WLAN_STATUS_SUCCESS, comeback_delay, handler->adv_proto_id_len + resp_frag_len); if (!resp) { gas_server_free_response(response); return; } /* Advertisement Protocol element */ wpabuf_put_u8(resp, WLAN_EID_ADV_PROTO); wpabuf_put_u8(resp, 1 + handler->adv_proto_id_len); /* Length */ wpabuf_put_u8(resp, 0x7f); /* Advertisement Protocol ID */ wpabuf_put_data(resp, handler->adv_proto_id, handler->adv_proto_id_len); /* Query Response Length */ wpabuf_put_le16(resp, resp_frag_len); if (!comeback_delay) wpabuf_put_buf(resp, query_resp); if (comeback_delay) { wpa_printf(MSG_DEBUG, "GAS: Need to fragment query response"); } else { wpa_printf(MSG_DEBUG, "GAS: Full query response fits in the GAS Initial Response frame"); } response->offset = resp_frag_len; response->resp = query_resp; dl_list_add(&gas->responses, &response->list); gas->tx(gas->ctx, freq, da, resp, comeback_delay ? 2000 : 0); wpabuf_free(resp); eloop_register_timeout(GAS_QUERY_TIMEOUT, 0, gas_server_response_timeout, response, NULL); }
static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd, const u8 *sa, const u8 *data, size_t len) { const u8 *pos = data; const u8 *end = data + len; const u8 *next; u8 dialog_token; u16 slen; struct anqp_query_info qi; const u8 *adv_proto; if (len < 1 + 2) return; os_memset(&qi, 0, sizeof(qi)); dialog_token = *pos++; wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: GAS Initial Request from " MACSTR " (dialog token %u) ", MAC2STR(sa), dialog_token); if (*pos != WLAN_EID_ADV_PROTO) { wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Unexpected IE in GAS Initial Request: %u", *pos); return; } adv_proto = pos++; slen = *pos++; next = pos + slen; if (next > end || slen < 2) { wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Invalid IE in GAS Initial Request"); return; } pos++; /* skip QueryRespLenLimit and PAME-BI */ if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) { struct wpabuf *buf; wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Unsupported GAS advertisement protocol id %u", *pos); if (sa[0] & 0x01) return; /* Invalid source address - drop silently */ buf = gas_build_initial_resp( dialog_token, WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED, 0, 2 + slen + 2); if (buf == NULL) return; wpabuf_put_data(buf, adv_proto, 2 + slen); wpabuf_put_le16(buf, 0); /* Query Response Length */ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa, wpabuf_head(buf), wpabuf_len(buf)); wpabuf_free(buf); return; } pos = next; /* Query Request */ if (pos + 2 > end) return; slen = WPA_GET_LE16(pos); pos += 2; if (pos + slen > end) return; end = pos + slen; /* ANQP Query Request */ while (pos < end) { u16 info_id, elen; if (pos + 4 > end) return; info_id = WPA_GET_LE16(pos); pos += 2; elen = WPA_GET_LE16(pos); pos += 2; if (pos + elen > end) { wpa_printf(MSG_DEBUG, "ANQP: Invalid Query Request"); return; } switch (info_id) { case ANQP_QUERY_LIST: rx_anqp_query_list(hapd, pos, pos + elen, &qi); break; #ifdef CONFIG_HS20 case ANQP_VENDOR_SPECIFIC: rx_anqp_vendor_specific(hapd, pos, pos + elen, &qi); break; #endif /* CONFIG_HS20 */ default: wpa_printf(MSG_DEBUG, "ANQP: Unsupported Query " "Request element %u", info_id); break; } pos += elen; } gas_serv_req_local_processing(hapd, sa, dialog_token, &qi); }