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 1388338050 Lines: 425 644 66.0 %
Date: 2013-12-29 Functions: 30 35 85.7 %
Branches: 156 292 53.4 %

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

Generated by: LCOV version 1.9