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 1393793999 Lines: 605 781 77.5 %
Date: 2014-03-02 Functions: 38 40 95.0 %
Branches: 240 358 67.0 %

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

Generated by: LCOV version 1.9