LCOV - code coverage report
Current view: top level - src/ap - gas_serv.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1475438200 Lines: 766 838 91.4 %
Date: 2016-10-02 Functions: 42 42 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Generic advertisement service (GAS) server
       3             :  * Copyright (c) 2011-2014, Qualcomm Atheros, Inc.
       4             :  *
       5             :  * This software may be distributed under the terms of the BSD license.
       6             :  * See README for more details.
       7             :  */
       8             : 
       9             : #include "includes.h"
      10             : 
      11             : #include "common.h"
      12             : #include "common/ieee802_11_defs.h"
      13             : #include "common/gas.h"
      14             : #include "utils/eloop.h"
      15             : #include "hostapd.h"
      16             : #include "ap_config.h"
      17             : #include "ap_drv_ops.h"
      18             : #include "sta_info.h"
      19             : #include "gas_serv.h"
      20             : 
      21             : 
      22           3 : static void convert_to_protected_dual(struct wpabuf *msg)
      23             : {
      24           3 :         u8 *categ = wpabuf_mhead_u8(msg);
      25           3 :         *categ = WLAN_ACTION_PROTECTED_DUAL;
      26           3 : }
      27             : 
      28             : 
      29             : static struct gas_dialog_info *
      30          39 : gas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token)
      31             : {
      32             :         struct sta_info *sta;
      33          39 :         struct gas_dialog_info *dia = NULL;
      34             :         int i, j;
      35             : 
      36          39 :         sta = ap_get_sta(hapd, addr);
      37          39 :         if (!sta) {
      38             :                 /*
      39             :                  * We need a STA entry to be able to maintain state for
      40             :                  * the GAS query.
      41             :                  */
      42          19 :                 wpa_printf(MSG_DEBUG, "ANQP: Add a temporary STA entry for "
      43             :                            "GAS query");
      44          19 :                 sta = ap_sta_add(hapd, addr);
      45          19 :                 if (!sta) {
      46           0 :                         wpa_printf(MSG_DEBUG, "Failed to add STA " MACSTR
      47           0 :                                    " for GAS query", MAC2STR(addr));
      48           0 :                         return NULL;
      49             :                 }
      50          19 :                 sta->flags |= WLAN_STA_GAS;
      51             :                 /*
      52             :                  * The default inactivity is 300 seconds. We don't need
      53             :                  * it to be that long.
      54             :                  */
      55          19 :                 ap_sta_session_timeout(hapd, sta, 5);
      56             :         } else {
      57          20 :                 ap_sta_replenish_timeout(hapd, sta, 5);
      58             :         }
      59             : 
      60          39 :         if (sta->gas_dialog == NULL) {
      61          28 :                 sta->gas_dialog = os_calloc(GAS_DIALOG_MAX,
      62             :                                             sizeof(struct gas_dialog_info));
      63          28 :                 if (sta->gas_dialog == NULL)
      64           0 :                         return NULL;
      65             :         }
      66             : 
      67          94 :         for (i = sta->gas_dialog_next, j = 0; j < GAS_DIALOG_MAX; i++, j++) {
      68          46 :                 if (i == GAS_DIALOG_MAX)
      69           0 :                         i = 0;
      70          46 :                 if (sta->gas_dialog[i].valid)
      71           8 :                         continue;
      72          38 :                 dia = &sta->gas_dialog[i];
      73          38 :                 dia->valid = 1;
      74          38 :                 dia->dialog_token = dialog_token;
      75          38 :                 sta->gas_dialog_next = (++i == GAS_DIALOG_MAX) ? 0 : i;
      76          38 :                 return dia;
      77             :         }
      78             : 
      79           7 :         wpa_msg(hapd->msg_ctx, MSG_ERROR, "ANQP: Could not create dialog for "
      80             :                 MACSTR " dialog_token %u. Consider increasing "
      81           6 :                 "GAS_DIALOG_MAX.", MAC2STR(addr), dialog_token);
      82             : 
      83           1 :         return NULL;
      84             : }
      85             : 
      86             : 
      87             : struct gas_dialog_info *
      88         155 : gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr,
      89             :                      u8 dialog_token)
      90             : {
      91             :         struct sta_info *sta;
      92             :         int i;
      93             : 
      94         155 :         sta = ap_get_sta(hapd, addr);
      95         155 :         if (!sta) {
      96           6 :                 wpa_printf(MSG_DEBUG, "ANQP: could not find STA " MACSTR,
      97           6 :                            MAC2STR(addr));
      98           1 :                 return NULL;
      99             :         }
     100         468 :         for (i = 0; sta->gas_dialog && i < GAS_DIALOG_MAX; i++) {
     101         388 :                 if (sta->gas_dialog[i].dialog_token != dialog_token ||
     102         154 :                     !sta->gas_dialog[i].valid)
     103          80 :                         continue;
     104         154 :                 ap_sta_replenish_timeout(hapd, sta, 5);
     105         154 :                 return &sta->gas_dialog[i];
     106             :         }
     107           0 :         wpa_printf(MSG_DEBUG, "ANQP: Could not find dialog for "
     108           0 :                    MACSTR " dialog_token %u", MAC2STR(addr), dialog_token);
     109           0 :         return NULL;
     110             : }
     111             : 
     112             : 
     113          51 : void gas_serv_dialog_clear(struct gas_dialog_info *dia)
     114             : {
     115          51 :         wpabuf_free(dia->sd_resp);
     116          51 :         os_memset(dia, 0, sizeof(*dia));
     117          51 : }
     118             : 
     119             : 
     120          26 : static void gas_serv_free_dialogs(struct hostapd_data *hapd,
     121             :                                   const u8 *sta_addr)
     122             : {
     123             :         struct sta_info *sta;
     124             :         int i;
     125             : 
     126          26 :         sta = ap_get_sta(hapd, sta_addr);
     127          26 :         if (sta == NULL || sta->gas_dialog == NULL)
     128           0 :                 return;
     129             : 
     130         226 :         for (i = 0; i < GAS_DIALOG_MAX; i++) {
     131         201 :                 if (sta->gas_dialog[i].valid)
     132           1 :                         return;
     133             :         }
     134             : 
     135          25 :         os_free(sta->gas_dialog);
     136          25 :         sta->gas_dialog = NULL;
     137             : }
     138             : 
     139             : 
     140             : #ifdef CONFIG_HS20
     141         582 : static void anqp_add_hs_capab_list(struct hostapd_data *hapd,
     142             :                                    struct wpabuf *buf)
     143             : {
     144             :         u8 *len;
     145             : 
     146         582 :         len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
     147         582 :         wpabuf_put_be24(buf, OUI_WFA);
     148         582 :         wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
     149         582 :         wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST);
     150         582 :         wpabuf_put_u8(buf, 0); /* Reserved */
     151         582 :         wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST);
     152         582 :         if (hapd->conf->hs20_oper_friendly_name)
     153          32 :                 wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
     154         582 :         if (hapd->conf->hs20_wan_metrics)
     155         578 :                 wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS);
     156         582 :         if (hapd->conf->hs20_connection_capability)
     157         578 :                 wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY);
     158         582 :         if (hapd->conf->nai_realm_data)
     159         575 :                 wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY);
     160         582 :         if (hapd->conf->hs20_operating_class)
     161         580 :                 wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
     162         582 :         if (hapd->conf->hs20_osu_providers_count)
     163          12 :                 wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_LIST);
     164         582 :         if (hapd->conf->hs20_icons_count)
     165          12 :                 wpabuf_put_u8(buf, HS20_STYPE_ICON_REQUEST);
     166         582 :         gas_anqp_set_element_len(buf, len);
     167         582 : }
     168             : #endif /* CONFIG_HS20 */
     169             : 
     170             : 
     171        5881 : static struct anqp_element * get_anqp_elem(struct hostapd_data *hapd,
     172             :                                            u16 infoid)
     173             : {
     174             :         struct anqp_element *elem;
     175             : 
     176        6966 :         dl_list_for_each(elem, &hapd->conf->anqp_elem, struct anqp_element,
     177             :                          list) {
     178        1160 :                 if (elem->infoid == infoid)
     179          75 :                         return elem;
     180             :         }
     181             : 
     182        5806 :         return NULL;
     183             : }
     184             : 
     185             : 
     186          38 : static void anqp_add_elem(struct hostapd_data *hapd, struct wpabuf *buf,
     187             :                           u16 infoid)
     188             : {
     189             :         struct anqp_element *elem;
     190             : 
     191          38 :         elem = get_anqp_elem(hapd, infoid);
     192          38 :         if (!elem)
     193           4 :                 return;
     194          34 :         if (wpabuf_tailroom(buf) < 2 + 2 + wpabuf_len(elem->payload)) {
     195           0 :                 wpa_printf(MSG_DEBUG, "ANQP: No room for InfoID %u payload",
     196             :                            infoid);
     197           0 :                 return;
     198             :         }
     199             : 
     200          34 :         wpabuf_put_le16(buf, infoid);
     201          34 :         wpabuf_put_le16(buf, wpabuf_len(elem->payload));
     202          34 :         wpabuf_put_buf(buf, elem->payload);
     203             : }
     204             : 
     205             : 
     206        1038 : static int anqp_add_override(struct hostapd_data *hapd, struct wpabuf *buf,
     207             :                              u16 infoid)
     208             : {
     209        1038 :         if (get_anqp_elem(hapd, infoid)) {
     210          28 :                 anqp_add_elem(hapd, buf, infoid);
     211          28 :                 return 1;
     212             :         }
     213             : 
     214        1010 :         return 0;
     215             : }
     216             : 
     217             : 
     218         299 : static void anqp_add_capab_list(struct hostapd_data *hapd,
     219             :                                 struct wpabuf *buf)
     220             : {
     221             :         u8 *len;
     222             :         u16 id;
     223             : 
     224         299 :         if (anqp_add_override(hapd, buf, ANQP_CAPABILITY_LIST))
     225         299 :                 return;
     226             : 
     227         299 :         len = gas_anqp_add_element(buf, ANQP_CAPABILITY_LIST);
     228         299 :         wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST);
     229         299 :         if (hapd->conf->venue_name || get_anqp_elem(hapd, ANQP_VENUE_NAME))
     230         297 :                 wpabuf_put_le16(buf, ANQP_VENUE_NAME);
     231         299 :         if (get_anqp_elem(hapd, ANQP_EMERGENCY_CALL_NUMBER))
     232           0 :                 wpabuf_put_le16(buf, ANQP_EMERGENCY_CALL_NUMBER);
     233         575 :         if (hapd->conf->network_auth_type ||
     234         276 :             get_anqp_elem(hapd, ANQP_NETWORK_AUTH_TYPE))
     235          23 :                 wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
     236         305 :         if (hapd->conf->roaming_consortium ||
     237           6 :             get_anqp_elem(hapd, ANQP_ROAMING_CONSORTIUM))
     238         293 :                 wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM);
     239         575 :         if (hapd->conf->ipaddr_type_configured ||
     240         276 :             get_anqp_elem(hapd, ANQP_IP_ADDR_TYPE_AVAILABILITY))
     241          24 :                 wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
     242         303 :         if (hapd->conf->nai_realm_data ||
     243           4 :             get_anqp_elem(hapd, ANQP_NAI_REALM))
     244         295 :                 wpabuf_put_le16(buf, ANQP_NAI_REALM);
     245         304 :         if (hapd->conf->anqp_3gpp_cell_net ||
     246           5 :             get_anqp_elem(hapd, ANQP_3GPP_CELLULAR_NETWORK))
     247         294 :                 wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
     248         299 :         if (get_anqp_elem(hapd, ANQP_AP_GEOSPATIAL_LOCATION))
     249           1 :                 wpabuf_put_le16(buf, ANQP_AP_GEOSPATIAL_LOCATION);
     250         299 :         if (get_anqp_elem(hapd, ANQP_AP_CIVIC_LOCATION))
     251           1 :                 wpabuf_put_le16(buf, ANQP_AP_CIVIC_LOCATION);
     252         299 :         if (get_anqp_elem(hapd, ANQP_AP_LOCATION_PUBLIC_URI))
     253           1 :                 wpabuf_put_le16(buf, ANQP_AP_LOCATION_PUBLIC_URI);
     254         299 :         if (hapd->conf->domain_name || get_anqp_elem(hapd, ANQP_DOMAIN_NAME))
     255         288 :                 wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
     256         299 :         if (get_anqp_elem(hapd, ANQP_EMERGENCY_ALERT_URI))
     257           0 :                 wpabuf_put_le16(buf, ANQP_EMERGENCY_ALERT_URI);
     258         299 :         if (get_anqp_elem(hapd, ANQP_EMERGENCY_NAI))
     259           0 :                 wpabuf_put_le16(buf, ANQP_EMERGENCY_NAI);
     260         299 :         if (get_anqp_elem(hapd, ANQP_NEIGHBOR_REPORT))
     261           0 :                 wpabuf_put_le16(buf, ANQP_NEIGHBOR_REPORT);
     262        1495 :         for (id = 273; id < 277; id++) {
     263        1196 :                 if (get_anqp_elem(hapd, id))
     264           1 :                         wpabuf_put_le16(buf, id);
     265             :         }
     266         299 :         if (get_anqp_elem(hapd, ANQP_VENUE_URL))
     267           0 :                 wpabuf_put_le16(buf, ANQP_VENUE_URL);
     268         299 :         if (get_anqp_elem(hapd, ANQP_ADVICE_OF_CHARGE))
     269           0 :                 wpabuf_put_le16(buf, ANQP_ADVICE_OF_CHARGE);
     270         299 :         if (get_anqp_elem(hapd, ANQP_LOCAL_CONTENT))
     271           0 :                 wpabuf_put_le16(buf, ANQP_LOCAL_CONTENT);
     272             : #ifdef CONFIG_HS20
     273         299 :         anqp_add_hs_capab_list(hapd, buf);
     274             : #endif /* CONFIG_HS20 */
     275         299 :         gas_anqp_set_element_len(buf, len);
     276             : }
     277             : 
     278             : 
     279          48 : static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
     280             : {
     281          48 :         if (anqp_add_override(hapd, buf, ANQP_VENUE_NAME))
     282          48 :                 return;
     283             : 
     284          48 :         if (hapd->conf->venue_name) {
     285             :                 u8 *len;
     286             :                 unsigned int i;
     287          47 :                 len = gas_anqp_add_element(buf, ANQP_VENUE_NAME);
     288          47 :                 wpabuf_put_u8(buf, hapd->conf->venue_group);
     289          47 :                 wpabuf_put_u8(buf, hapd->conf->venue_type);
     290         140 :                 for (i = 0; i < hapd->conf->venue_name_count; i++) {
     291             :                         struct hostapd_lang_string *vn;
     292          93 :                         vn = &hapd->conf->venue_name[i];
     293          93 :                         wpabuf_put_u8(buf, 3 + vn->name_len);
     294          93 :                         wpabuf_put_data(buf, vn->lang, 3);
     295          93 :                         wpabuf_put_data(buf, vn->name, vn->name_len);
     296             :                 }
     297          47 :                 gas_anqp_set_element_len(buf, len);
     298             :         }
     299             : }
     300             : 
     301             : 
     302          32 : static void anqp_add_network_auth_type(struct hostapd_data *hapd,
     303             :                                        struct wpabuf *buf)
     304             : {
     305          32 :         if (anqp_add_override(hapd, buf, ANQP_NETWORK_AUTH_TYPE))
     306          32 :                 return;
     307             : 
     308          32 :         if (hapd->conf->network_auth_type) {
     309          18 :                 wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
     310          18 :                 wpabuf_put_le16(buf, hapd->conf->network_auth_type_len);
     311          18 :                 wpabuf_put_data(buf, hapd->conf->network_auth_type,
     312          18 :                                 hapd->conf->network_auth_type_len);
     313             :         }
     314             : }
     315             : 
     316             : 
     317          60 : static void anqp_add_roaming_consortium(struct hostapd_data *hapd,
     318             :                                         struct wpabuf *buf)
     319             : {
     320             :         unsigned int i;
     321             :         u8 *len;
     322             : 
     323          60 :         if (anqp_add_override(hapd, buf, ANQP_ROAMING_CONSORTIUM))
     324          61 :                 return;
     325             : 
     326          59 :         len = gas_anqp_add_element(buf, ANQP_ROAMING_CONSORTIUM);
     327         291 :         for (i = 0; i < hapd->conf->roaming_consortium_count; i++) {
     328             :                 struct hostapd_roaming_consortium *rc;
     329         232 :                 rc = &hapd->conf->roaming_consortium[i];
     330         232 :                 wpabuf_put_u8(buf, rc->len);
     331         232 :                 wpabuf_put_data(buf, rc->oi, rc->len);
     332             :         }
     333          59 :         gas_anqp_set_element_len(buf, len);
     334             : }
     335             : 
     336             : 
     337          32 : static void anqp_add_ip_addr_type_availability(struct hostapd_data *hapd,
     338             :                                                struct wpabuf *buf)
     339             : {
     340          32 :         if (anqp_add_override(hapd, buf, ANQP_IP_ADDR_TYPE_AVAILABILITY))
     341          33 :                 return;
     342             : 
     343          31 :         if (hapd->conf->ipaddr_type_configured) {
     344          18 :                 wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
     345          18 :                 wpabuf_put_le16(buf, 1);
     346          18 :                 wpabuf_put_u8(buf, hapd->conf->ipaddr_type_availability);
     347             :         }
     348             : }
     349             : 
     350             : 
     351         422 : static void anqp_add_nai_realm_eap(struct wpabuf *buf,
     352             :                                    struct hostapd_nai_realm_data *realm)
     353             : {
     354             :         unsigned int i, j;
     355             : 
     356         422 :         wpabuf_put_u8(buf, realm->eap_method_count);
     357             : 
     358         860 :         for (i = 0; i < realm->eap_method_count; i++) {
     359         438 :                 struct hostapd_nai_realm_eap *eap = &realm->eap_method[i];
     360         438 :                 wpabuf_put_u8(buf, 2 + (3 * eap->num_auths));
     361         438 :                 wpabuf_put_u8(buf, eap->eap_method);
     362         438 :                 wpabuf_put_u8(buf, eap->num_auths);
     363        1080 :                 for (j = 0; j < eap->num_auths; j++) {
     364         642 :                         wpabuf_put_u8(buf, eap->auth_id[j]);
     365         642 :                         wpabuf_put_u8(buf, 1);
     366         642 :                         wpabuf_put_u8(buf, eap->auth_val[j]);
     367             :                 }
     368             :         }
     369         422 : }
     370             : 
     371             : 
     372           3 : static void anqp_add_nai_realm_data(struct wpabuf *buf,
     373             :                                     struct hostapd_nai_realm_data *realm,
     374             :                                     unsigned int realm_idx)
     375             : {
     376             :         u8 *realm_data_len;
     377             : 
     378           3 :         wpa_printf(MSG_DEBUG, "realm=%s, len=%d", realm->realm[realm_idx],
     379           3 :                    (int) os_strlen(realm->realm[realm_idx]));
     380           3 :         realm_data_len = wpabuf_put(buf, 2);
     381           3 :         wpabuf_put_u8(buf, realm->encoding);
     382           3 :         wpabuf_put_u8(buf, os_strlen(realm->realm[realm_idx]));
     383           3 :         wpabuf_put_str(buf, realm->realm[realm_idx]);
     384           3 :         anqp_add_nai_realm_eap(buf, realm);
     385           3 :         gas_anqp_set_element_len(buf, realm_data_len);
     386           3 : }
     387             : 
     388             : 
     389           4 : static int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd,
     390             :                                            struct wpabuf *buf,
     391             :                                            const u8 *home_realm,
     392             :                                            size_t home_realm_len)
     393             : {
     394             :         unsigned int i, j, k;
     395           4 :         u8 num_realms, num_matching = 0, encoding, realm_len, *realm_list_len;
     396             :         struct hostapd_nai_realm_data *realm;
     397             :         const u8 *pos, *realm_name, *end;
     398             :         struct {
     399             :                 unsigned int realm_data_idx;
     400             :                 unsigned int realm_idx;
     401             :         } matches[10];
     402             : 
     403           4 :         pos = home_realm;
     404           4 :         end = pos + home_realm_len;
     405           4 :         if (end - pos < 1) {
     406           1 :                 wpa_hexdump(MSG_DEBUG, "Too short NAI Home Realm Query",
     407             :                             home_realm, home_realm_len);
     408           1 :                 return -1;
     409             :         }
     410           3 :         num_realms = *pos++;
     411             : 
     412           6 :         for (i = 0; i < num_realms && num_matching < 10; i++) {
     413           3 :                 if (end - pos < 2) {
     414           0 :                         wpa_hexdump(MSG_DEBUG,
     415             :                                     "Truncated NAI Home Realm Query",
     416             :                                     home_realm, home_realm_len);
     417           0 :                         return -1;
     418             :                 }
     419           3 :                 encoding = *pos++;
     420           3 :                 realm_len = *pos++;
     421           3 :                 if (realm_len > end - pos) {
     422           0 :                         wpa_hexdump(MSG_DEBUG,
     423             :                                     "Truncated NAI Home Realm Query",
     424             :                                     home_realm, home_realm_len);
     425           0 :                         return -1;
     426             :                 }
     427           3 :                 realm_name = pos;
     428          12 :                 for (j = 0; j < hapd->conf->nai_realm_count &&
     429           6 :                              num_matching < 10; j++) {
     430             :                         const u8 *rpos, *rend;
     431           6 :                         realm = &hapd->conf->nai_realm_data[j];
     432           6 :                         if (encoding != realm->encoding)
     433           0 :                                 continue;
     434             : 
     435           6 :                         rpos = realm_name;
     436          18 :                         while (rpos < realm_name + realm_len &&
     437             :                                num_matching < 10) {
     438          78 :                                 for (rend = rpos;
     439          66 :                                      rend < realm_name + realm_len; rend++) {
     440          66 :                                         if (*rend == ';')
     441           0 :                                                 break;
     442             :                                 }
     443          30 :                                 for (k = 0; k < MAX_NAI_REALMS &&
     444          18 :                                              realm->realm[k] &&
     445           6 :                                              num_matching < 10; k++) {
     446          12 :                                         if ((int) os_strlen(realm->realm[k]) !=
     447           9 :                                             rend - rpos ||
     448           3 :                                             os_strncmp((char *) rpos,
     449             :                                                        realm->realm[k],
     450             :                                                        rend - rpos) != 0)
     451           3 :                                                 continue;
     452           3 :                                         matches[num_matching].realm_data_idx =
     453             :                                                 j;
     454           3 :                                         matches[num_matching].realm_idx = k;
     455           3 :                                         num_matching++;
     456             :                                 }
     457           6 :                                 rpos = rend + 1;
     458             :                         }
     459             :                 }
     460           3 :                 pos += realm_len;
     461             :         }
     462             : 
     463           3 :         realm_list_len = gas_anqp_add_element(buf, ANQP_NAI_REALM);
     464           3 :         wpabuf_put_le16(buf, num_matching);
     465             : 
     466             :         /*
     467             :          * There are two ways to format. 1. each realm in a NAI Realm Data unit
     468             :          * 2. all realms that share the same EAP methods in a NAI Realm Data
     469             :          * unit. The first format is likely to be bigger in size than the
     470             :          * second, but may be easier to parse and process by the receiver.
     471             :          */
     472           6 :         for (i = 0; i < num_matching; i++) {
     473           3 :                 wpa_printf(MSG_DEBUG, "realm_idx %d, realm_data_idx %d",
     474             :                            matches[i].realm_data_idx, matches[i].realm_idx);
     475           3 :                 realm = &hapd->conf->nai_realm_data[matches[i].realm_data_idx];
     476           3 :                 anqp_add_nai_realm_data(buf, realm, matches[i].realm_idx);
     477             :         }
     478           3 :         gas_anqp_set_element_len(buf, realm_list_len);
     479           3 :         return 0;
     480             : }
     481             : 
     482             : 
     483         258 : static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf,
     484             :                                const u8 *home_realm, size_t home_realm_len,
     485             :                                int nai_realm, int nai_home_realm)
     486             : {
     487         512 :         if (nai_realm && !nai_home_realm &&
     488         254 :             anqp_add_override(hapd, buf, ANQP_NAI_REALM))
     489         277 :                 return;
     490             : 
     491         470 :         if (nai_realm && hapd->conf->nai_realm_data) {
     492             :                 u8 *len;
     493             :                 unsigned int i, j;
     494         231 :                 len = gas_anqp_add_element(buf, ANQP_NAI_REALM);
     495         231 :                 wpabuf_put_le16(buf, hapd->conf->nai_realm_count);
     496         650 :                 for (i = 0; i < hapd->conf->nai_realm_count; i++) {
     497             :                         u8 *realm_data_len, *realm_len;
     498             :                         struct hostapd_nai_realm_data *realm;
     499             : 
     500         419 :                         realm = &hapd->conf->nai_realm_data[i];
     501         419 :                         realm_data_len = wpabuf_put(buf, 2);
     502         419 :                         wpabuf_put_u8(buf, realm->encoding);
     503         419 :                         realm_len = wpabuf_put(buf, 1);
     504         850 :                         for (j = 0; realm->realm[j]; j++) {
     505         431 :                                 if (j > 0)
     506          12 :                                         wpabuf_put_u8(buf, ';');
     507         431 :                                 wpabuf_put_str(buf, realm->realm[j]);
     508             :                         }
     509         419 :                         *realm_len = (u8 *) wpabuf_put(buf, 0) - realm_len - 1;
     510         419 :                         anqp_add_nai_realm_eap(buf, realm);
     511         419 :                         gas_anqp_set_element_len(buf, realm_data_len);
     512             :                 }
     513         231 :                 gas_anqp_set_element_len(buf, len);
     514           8 :         } else if (nai_home_realm && hapd->conf->nai_realm_data && home_realm) {
     515           4 :                 hs20_add_nai_home_realm_matches(hapd, buf, home_realm,
     516             :                                                 home_realm_len);
     517             :         }
     518             : }
     519             : 
     520             : 
     521          67 : static void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd,
     522             :                                            struct wpabuf *buf)
     523             : {
     524          67 :         if (anqp_add_override(hapd, buf, ANQP_3GPP_CELLULAR_NETWORK))
     525          74 :                 return;
     526             : 
     527          60 :         if (hapd->conf->anqp_3gpp_cell_net) {
     528          57 :                 wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
     529          57 :                 wpabuf_put_le16(buf,
     530          57 :                                 hapd->conf->anqp_3gpp_cell_net_len);
     531          57 :                 wpabuf_put_data(buf, hapd->conf->anqp_3gpp_cell_net,
     532          57 :                                 hapd->conf->anqp_3gpp_cell_net_len);
     533             :         }
     534             : }
     535             : 
     536             : 
     537         246 : static void anqp_add_domain_name(struct hostapd_data *hapd, struct wpabuf *buf)
     538             : {
     539         246 :         if (anqp_add_override(hapd, buf, ANQP_DOMAIN_NAME))
     540         246 :                 return;
     541             : 
     542         246 :         if (hapd->conf->domain_name) {
     543         235 :                 wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
     544         235 :                 wpabuf_put_le16(buf, hapd->conf->domain_name_len);
     545         235 :                 wpabuf_put_data(buf, hapd->conf->domain_name,
     546         235 :                                 hapd->conf->domain_name_len);
     547             :         }
     548             : }
     549             : 
     550             : 
     551             : #ifdef CONFIG_HS20
     552             : 
     553          24 : static void anqp_add_operator_friendly_name(struct hostapd_data *hapd,
     554             :                                             struct wpabuf *buf)
     555             : {
     556          24 :         if (hapd->conf->hs20_oper_friendly_name) {
     557             :                 u8 *len;
     558             :                 unsigned int i;
     559          11 :                 len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
     560          11 :                 wpabuf_put_be24(buf, OUI_WFA);
     561          11 :                 wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
     562          11 :                 wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
     563          11 :                 wpabuf_put_u8(buf, 0); /* Reserved */
     564          33 :                 for (i = 0; i < hapd->conf->hs20_oper_friendly_name_count; i++)
     565             :                 {
     566             :                         struct hostapd_lang_string *vn;
     567          22 :                         vn = &hapd->conf->hs20_oper_friendly_name[i];
     568          22 :                         wpabuf_put_u8(buf, 3 + vn->name_len);
     569          22 :                         wpabuf_put_data(buf, vn->lang, 3);
     570          22 :                         wpabuf_put_data(buf, vn->name, vn->name_len);
     571             :                 }
     572          11 :                 gas_anqp_set_element_len(buf, len);
     573             :         }
     574          24 : }
     575             : 
     576             : 
     577          58 : static void anqp_add_wan_metrics(struct hostapd_data *hapd,
     578             :                                  struct wpabuf *buf)
     579             : {
     580          58 :         if (hapd->conf->hs20_wan_metrics) {
     581          57 :                 u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
     582          57 :                 wpabuf_put_be24(buf, OUI_WFA);
     583          57 :                 wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
     584          57 :                 wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS);
     585          57 :                 wpabuf_put_u8(buf, 0); /* Reserved */
     586          57 :                 wpabuf_put_data(buf, hapd->conf->hs20_wan_metrics, 13);
     587          57 :                 gas_anqp_set_element_len(buf, len);
     588             :         }
     589          58 : }
     590             : 
     591             : 
     592          36 : static void anqp_add_connection_capability(struct hostapd_data *hapd,
     593             :                                            struct wpabuf *buf)
     594             : {
     595          36 :         if (hapd->conf->hs20_connection_capability) {
     596          35 :                 u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
     597          35 :                 wpabuf_put_be24(buf, OUI_WFA);
     598          35 :                 wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
     599          35 :                 wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY);
     600          35 :                 wpabuf_put_u8(buf, 0); /* Reserved */
     601          35 :                 wpabuf_put_data(buf, hapd->conf->hs20_connection_capability,
     602          35 :                                 hapd->conf->hs20_connection_capability_len);
     603          35 :                 gas_anqp_set_element_len(buf, len);
     604             :         }
     605          36 : }
     606             : 
     607             : 
     608          22 : static void anqp_add_operating_class(struct hostapd_data *hapd,
     609             :                                      struct wpabuf *buf)
     610             : {
     611          22 :         if (hapd->conf->hs20_operating_class) {
     612          22 :                 u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
     613          22 :                 wpabuf_put_be24(buf, OUI_WFA);
     614          22 :                 wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
     615          22 :                 wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
     616          22 :                 wpabuf_put_u8(buf, 0); /* Reserved */
     617          22 :                 wpabuf_put_data(buf, hapd->conf->hs20_operating_class,
     618          22 :                                 hapd->conf->hs20_operating_class_len);
     619          22 :                 gas_anqp_set_element_len(buf, len);
     620             :         }
     621          22 : }
     622             : 
     623             : 
     624           6 : static void anqp_add_osu_provider(struct wpabuf *buf,
     625             :                                   struct hostapd_bss_config *bss,
     626             :                                   struct hs20_osu_provider *p)
     627             : {
     628             :         u8 *len, *len2, *count;
     629             :         unsigned int i;
     630             : 
     631           6 :         len = wpabuf_put(buf, 2); /* OSU Provider Length to be filled */
     632             : 
     633             :         /* OSU Friendly Name Duples */
     634           6 :         len2 = wpabuf_put(buf, 2);
     635          18 :         for (i = 0; i < p->friendly_name_count; i++) {
     636          12 :                 struct hostapd_lang_string *s = &p->friendly_name[i];
     637          12 :                 wpabuf_put_u8(buf, 3 + s->name_len);
     638          12 :                 wpabuf_put_data(buf, s->lang, 3);
     639          12 :                 wpabuf_put_data(buf, s->name, s->name_len);
     640             :         }
     641           6 :         WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
     642             : 
     643             :         /* OSU Server URI */
     644           6 :         if (p->server_uri) {
     645           6 :                 wpabuf_put_u8(buf, os_strlen(p->server_uri));
     646           6 :                 wpabuf_put_str(buf, p->server_uri);
     647             :         } else
     648           0 :                 wpabuf_put_u8(buf, 0);
     649             : 
     650             :         /* OSU Method List */
     651           6 :         count = wpabuf_put(buf, 1);
     652          12 :         for (i = 0; p->method_list[i] >= 0; i++)
     653           6 :                 wpabuf_put_u8(buf, p->method_list[i]);
     654           6 :         *count = i;
     655             : 
     656             :         /* Icons Available */
     657           6 :         len2 = wpabuf_put(buf, 2);
     658          12 :         for (i = 0; i < p->icons_count; i++) {
     659             :                 size_t j;
     660           6 :                 struct hs20_icon *icon = NULL;
     661             : 
     662          12 :                 for (j = 0; j < bss->hs20_icons_count && !icon; j++) {
     663           6 :                         if (os_strcmp(p->icons[i], bss->hs20_icons[j].name) ==
     664             :                             0)
     665           6 :                                 icon = &bss->hs20_icons[j];
     666             :                 }
     667           6 :                 if (!icon)
     668           0 :                         continue; /* icon info not found */
     669             : 
     670           6 :                 wpabuf_put_le16(buf, icon->width);
     671           6 :                 wpabuf_put_le16(buf, icon->height);
     672           6 :                 wpabuf_put_data(buf, icon->language, 3);
     673           6 :                 wpabuf_put_u8(buf, os_strlen(icon->type));
     674           6 :                 wpabuf_put_str(buf, icon->type);
     675           6 :                 wpabuf_put_u8(buf, os_strlen(icon->name));
     676           6 :                 wpabuf_put_str(buf, icon->name);
     677             :         }
     678           6 :         WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
     679             : 
     680             :         /* OSU_NAI */
     681           6 :         if (p->osu_nai) {
     682           1 :                 wpabuf_put_u8(buf, os_strlen(p->osu_nai));
     683           1 :                 wpabuf_put_str(buf, p->osu_nai);
     684             :         } else
     685           5 :                 wpabuf_put_u8(buf, 0);
     686             : 
     687             :         /* OSU Service Description Duples */
     688           6 :         len2 = wpabuf_put(buf, 2);
     689          18 :         for (i = 0; i < p->service_desc_count; i++) {
     690          12 :                 struct hostapd_lang_string *s = &p->service_desc[i];
     691          12 :                 wpabuf_put_u8(buf, 3 + s->name_len);
     692          12 :                 wpabuf_put_data(buf, s->lang, 3);
     693          12 :                 wpabuf_put_data(buf, s->name, s->name_len);
     694             :         }
     695           6 :         WPA_PUT_LE16(len2, (u8 *) wpabuf_put(buf, 0) - len2 - 2);
     696             : 
     697           6 :         WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
     698           6 : }
     699             : 
     700             : 
     701          22 : static void anqp_add_osu_providers_list(struct hostapd_data *hapd,
     702             :                                         struct wpabuf *buf)
     703             : {
     704          22 :         if (hapd->conf->hs20_osu_providers_count) {
     705             :                 size_t i;
     706           6 :                 u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
     707           6 :                 wpabuf_put_be24(buf, OUI_WFA);
     708           6 :                 wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
     709           6 :                 wpabuf_put_u8(buf, HS20_STYPE_OSU_PROVIDERS_LIST);
     710           6 :                 wpabuf_put_u8(buf, 0); /* Reserved */
     711             : 
     712             :                 /* OSU SSID */
     713           6 :                 wpabuf_put_u8(buf, hapd->conf->osu_ssid_len);
     714           6 :                 wpabuf_put_data(buf, hapd->conf->osu_ssid,
     715           6 :                                 hapd->conf->osu_ssid_len);
     716             : 
     717             :                 /* Number of OSU Providers */
     718           6 :                 wpabuf_put_u8(buf, hapd->conf->hs20_osu_providers_count);
     719             : 
     720          12 :                 for (i = 0; i < hapd->conf->hs20_osu_providers_count; i++) {
     721           6 :                         anqp_add_osu_provider(
     722             :                                 buf, hapd->conf,
     723           6 :                                 &hapd->conf->hs20_osu_providers[i]);
     724             :                 }
     725             : 
     726           6 :                 gas_anqp_set_element_len(buf, len);
     727             :         }
     728          22 : }
     729             : 
     730             : 
     731          19 : static void anqp_add_icon_binary_file(struct hostapd_data *hapd,
     732             :                                       struct wpabuf *buf,
     733             :                                       const u8 *name, size_t name_len)
     734             : {
     735             :         struct hs20_icon *icon;
     736             :         size_t i;
     737             :         u8 *len;
     738             : 
     739          19 :         wpa_hexdump_ascii(MSG_DEBUG, "HS 2.0: Requested Icon Filename",
     740             :                           name, name_len);
     741          21 :         for (i = 0; i < hapd->conf->hs20_icons_count; i++) {
     742          19 :                 icon = &hapd->conf->hs20_icons[i];
     743          38 :                 if (name_len == os_strlen(icon->name) &&
     744          19 :                     os_memcmp(name, icon->name, name_len) == 0)
     745          17 :                         break;
     746             :         }
     747             : 
     748          19 :         if (i < hapd->conf->hs20_icons_count)
     749          17 :                 icon = &hapd->conf->hs20_icons[i];
     750             :         else
     751           2 :                 icon = NULL;
     752             : 
     753          19 :         len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
     754          19 :         wpabuf_put_be24(buf, OUI_WFA);
     755          19 :         wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
     756          19 :         wpabuf_put_u8(buf, HS20_STYPE_ICON_BINARY_FILE);
     757          19 :         wpabuf_put_u8(buf, 0); /* Reserved */
     758             : 
     759          19 :         if (icon) {
     760             :                 char *data;
     761             :                 size_t data_len;
     762             : 
     763          17 :                 data = os_readfile(icon->file, &data_len);
     764          17 :                 if (data == NULL || data_len > 65535) {
     765           1 :                         wpabuf_put_u8(buf, 2); /* Download Status:
     766             :                                                 * Unspecified file error */
     767           1 :                         wpabuf_put_u8(buf, 0);
     768           1 :                         wpabuf_put_le16(buf, 0);
     769             :                 } else {
     770          16 :                         wpabuf_put_u8(buf, 0); /* Download Status: Success */
     771          16 :                         wpabuf_put_u8(buf, os_strlen(icon->type));
     772          16 :                         wpabuf_put_str(buf, icon->type);
     773          16 :                         wpabuf_put_le16(buf, data_len);
     774          16 :                         wpabuf_put_data(buf, data, data_len);
     775             :                 }
     776          17 :                 os_free(data);
     777             :         } else {
     778           2 :                 wpabuf_put_u8(buf, 1); /* Download Status: File not found */
     779           2 :                 wpabuf_put_u8(buf, 0);
     780           2 :                 wpabuf_put_le16(buf, 0);
     781             :         }
     782             : 
     783          19 :         gas_anqp_set_element_len(buf, len);
     784          19 : }
     785             : 
     786             : #endif /* CONFIG_HS20 */
     787             : 
     788             : 
     789         354 : static size_t anqp_get_required_len(struct hostapd_data *hapd,
     790             :                                     const u16 *infoid,
     791             :                                     unsigned int num_infoid)
     792             : {
     793         354 :         size_t len = 0;
     794             :         unsigned int i;
     795             : 
     796         356 :         for (i = 0; i < num_infoid; i++) {
     797           2 :                 struct anqp_element *elem = get_anqp_elem(hapd, infoid[i]);
     798             : 
     799           2 :                 if (elem)
     800           2 :                         len += 2 + 2 + wpabuf_len(elem->payload);
     801             :         }
     802             : 
     803         354 :         return len;
     804             : }
     805             : 
     806             : 
     807             : static struct wpabuf *
     808         354 : gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
     809             :                                 unsigned int request,
     810             :                                 const u8 *home_realm, size_t home_realm_len,
     811             :                                 const u8 *icon_name, size_t icon_name_len,
     812             :                                 const u16 *extra_req,
     813             :                                 unsigned int num_extra_req)
     814             : {
     815             :         struct wpabuf *buf;
     816             :         size_t len;
     817             :         unsigned int i;
     818             : 
     819         354 :         len = 1400;
     820         354 :         if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM))
     821         258 :                 len += 1000;
     822         354 :         if (request & ANQP_REQ_ICON_REQUEST)
     823          19 :                 len += 65536;
     824         354 :         len += anqp_get_required_len(hapd, extra_req, num_extra_req);
     825             : 
     826         354 :         buf = wpabuf_alloc(len);
     827         354 :         if (buf == NULL)
     828           0 :                 return NULL;
     829             : 
     830         354 :         if (request & ANQP_REQ_CAPABILITY_LIST)
     831         299 :                 anqp_add_capab_list(hapd, buf);
     832         354 :         if (request & ANQP_REQ_VENUE_NAME)
     833          48 :                 anqp_add_venue_name(hapd, buf);
     834         354 :         if (request & ANQP_REQ_EMERGENCY_CALL_NUMBER)
     835           1 :                 anqp_add_elem(hapd, buf, ANQP_EMERGENCY_CALL_NUMBER);
     836         354 :         if (request & ANQP_REQ_NETWORK_AUTH_TYPE)
     837          32 :                 anqp_add_network_auth_type(hapd, buf);
     838         354 :         if (request & ANQP_REQ_ROAMING_CONSORTIUM)
     839          60 :                 anqp_add_roaming_consortium(hapd, buf);
     840         354 :         if (request & ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY)
     841          32 :                 anqp_add_ip_addr_type_availability(hapd, buf);
     842         354 :         if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM))
     843         258 :                 anqp_add_nai_realm(hapd, buf, home_realm, home_realm_len,
     844             :                                    request & ANQP_REQ_NAI_REALM,
     845             :                                    request & ANQP_REQ_NAI_HOME_REALM);
     846         354 :         if (request & ANQP_REQ_3GPP_CELLULAR_NETWORK)
     847          67 :                 anqp_add_3gpp_cellular_network(hapd, buf);
     848         354 :         if (request & ANQP_REQ_AP_GEOSPATIAL_LOCATION)
     849           2 :                 anqp_add_elem(hapd, buf, ANQP_AP_GEOSPATIAL_LOCATION);
     850         354 :         if (request & ANQP_REQ_AP_CIVIC_LOCATION)
     851           1 :                 anqp_add_elem(hapd, buf, ANQP_AP_CIVIC_LOCATION);
     852         354 :         if (request & ANQP_REQ_AP_LOCATION_PUBLIC_URI)
     853           1 :                 anqp_add_elem(hapd, buf, ANQP_AP_LOCATION_PUBLIC_URI);
     854         354 :         if (request & ANQP_REQ_DOMAIN_NAME)
     855         246 :                 anqp_add_domain_name(hapd, buf);
     856         354 :         if (request & ANQP_REQ_EMERGENCY_ALERT_URI)
     857           1 :                 anqp_add_elem(hapd, buf, ANQP_EMERGENCY_ALERT_URI);
     858         354 :         if (request & ANQP_REQ_TDLS_CAPABILITY)
     859           1 :                 anqp_add_elem(hapd, buf, ANQP_TDLS_CAPABILITY);
     860         354 :         if (request & ANQP_REQ_EMERGENCY_NAI)
     861           1 :                 anqp_add_elem(hapd, buf, ANQP_EMERGENCY_NAI);
     862             : 
     863         356 :         for (i = 0; i < num_extra_req; i++)
     864           2 :                 anqp_add_elem(hapd, buf, extra_req[i]);
     865             : 
     866             : #ifdef CONFIG_HS20
     867         354 :         if (request & ANQP_REQ_HS_CAPABILITY_LIST)
     868         283 :                 anqp_add_hs_capab_list(hapd, buf);
     869         354 :         if (request & ANQP_REQ_OPERATOR_FRIENDLY_NAME)
     870          24 :                 anqp_add_operator_friendly_name(hapd, buf);
     871         354 :         if (request & ANQP_REQ_WAN_METRICS)
     872          58 :                 anqp_add_wan_metrics(hapd, buf);
     873         354 :         if (request & ANQP_REQ_CONNECTION_CAPABILITY)
     874          36 :                 anqp_add_connection_capability(hapd, buf);
     875         354 :         if (request & ANQP_REQ_OPERATING_CLASS)
     876          22 :                 anqp_add_operating_class(hapd, buf);
     877         354 :         if (request & ANQP_REQ_OSU_PROVIDERS_LIST)
     878          22 :                 anqp_add_osu_providers_list(hapd, buf);
     879         354 :         if (request & ANQP_REQ_ICON_REQUEST)
     880          19 :                 anqp_add_icon_binary_file(hapd, buf, icon_name, icon_name_len);
     881             : #endif /* CONFIG_HS20 */
     882             : 
     883         354 :         return buf;
     884             : }
     885             : 
     886             : 
     887             : #define ANQP_MAX_EXTRA_REQ 20
     888             : 
     889             : struct anqp_query_info {
     890             :         unsigned int request;
     891             :         const u8 *home_realm_query;
     892             :         size_t home_realm_query_len;
     893             :         const u8 *icon_name;
     894             :         size_t icon_name_len;
     895             :         int p2p_sd;
     896             :         u16 extra_req[ANQP_MAX_EXTRA_REQ];
     897             :         unsigned int num_extra_req;
     898             : };
     899             : 
     900             : 
     901        1491 : static void set_anqp_req(unsigned int bit, const char *name, int local,
     902             :                          struct anqp_query_info *qi)
     903             : {
     904        1491 :         qi->request |= bit;
     905        1491 :         if (local) {
     906        1408 :                 wpa_printf(MSG_DEBUG, "ANQP: %s (local)", name);
     907             :         } else {
     908          83 :                 wpa_printf(MSG_DEBUG, "ANQP: %s not available", name);
     909             :         }
     910        1491 : }
     911             : 
     912             : 
     913        1075 : static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
     914             :                                   struct anqp_query_info *qi)
     915             : {
     916        1075 :         switch (info_id) {
     917             :         case ANQP_CAPABILITY_LIST:
     918         299 :                 set_anqp_req(ANQP_REQ_CAPABILITY_LIST, "Capability List", 1,
     919             :                              qi);
     920         299 :                 break;
     921             :         case ANQP_VENUE_NAME:
     922          48 :                 set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name",
     923          48 :                              hapd->conf->venue_name != NULL, qi);
     924          48 :                 break;
     925             :         case ANQP_EMERGENCY_CALL_NUMBER:
     926           1 :                 set_anqp_req(ANQP_REQ_EMERGENCY_CALL_NUMBER,
     927             :                              "Emergency Call Number",
     928           1 :                              get_anqp_elem(hapd, info_id) != NULL, qi);
     929           1 :                 break;
     930             :         case ANQP_NETWORK_AUTH_TYPE:
     931          32 :                 set_anqp_req(ANQP_REQ_NETWORK_AUTH_TYPE, "Network Auth Type",
     932          32 :                              hapd->conf->network_auth_type != NULL, qi);
     933          32 :                 break;
     934             :         case ANQP_ROAMING_CONSORTIUM:
     935          60 :                 set_anqp_req(ANQP_REQ_ROAMING_CONSORTIUM, "Roaming Consortium",
     936          60 :                              hapd->conf->roaming_consortium != NULL, qi);
     937          60 :                 break;
     938             :         case ANQP_IP_ADDR_TYPE_AVAILABILITY:
     939          32 :                 set_anqp_req(ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY,
     940             :                              "IP Addr Type Availability",
     941          32 :                              hapd->conf->ipaddr_type_configured, qi);
     942          32 :                 break;
     943             :         case ANQP_NAI_REALM:
     944         254 :                 set_anqp_req(ANQP_REQ_NAI_REALM, "NAI Realm",
     945         254 :                              hapd->conf->nai_realm_data != NULL, qi);
     946         254 :                 break;
     947             :         case ANQP_3GPP_CELLULAR_NETWORK:
     948          67 :                 set_anqp_req(ANQP_REQ_3GPP_CELLULAR_NETWORK,
     949             :                              "3GPP Cellular Network",
     950          67 :                              hapd->conf->anqp_3gpp_cell_net != NULL, qi);
     951          67 :                 break;
     952             :         case ANQP_AP_GEOSPATIAL_LOCATION:
     953           2 :                 set_anqp_req(ANQP_REQ_AP_GEOSPATIAL_LOCATION,
     954             :                              "AP Geospatial Location",
     955           2 :                              get_anqp_elem(hapd, info_id) != NULL, qi);
     956           2 :                 break;
     957             :         case ANQP_AP_CIVIC_LOCATION:
     958           1 :                 set_anqp_req(ANQP_REQ_AP_CIVIC_LOCATION,
     959             :                              "AP Civic Location",
     960           1 :                              get_anqp_elem(hapd, info_id) != NULL, qi);
     961           1 :                 break;
     962             :         case ANQP_AP_LOCATION_PUBLIC_URI:
     963           1 :                 set_anqp_req(ANQP_REQ_AP_LOCATION_PUBLIC_URI,
     964             :                              "AP Location Public URI",
     965           1 :                              get_anqp_elem(hapd, info_id) != NULL, qi);
     966           1 :                 break;
     967             :         case ANQP_DOMAIN_NAME:
     968         246 :                 set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name",
     969         246 :                              hapd->conf->domain_name != NULL, qi);
     970         246 :                 break;
     971             :         case ANQP_EMERGENCY_ALERT_URI:
     972           1 :                 set_anqp_req(ANQP_REQ_EMERGENCY_ALERT_URI,
     973             :                              "Emergency Alert URI",
     974           1 :                              get_anqp_elem(hapd, info_id) != NULL, qi);
     975           1 :                 break;
     976             :         case ANQP_TDLS_CAPABILITY:
     977           1 :                 set_anqp_req(ANQP_REQ_TDLS_CAPABILITY,
     978             :                              "TDLS Capability",
     979           1 :                              get_anqp_elem(hapd, info_id) != NULL, qi);
     980           1 :                 break;
     981             :         case ANQP_EMERGENCY_NAI:
     982           1 :                 set_anqp_req(ANQP_REQ_EMERGENCY_NAI,
     983             :                              "Emergency NAI",
     984           1 :                              get_anqp_elem(hapd, info_id) != NULL, qi);
     985           1 :                 break;
     986             :         default:
     987          29 :                 if (!get_anqp_elem(hapd, info_id)) {
     988          27 :                         wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
     989             :                                    info_id);
     990          27 :                         break;
     991             :                 }
     992           2 :                 if (qi->num_extra_req == ANQP_MAX_EXTRA_REQ) {
     993           0 :                         wpa_printf(MSG_DEBUG,
     994             :                                    "ANQP: No more room for extra requests - ignore Info Id %u",
     995             :                                    info_id);
     996           0 :                         break;
     997             :                 }
     998           2 :                 wpa_printf(MSG_DEBUG, "ANQP: Info Id %u (local)", info_id);
     999           2 :                 qi->extra_req[qi->num_extra_req] = info_id;
    1000           2 :                 qi->num_extra_req++;
    1001           2 :                 break;
    1002             :         }
    1003        1075 : }
    1004             : 
    1005             : 
    1006         328 : static void rx_anqp_query_list(struct hostapd_data *hapd,
    1007             :                                const u8 *pos, const u8 *end,
    1008             :                                struct anqp_query_info *qi)
    1009             : {
    1010         328 :         wpa_printf(MSG_DEBUG, "ANQP: %u Info IDs requested in Query list",
    1011         328 :                    (unsigned int) (end - pos) / 2);
    1012             : 
    1013        1731 :         while (end - pos >= 2) {
    1014        1075 :                 rx_anqp_query_list_id(hapd, WPA_GET_LE16(pos), qi);
    1015        1075 :                 pos += 2;
    1016             :         }
    1017         328 : }
    1018             : 
    1019             : 
    1020             : #ifdef CONFIG_HS20
    1021             : 
    1022         445 : static void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype,
    1023             :                                   struct anqp_query_info *qi)
    1024             : {
    1025         445 :         switch (subtype) {
    1026             :         case HS20_STYPE_CAPABILITY_LIST:
    1027         283 :                 set_anqp_req(ANQP_REQ_HS_CAPABILITY_LIST, "HS Capability List",
    1028             :                              1, qi);
    1029         283 :                 break;
    1030             :         case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
    1031          24 :                 set_anqp_req(ANQP_REQ_OPERATOR_FRIENDLY_NAME,
    1032             :                              "Operator Friendly Name",
    1033          24 :                              hapd->conf->hs20_oper_friendly_name != NULL, qi);
    1034          24 :                 break;
    1035             :         case HS20_STYPE_WAN_METRICS:
    1036          58 :                 set_anqp_req(ANQP_REQ_WAN_METRICS, "WAN Metrics",
    1037          58 :                              hapd->conf->hs20_wan_metrics != NULL, qi);
    1038          58 :                 break;
    1039             :         case HS20_STYPE_CONNECTION_CAPABILITY:
    1040          36 :                 set_anqp_req(ANQP_REQ_CONNECTION_CAPABILITY,
    1041             :                              "Connection Capability",
    1042          36 :                              hapd->conf->hs20_connection_capability != NULL,
    1043             :                              qi);
    1044          36 :                 break;
    1045             :         case HS20_STYPE_OPERATING_CLASS:
    1046          22 :                 set_anqp_req(ANQP_REQ_OPERATING_CLASS, "Operating Class",
    1047          22 :                              hapd->conf->hs20_operating_class != NULL, qi);
    1048          22 :                 break;
    1049             :         case HS20_STYPE_OSU_PROVIDERS_LIST:
    1050          22 :                 set_anqp_req(ANQP_REQ_OSU_PROVIDERS_LIST, "OSU Providers list",
    1051          22 :                              hapd->conf->hs20_osu_providers_count, qi);
    1052          22 :                 break;
    1053             :         default:
    1054           0 :                 wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u",
    1055             :                            subtype);
    1056           0 :                 break;
    1057             :         }
    1058         445 : }
    1059             : 
    1060             : 
    1061           4 : static void rx_anqp_hs_nai_home_realm(struct hostapd_data *hapd,
    1062             :                                       const u8 *pos, const u8 *end,
    1063             :                                       struct anqp_query_info *qi)
    1064             : {
    1065           4 :         qi->request |= ANQP_REQ_NAI_HOME_REALM;
    1066           4 :         qi->home_realm_query = pos;
    1067           4 :         qi->home_realm_query_len = end - pos;
    1068           4 :         if (hapd->conf->nai_realm_data != NULL) {
    1069           4 :                 wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query "
    1070             :                            "(local)");
    1071             :         } else {
    1072           0 :                 wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query not "
    1073             :                            "available");
    1074             :         }
    1075           4 : }
    1076             : 
    1077             : 
    1078          19 : static void rx_anqp_hs_icon_request(struct hostapd_data *hapd,
    1079             :                                     const u8 *pos, const u8 *end,
    1080             :                                     struct anqp_query_info *qi)
    1081             : {
    1082          19 :         qi->request |= ANQP_REQ_ICON_REQUEST;
    1083          19 :         qi->icon_name = pos;
    1084          19 :         qi->icon_name_len = end - pos;
    1085          19 :         if (hapd->conf->hs20_icons_count) {
    1086          17 :                 wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Icon Request Query "
    1087             :                            "(local)");
    1088             :         } else {
    1089           2 :                 wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Icon Request Query not "
    1090             :                            "available");
    1091             :         }
    1092          19 : }
    1093             : 
    1094             : 
    1095         310 : static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
    1096             :                                     const u8 *pos, const u8 *end,
    1097             :                                     struct anqp_query_info *qi)
    1098             : {
    1099             :         u32 oui;
    1100             :         u8 subtype;
    1101             : 
    1102         310 :         if (end - pos < 4) {
    1103           0 :                 wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP "
    1104             :                            "Query element");
    1105           0 :                 return;
    1106             :         }
    1107             : 
    1108         310 :         oui = WPA_GET_BE24(pos);
    1109         310 :         pos += 3;
    1110         310 :         if (oui != OUI_WFA) {
    1111           0 :                 wpa_printf(MSG_DEBUG, "ANQP: Unsupported vendor OUI %06x",
    1112             :                            oui);
    1113           0 :                 return;
    1114             :         }
    1115             : 
    1116             : #ifdef CONFIG_P2P
    1117           2 :         if (*pos == P2P_OUI_TYPE) {
    1118             :                 /*
    1119             :                  * This is for P2P SD and will be taken care of by the P2P
    1120             :                  * implementation. This query needs to be ignored in the generic
    1121             :                  * GAS server to avoid duplicated response.
    1122             :                  */
    1123           2 :                 wpa_printf(MSG_DEBUG,
    1124             :                            "ANQP: Ignore WFA vendor type %u (P2P SD) in generic GAS server",
    1125           2 :                            *pos);
    1126           2 :                 qi->p2p_sd = 1;
    1127           2 :                 return;
    1128             :         }
    1129             : #endif /* CONFIG_P2P */
    1130             : 
    1131         308 :         if (*pos != HS20_ANQP_OUI_TYPE) {
    1132           0 :                 wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u",
    1133           0 :                            *pos);
    1134           0 :                 return;
    1135             :         }
    1136         308 :         pos++;
    1137             : 
    1138         308 :         if (end - pos <= 1)
    1139           0 :                 return;
    1140             : 
    1141         308 :         subtype = *pos++;
    1142         308 :         pos++; /* Reserved */
    1143         308 :         switch (subtype) {
    1144             :         case HS20_STYPE_QUERY_LIST:
    1145         285 :                 wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Query List");
    1146        1015 :                 while (pos < end) {
    1147         445 :                         rx_anqp_hs_query_list(hapd, *pos, qi);
    1148         445 :                         pos++;
    1149             :                 }
    1150         285 :                 break;
    1151             :         case HS20_STYPE_NAI_HOME_REALM_QUERY:
    1152           4 :                 rx_anqp_hs_nai_home_realm(hapd, pos, end, qi);
    1153           4 :                 break;
    1154             :         case HS20_STYPE_ICON_REQUEST:
    1155          19 :                 rx_anqp_hs_icon_request(hapd, pos, end, qi);
    1156          19 :                 break;
    1157             :         default:
    1158           0 :                 wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 query subtype "
    1159             :                            "%u", subtype);
    1160           0 :                 break;
    1161             :         }
    1162             : }
    1163             : 
    1164             : #endif /* CONFIG_HS20 */
    1165             : 
    1166             : 
    1167         354 : static void gas_serv_req_local_processing(struct hostapd_data *hapd,
    1168             :                                           const u8 *sa, u8 dialog_token,
    1169             :                                           struct anqp_query_info *qi, int prot,
    1170             :                                           int std_addr3)
    1171             : {
    1172             :         struct wpabuf *buf, *tx_buf;
    1173             : 
    1174         708 :         buf = gas_serv_build_gas_resp_payload(hapd, qi->request,
    1175             :                                               qi->home_realm_query,
    1176             :                                               qi->home_realm_query_len,
    1177             :                                               qi->icon_name, qi->icon_name_len,
    1178         354 :                                               qi->extra_req, qi->num_extra_req);
    1179         354 :         wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses",
    1180             :                         buf);
    1181         354 :         if (!buf)
    1182           0 :                 return;
    1183             : #ifdef CONFIG_P2P
    1184           2 :         if (wpabuf_len(buf) == 0 && qi->p2p_sd) {
    1185           2 :                 wpa_printf(MSG_DEBUG,
    1186             :                            "ANQP: Do not send response to P2P SD from generic GAS service (P2P SD implementation will process this)");
    1187           2 :                 wpabuf_free(buf);
    1188           2 :                 return;
    1189             :         }
    1190             : #endif /* CONFIG_P2P */
    1191             : 
    1192         670 :         if (wpabuf_len(buf) > hapd->gas_frag_limit ||
    1193         357 :             hapd->conf->gas_comeback_delay) {
    1194             :                 struct gas_dialog_info *di;
    1195          39 :                 u16 comeback_delay = 1;
    1196             : 
    1197          39 :                 if (hapd->conf->gas_comeback_delay) {
    1198             :                         /* Testing - allow overriding of the delay value */
    1199           7 :                         comeback_delay = hapd->conf->gas_comeback_delay;
    1200             :                 }
    1201             : 
    1202          39 :                 wpa_printf(MSG_DEBUG, "ANQP: Too long response to fit in "
    1203             :                            "initial response - use GAS comeback");
    1204          39 :                 di = gas_dialog_create(hapd, sa, dialog_token);
    1205          39 :                 if (!di) {
    1206           7 :                         wpa_printf(MSG_INFO, "ANQP: Could not create dialog "
    1207             :                                    "for " MACSTR " (dialog token %u)",
    1208           6 :                                    MAC2STR(sa), dialog_token);
    1209           1 :                         wpabuf_free(buf);
    1210           1 :                         tx_buf = gas_anqp_build_initial_resp_buf(
    1211             :                                 dialog_token, WLAN_STATUS_UNSPECIFIED_FAILURE,
    1212             :                                 0, NULL);
    1213             :                 } else {
    1214          38 :                         di->prot = prot;
    1215          38 :                         di->sd_resp = buf;
    1216          38 :                         di->sd_resp_pos = 0;
    1217          38 :                         tx_buf = gas_anqp_build_initial_resp_buf(
    1218             :                                 dialog_token, WLAN_STATUS_SUCCESS,
    1219             :                                 comeback_delay, NULL);
    1220             :                 }
    1221             :         } else {
    1222         313 :                 wpa_printf(MSG_DEBUG, "ANQP: Initial response (no comeback)");
    1223         313 :                 tx_buf = gas_anqp_build_initial_resp_buf(
    1224             :                         dialog_token, WLAN_STATUS_SUCCESS, 0, buf);
    1225         313 :                 wpabuf_free(buf);
    1226             :         }
    1227         352 :         if (!tx_buf)
    1228           1 :                 return;
    1229         351 :         if (prot)
    1230           3 :                 convert_to_protected_dual(tx_buf);
    1231         351 :         if (std_addr3)
    1232           4 :                 hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
    1233           2 :                                         wpabuf_head(tx_buf),
    1234             :                                         wpabuf_len(tx_buf));
    1235             :         else
    1236         698 :                 hostapd_drv_send_action_addr3_ap(hapd, hapd->iface->freq, 0, sa,
    1237         349 :                                                  wpabuf_head(tx_buf),
    1238             :                                                  wpabuf_len(tx_buf));
    1239         351 :         wpabuf_free(tx_buf);
    1240             : }
    1241             : 
    1242             : 
    1243         356 : static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
    1244             :                                         const u8 *sa,
    1245             :                                         const u8 *data, size_t len, int prot,
    1246             :                                         int std_addr3)
    1247             : {
    1248         356 :         const u8 *pos = data;
    1249         356 :         const u8 *end = data + len;
    1250             :         const u8 *next;
    1251             :         u8 dialog_token;
    1252             :         u16 slen;
    1253             :         struct anqp_query_info qi;
    1254             :         const u8 *adv_proto;
    1255             : 
    1256         356 :         if (len < 1 + 2)
    1257           3 :                 return;
    1258             : 
    1259         355 :         os_memset(&qi, 0, sizeof(qi));
    1260             : 
    1261         355 :         dialog_token = *pos++;
    1262        2485 :         wpa_msg(hapd->msg_ctx, MSG_DEBUG,
    1263             :                 "GAS: GAS Initial Request from " MACSTR " (dialog token %u) ",
    1264        2130 :                 MAC2STR(sa), dialog_token);
    1265             : 
    1266         355 :         if (*pos != WLAN_EID_ADV_PROTO) {
    1267           0 :                 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
    1268           0 :                         "GAS: Unexpected IE in GAS Initial Request: %u", *pos);
    1269           0 :                 return;
    1270             :         }
    1271         355 :         adv_proto = pos++;
    1272             : 
    1273         355 :         slen = *pos++;
    1274         355 :         if (slen > end - pos || slen < 2) {
    1275           0 :                 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
    1276             :                         "GAS: Invalid IE in GAS Initial Request");
    1277           0 :                 return;
    1278             :         }
    1279         355 :         next = pos + slen;
    1280         355 :         pos++; /* skip QueryRespLenLimit and PAME-BI */
    1281             : 
    1282         355 :         if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
    1283             :                 struct wpabuf *buf;
    1284           1 :                 wpa_msg(hapd->msg_ctx, MSG_DEBUG,
    1285             :                         "GAS: Unsupported GAS advertisement protocol id %u",
    1286           1 :                         *pos);
    1287           1 :                 if (sa[0] & 0x01)
    1288           0 :                         return; /* Invalid source address - drop silently */
    1289           1 :                 buf = gas_build_initial_resp(
    1290             :                         dialog_token, WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED,
    1291           1 :                         0, 2 + slen + 2);
    1292           1 :                 if (buf == NULL)
    1293           0 :                         return;
    1294           1 :                 wpabuf_put_data(buf, adv_proto, 2 + slen);
    1295           1 :                 wpabuf_put_le16(buf, 0); /* Query Response Length */
    1296           1 :                 if (prot)
    1297           0 :                         convert_to_protected_dual(buf);
    1298           1 :                 if (std_addr3)
    1299           0 :                         hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
    1300           0 :                                                 wpabuf_head(buf),
    1301             :                                                 wpabuf_len(buf));
    1302             :                 else
    1303           2 :                         hostapd_drv_send_action_addr3_ap(hapd,
    1304           1 :                                                          hapd->iface->freq, 0,
    1305           1 :                                                          sa, wpabuf_head(buf),
    1306             :                                                          wpabuf_len(buf));
    1307           1 :                 wpabuf_free(buf);
    1308           1 :                 return;
    1309             :         }
    1310             : 
    1311         354 :         pos = next;
    1312             :         /* Query Request */
    1313         354 :         if (end - pos < 2)
    1314           0 :                 return;
    1315         354 :         slen = WPA_GET_LE16(pos);
    1316         354 :         pos += 2;
    1317         354 :         if (slen > end - pos)
    1318           0 :                 return;
    1319         354 :         end = pos + slen;
    1320             : 
    1321             :         /* ANQP Query Request */
    1322        1346 :         while (pos < end) {
    1323             :                 u16 info_id, elen;
    1324             : 
    1325         638 :                 if (end - pos < 4)
    1326           0 :                         return;
    1327             : 
    1328         638 :                 info_id = WPA_GET_LE16(pos);
    1329         638 :                 pos += 2;
    1330         638 :                 elen = WPA_GET_LE16(pos);
    1331         638 :                 pos += 2;
    1332             : 
    1333         638 :                 if (elen > end - pos) {
    1334           0 :                         wpa_printf(MSG_DEBUG, "ANQP: Invalid Query Request");
    1335           0 :                         return;
    1336             :                 }
    1337             : 
    1338         638 :                 switch (info_id) {
    1339             :                 case ANQP_QUERY_LIST:
    1340         328 :                         rx_anqp_query_list(hapd, pos, pos + elen, &qi);
    1341         328 :                         break;
    1342             : #ifdef CONFIG_HS20
    1343             :                 case ANQP_VENDOR_SPECIFIC:
    1344         310 :                         rx_anqp_vendor_specific(hapd, pos, pos + elen, &qi);
    1345         310 :                         break;
    1346             : #endif /* CONFIG_HS20 */
    1347             :                 default:
    1348           0 :                         wpa_printf(MSG_DEBUG, "ANQP: Unsupported Query "
    1349             :                                    "Request element %u", info_id);
    1350           0 :                         break;
    1351             :                 }
    1352             : 
    1353         638 :                 pos += elen;
    1354             :         }
    1355             : 
    1356         354 :         gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot,
    1357             :                                       std_addr3);
    1358             : }
    1359             : 
    1360             : 
    1361         155 : static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
    1362             :                                          const u8 *sa,
    1363             :                                          const u8 *data, size_t len, int prot,
    1364             :                                          int std_addr3)
    1365             : {
    1366             :         struct gas_dialog_info *dialog;
    1367             :         struct wpabuf *buf, *tx_buf;
    1368             :         u8 dialog_token;
    1369             :         size_t frag_len;
    1370         155 :         int more = 0;
    1371             : 
    1372         155 :         wpa_hexdump(MSG_DEBUG, "GAS: RX GAS Comeback Request", data, len);
    1373         155 :         if (len < 1)
    1374           0 :                 return;
    1375         155 :         dialog_token = *data;
    1376         155 :         wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Dialog Token: %u",
    1377             :                 dialog_token);
    1378             : 
    1379         155 :         dialog = gas_serv_dialog_find(hapd, sa, dialog_token);
    1380         155 :         if (!dialog) {
    1381           7 :                 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: No pending SD "
    1382             :                         "response fragment for " MACSTR " dialog token %u",
    1383           6 :                         MAC2STR(sa), dialog_token);
    1384             : 
    1385           1 :                 if (sa[0] & 0x01)
    1386           0 :                         return; /* Invalid source address - drop silently */
    1387           1 :                 tx_buf = gas_anqp_build_comeback_resp_buf(
    1388             :                         dialog_token, WLAN_STATUS_NO_OUTSTANDING_GAS_REQ, 0, 0,
    1389             :                         0, NULL);
    1390           1 :                 if (tx_buf == NULL)
    1391           0 :                         return;
    1392           1 :                 goto send_resp;
    1393             :         }
    1394             : 
    1395         154 :         frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
    1396         154 :         if (frag_len > hapd->gas_frag_limit) {
    1397         128 :                 frag_len = hapd->gas_frag_limit;
    1398         128 :                 more = 1;
    1399             :         }
    1400         154 :         wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: resp frag_len %u",
    1401             :                 (unsigned int) frag_len);
    1402         154 :         buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) +
    1403             :                                 dialog->sd_resp_pos, frag_len);
    1404         154 :         if (buf == NULL) {
    1405           0 :                 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Failed to allocate "
    1406             :                         "buffer");
    1407           0 :                 gas_serv_dialog_clear(dialog);
    1408           0 :                 return;
    1409             :         }
    1410         308 :         tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token,
    1411             :                                                   WLAN_STATUS_SUCCESS,
    1412         154 :                                                   dialog->sd_frag_id,
    1413             :                                                   more, 0, buf);
    1414         154 :         wpabuf_free(buf);
    1415         154 :         if (tx_buf == NULL) {
    1416           1 :                 gas_serv_dialog_clear(dialog);
    1417           1 :                 return;
    1418             :         }
    1419         306 :         wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Comeback Response "
    1420             :                 "(frag_id %d more=%d frag_len=%d)",
    1421         153 :                 dialog->sd_frag_id, more, (int) frag_len);
    1422         153 :         dialog->sd_frag_id++;
    1423         153 :         dialog->sd_resp_pos += frag_len;
    1424             : 
    1425         153 :         if (more) {
    1426         254 :                 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: %d more bytes remain "
    1427             :                         "to be sent",
    1428         127 :                         (int) (wpabuf_len(dialog->sd_resp) -
    1429         127 :                                dialog->sd_resp_pos));
    1430             :         } else {
    1431          26 :                 wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: All fragments of "
    1432             :                         "SD response sent");
    1433          26 :                 gas_serv_dialog_clear(dialog);
    1434          26 :                 gas_serv_free_dialogs(hapd, sa);
    1435             :         }
    1436             : 
    1437             : send_resp:
    1438         154 :         if (prot)
    1439           0 :                 convert_to_protected_dual(tx_buf);
    1440         154 :         if (std_addr3)
    1441           0 :                 hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
    1442           0 :                                         wpabuf_head(tx_buf),
    1443             :                                         wpabuf_len(tx_buf));
    1444             :         else
    1445         308 :                 hostapd_drv_send_action_addr3_ap(hapd, hapd->iface->freq, 0, sa,
    1446         154 :                                                  wpabuf_head(tx_buf),
    1447             :                                                  wpabuf_len(tx_buf));
    1448         154 :         wpabuf_free(tx_buf);
    1449             : }
    1450             : 
    1451             : 
    1452         607 : static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
    1453             :                                       int freq)
    1454             : {
    1455         607 :         struct hostapd_data *hapd = ctx;
    1456             :         const struct ieee80211_mgmt *mgmt;
    1457             :         const u8 *sa, *data;
    1458             :         int prot, std_addr3;
    1459             : 
    1460         607 :         mgmt = (const struct ieee80211_mgmt *) buf;
    1461         607 :         if (len < IEEE80211_HDRLEN + 2)
    1462           0 :                 return;
    1463         610 :         if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
    1464           3 :             mgmt->u.action.category != WLAN_ACTION_PROTECTED_DUAL)
    1465           0 :                 return;
    1466             :         /*
    1467             :          * Note: Public Action and Protected Dual of Public Action frames share
    1468             :          * the same payload structure, so it is fine to use definitions of
    1469             :          * Public Action frames to process both.
    1470             :          */
    1471         607 :         prot = mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL;
    1472         607 :         sa = mgmt->sa;
    1473         607 :         if (hapd->conf->gas_address3 == 1)
    1474           1 :                 std_addr3 = 1;
    1475         606 :         else if (hapd->conf->gas_address3 == 2)
    1476           1 :                 std_addr3 = 0;
    1477             :         else
    1478         605 :                 std_addr3 = is_broadcast_ether_addr(mgmt->bssid);
    1479         607 :         len -= IEEE80211_HDRLEN + 1;
    1480         607 :         data = buf + IEEE80211_HDRLEN + 1;
    1481         607 :         switch (data[0]) {
    1482             :         case WLAN_PA_GAS_INITIAL_REQ:
    1483         356 :                 gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot,
    1484             :                                             std_addr3);
    1485         356 :                 break;
    1486             :         case WLAN_PA_GAS_COMEBACK_REQ:
    1487         155 :                 gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot,
    1488             :                                              std_addr3);
    1489         155 :                 break;
    1490             :         }
    1491             : }
    1492             : 
    1493             : 
    1494        2650 : int gas_serv_init(struct hostapd_data *hapd)
    1495             : {
    1496        2650 :         hapd->public_action_cb2 = gas_serv_rx_public_action;
    1497        2650 :         hapd->public_action_cb2_ctx = hapd;
    1498        2650 :         hapd->gas_frag_limit = 1400;
    1499        2650 :         if (hapd->conf->gas_frag_limit > 0)
    1500           0 :                 hapd->gas_frag_limit = hapd->conf->gas_frag_limit;
    1501        2650 :         return 0;
    1502             : }
    1503             : 
    1504             : 
    1505        2659 : void gas_serv_deinit(struct hostapd_data *hapd)
    1506             : {
    1507        2659 : }

Generated by: LCOV version 1.10