LCOV - code coverage report
Current view: top level - wpa_supplicant - hs20_supplicant.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1475438200 Lines: 660 681 96.9 %
Date: 2016-10-02 Functions: 33 33 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2009, Atheros Communications, Inc.
       3             :  * Copyright (c) 2011-2013, 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             : #include <sys/stat.h>
      11             : 
      12             : #include "common.h"
      13             : #include "eloop.h"
      14             : #include "common/ieee802_11_common.h"
      15             : #include "common/ieee802_11_defs.h"
      16             : #include "common/gas.h"
      17             : #include "common/wpa_ctrl.h"
      18             : #include "rsn_supp/wpa.h"
      19             : #include "wpa_supplicant_i.h"
      20             : #include "driver_i.h"
      21             : #include "config.h"
      22             : #include "scan.h"
      23             : #include "bss.h"
      24             : #include "blacklist.h"
      25             : #include "gas_query.h"
      26             : #include "interworking.h"
      27             : #include "hs20_supplicant.h"
      28             : #include "base64.h"
      29             : 
      30             : 
      31             : #define OSU_MAX_ITEMS 10
      32             : 
      33             : struct osu_lang_string {
      34             :         char lang[4];
      35             :         char text[253];
      36             : };
      37             : 
      38             : struct osu_icon {
      39             :         u16 width;
      40             :         u16 height;
      41             :         char lang[4];
      42             :         char icon_type[256];
      43             :         char filename[256];
      44             :         unsigned int id;
      45             :         unsigned int failed:1;
      46             : };
      47             : 
      48             : struct osu_provider {
      49             :         u8 bssid[ETH_ALEN];
      50             :         u8 osu_ssid[SSID_MAX_LEN];
      51             :         u8 osu_ssid_len;
      52             :         char server_uri[256];
      53             :         u32 osu_methods; /* bit 0 = OMA-DM, bit 1 = SOAP-XML SPP */
      54             :         char osu_nai[256];
      55             :         struct osu_lang_string friendly_name[OSU_MAX_ITEMS];
      56             :         size_t friendly_name_count;
      57             :         struct osu_lang_string serv_desc[OSU_MAX_ITEMS];
      58             :         size_t serv_desc_count;
      59             :         struct osu_icon icon[OSU_MAX_ITEMS];
      60             :         size_t icon_count;
      61             : };
      62             : 
      63             : 
      64        4903 : void hs20_configure_frame_filters(struct wpa_supplicant *wpa_s)
      65             : {
      66        4903 :         struct wpa_bss *bss = wpa_s->current_bss;
      67        4903 :         u8 *bssid = wpa_s->bssid;
      68             :         const u8 *ie;
      69             :         const u8 *ext_capa;
      70        4903 :         u32 filter = 0;
      71             : 
      72        4903 :         if (!bss || !is_hs20_network(wpa_s, wpa_s->current_ssid, bss)) {
      73       28734 :                 wpa_printf(MSG_DEBUG,
      74             :                            "Not configuring frame filtering - BSS " MACSTR
      75       28734 :                            " is not a Hotspot 2.0 network", MAC2STR(bssid));
      76        4789 :                 return;
      77             :         }
      78             : 
      79         114 :         ie = wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE);
      80             : 
      81             :         /* Check if DGAF disabled bit is zero (5th byte in the IE) */
      82         114 :         if (!ie || ie[1] < 5)
      83           1 :                 wpa_printf(MSG_DEBUG,
      84             :                            "Not configuring frame filtering - Can't extract DGAF bit");
      85         113 :         else if (!(ie[6] & HS20_DGAF_DISABLED))
      86         107 :                 filter |= WPA_DATA_FRAME_FILTER_FLAG_GTK;
      87             : 
      88         114 :         ext_capa = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB);
      89         114 :         if (!ext_capa || ext_capa[1] < 2) {
      90           0 :                 wpa_printf(MSG_DEBUG,
      91             :                            "Not configuring frame filtering - Can't extract Proxy ARP bit");
      92           0 :                 return;
      93             :         }
      94             : 
      95             :         /* Check if Proxy ARP is enabled (2nd byte in the IE) */
      96         114 :         if (ext_capa[3] & BIT(4))
      97           9 :                 filter |= WPA_DATA_FRAME_FILTER_FLAG_ARP |
      98             :                         WPA_DATA_FRAME_FILTER_FLAG_NA;
      99             : 
     100         114 :         wpa_drv_configure_frame_filters(wpa_s, filter);
     101             : }
     102             : 
     103             : 
     104        1929 : void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id)
     105             : {
     106             :         u8 conf;
     107             : 
     108        1929 :         wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
     109        1929 :         wpabuf_put_u8(buf, pps_mo_id >= 0 ? 7 : 5);
     110        1929 :         wpabuf_put_be24(buf, OUI_WFA);
     111        1929 :         wpabuf_put_u8(buf, HS20_INDICATION_OUI_TYPE);
     112        1929 :         conf = HS20_VERSION;
     113        1929 :         if (pps_mo_id >= 0)
     114         114 :                 conf |= HS20_PPS_MO_ID_PRESENT;
     115        1929 :         wpabuf_put_u8(buf, conf);
     116        1929 :         if (pps_mo_id >= 0)
     117         114 :                 wpabuf_put_le16(buf, pps_mo_id);
     118        1929 : }
     119             : 
     120             : 
     121        9823 : int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
     122             :                     struct wpa_bss *bss)
     123             : {
     124        9823 :         if (!wpa_s->conf->hs20 || !ssid)
     125        5899 :                 return 0;
     126             : 
     127        3924 :         if (ssid->parent_cred)
     128         224 :                 return 1;
     129             : 
     130        3700 :         if (bss && !wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE))
     131        3682 :                 return 0;
     132             : 
     133             :         /*
     134             :          * This may catch some non-Hotspot 2.0 cases, but it is safer to do that
     135             :          * than cause Hotspot 2.0 connections without indication element getting
     136             :          * added. Non-Hotspot 2.0 APs should ignore the unknown vendor element.
     137             :          */
     138             : 
     139          18 :         if (!(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X))
     140           8 :                 return 0;
     141          10 :         if (!(ssid->pairwise_cipher & WPA_CIPHER_CCMP))
     142           2 :                 return 0;
     143           8 :         if (ssid->proto != WPA_PROTO_RSN)
     144           4 :                 return 0;
     145             : 
     146           4 :         return 1;
     147             : }
     148             : 
     149             : 
     150         114 : int hs20_get_pps_mo_id(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
     151             : {
     152             :         struct wpa_cred *cred;
     153             : 
     154         114 :         if (ssid == NULL)
     155           0 :                 return 0;
     156             : 
     157         114 :         if (ssid->update_identifier)
     158           1 :                 return ssid->update_identifier;
     159             : 
     160         113 :         if (ssid->parent_cred == NULL)
     161           1 :                 return 0;
     162             : 
     163         117 :         for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
     164         117 :                 if (ssid->parent_cred == cred)
     165         112 :                         return cred->update_identifier;
     166             :         }
     167             : 
     168           0 :         return 0;
     169             : }
     170             : 
     171             : 
     172          48 : void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len,
     173             :                        struct wpabuf *buf)
     174             : {
     175             :         u8 *len_pos;
     176             : 
     177          48 :         if (buf == NULL)
     178          48 :                 return;
     179             : 
     180          48 :         len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
     181          48 :         wpabuf_put_be24(buf, OUI_WFA);
     182          48 :         wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
     183          48 :         if (stypes == BIT(HS20_STYPE_NAI_HOME_REALM_QUERY)) {
     184           4 :                 wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY);
     185           4 :                 wpabuf_put_u8(buf, 0); /* Reserved */
     186           4 :                 if (payload)
     187           4 :                         wpabuf_put_data(buf, payload, payload_len);
     188          44 :         } else if (stypes == BIT(HS20_STYPE_ICON_REQUEST)) {
     189          29 :                 wpabuf_put_u8(buf, HS20_STYPE_ICON_REQUEST);
     190          29 :                 wpabuf_put_u8(buf, 0); /* Reserved */
     191          29 :                 if (payload)
     192          29 :                         wpabuf_put_data(buf, payload, payload_len);
     193             :         } else {
     194             :                 u8 i;
     195          15 :                 wpabuf_put_u8(buf, HS20_STYPE_QUERY_LIST);
     196          15 :                 wpabuf_put_u8(buf, 0); /* Reserved */
     197         495 :                 for (i = 0; i < 32; i++) {
     198         480 :                         if (stypes & BIT(i))
     199          29 :                                 wpabuf_put_u8(buf, i);
     200             :                 }
     201             :         }
     202          48 :         gas_anqp_set_element_len(buf, len_pos);
     203             : 
     204          48 :         gas_anqp_set_len(buf);
     205             : }
     206             : 
     207             : 
     208          50 : static struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
     209             :                                            size_t payload_len)
     210             : {
     211             :         struct wpabuf *buf;
     212             : 
     213          50 :         buf = gas_anqp_build_initial_req(0, 100 + payload_len);
     214          50 :         if (buf == NULL)
     215           3 :                 return NULL;
     216             : 
     217          47 :         hs20_put_anqp_req(stypes, payload, payload_len, buf);
     218             : 
     219          47 :         return buf;
     220             : }
     221             : 
     222             : 
     223          52 : int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
     224             :                        const u8 *payload, size_t payload_len, int inmem)
     225             : {
     226             :         struct wpabuf *buf;
     227          52 :         int ret = 0;
     228             :         int freq;
     229             :         struct wpa_bss *bss;
     230             :         int res;
     231             :         struct icon_entry *icon_entry;
     232             : 
     233          52 :         bss = wpa_bss_get_bssid(wpa_s, dst);
     234          52 :         if (!bss) {
     235          12 :                 wpa_printf(MSG_WARNING,
     236             :                            "ANQP: Cannot send query to unknown BSS "
     237          12 :                            MACSTR, MAC2STR(dst));
     238           2 :                 return -1;
     239             :         }
     240             : 
     241          50 :         wpa_bss_anqp_unshare_alloc(bss);
     242          50 :         freq = bss->freq;
     243             : 
     244         300 :         wpa_printf(MSG_DEBUG, "HS20: ANQP Query Request to " MACSTR " for "
     245         300 :                    "subtypes 0x%x", MAC2STR(dst), stypes);
     246             : 
     247          50 :         buf = hs20_build_anqp_req(stypes, payload, payload_len);
     248          50 :         if (buf == NULL)
     249           3 :                 return -1;
     250             : 
     251          47 :         res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
     252          47 :         if (res < 0) {
     253           2 :                 wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
     254           2 :                 wpabuf_free(buf);
     255           2 :                 return -1;
     256             :         } else
     257          45 :                 wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
     258             :                            "%u", res);
     259             : 
     260          45 :         if (inmem) {
     261          14 :                 icon_entry = os_zalloc(sizeof(struct icon_entry));
     262          14 :                 if (!icon_entry)
     263           2 :                         return -1;
     264          12 :                 os_memcpy(icon_entry->bssid, dst, ETH_ALEN);
     265          12 :                 icon_entry->file_name = os_malloc(payload_len + 1);
     266          12 :                 if (!icon_entry->file_name) {
     267           2 :                         os_free(icon_entry);
     268           2 :                         return -1;
     269             :                 }
     270          10 :                 os_memcpy(icon_entry->file_name, payload, payload_len);
     271          10 :                 icon_entry->file_name[payload_len] = '\0';
     272          10 :                 icon_entry->dialog_token = res;
     273             : 
     274          10 :                 dl_list_add(&wpa_s->icon_head, &icon_entry->list);
     275             :         }
     276             : 
     277          41 :         return ret;
     278             : }
     279             : 
     280             : 
     281          32 : static struct icon_entry * hs20_find_icon(struct wpa_supplicant *wpa_s,
     282             :                                           const u8 *bssid,
     283             :                                           const char *file_name)
     284             : {
     285             :         struct icon_entry *icon;
     286             : 
     287          41 :         dl_list_for_each(icon, &wpa_s->icon_head, struct icon_entry, list) {
     288          80 :                 if (os_memcmp(icon->bssid, bssid, ETH_ALEN) == 0 &&
     289          71 :                     os_strcmp(icon->file_name, file_name) == 0 && icon->image)
     290          31 :                         return icon;
     291             :         }
     292             : 
     293           1 :         return NULL;
     294             : }
     295             : 
     296             : 
     297          32 : int hs20_get_icon(struct wpa_supplicant *wpa_s, const u8 *bssid,
     298             :                   const char *file_name, size_t offset, size_t size,
     299             :                   char *reply, size_t buf_len)
     300             : {
     301             :         struct icon_entry *icon;
     302             :         size_t out_size;
     303             :         unsigned char *b64;
     304             :         size_t b64_size;
     305             :         int reply_size;
     306             : 
     307         224 :         wpa_printf(MSG_DEBUG, "HS20: Get icon " MACSTR " %s @ %u +%u (%u)",
     308         192 :                    MAC2STR(bssid), file_name, (unsigned int) offset,
     309             :                    (unsigned int) size, (unsigned int) buf_len);
     310             : 
     311          32 :         icon = hs20_find_icon(wpa_s, bssid, file_name);
     312          32 :         if (!icon || !icon->image || offset >= icon->image_len)
     313           7 :                 return -1;
     314          25 :         if (size > icon->image_len - offset)
     315           5 :                 size = icon->image_len - offset;
     316          25 :         out_size = buf_len - 3 /* max base64 padding */;
     317          25 :         if (size * 4 > out_size * 3)
     318           1 :                 size = out_size * 3 / 4;
     319          25 :         if (size == 0)
     320           1 :                 return -1;
     321             : 
     322          24 :         b64 = base64_encode(&icon->image[offset], size, &b64_size);
     323          24 :         if (b64 && buf_len >= b64_size) {
     324          22 :                 os_memcpy(reply, b64, b64_size);
     325          22 :                 reply_size = b64_size;
     326             :         } else {
     327           2 :                 reply_size = -1;
     328             :         }
     329          24 :         os_free(b64);
     330          24 :         return reply_size;
     331             : }
     332             : 
     333             : 
     334          10 : static void hs20_free_icon_entry(struct icon_entry *icon)
     335             : {
     336          90 :         wpa_printf(MSG_DEBUG, "HS20: Free stored icon from " MACSTR
     337             :                    " dialog_token=%u file_name=%s image_len=%u",
     338          70 :                    MAC2STR(icon->bssid), icon->dialog_token,
     339          10 :                    icon->file_name ? icon->file_name : "N/A",
     340          10 :                    (unsigned int) icon->image_len);
     341          10 :         os_free(icon->file_name);
     342          10 :         os_free(icon->image);
     343          10 :         os_free(icon);
     344          10 : }
     345             : 
     346             : 
     347        6766 : int hs20_del_icon(struct wpa_supplicant *wpa_s, const u8 *bssid,
     348             :                   const char *file_name)
     349             : {
     350             :         struct icon_entry *icon, *tmp;
     351        6766 :         int count = 0;
     352             : 
     353        6766 :         if (!bssid)
     354        6759 :                 wpa_printf(MSG_DEBUG, "HS20: Delete all stored icons");
     355           7 :         else if (!file_name)
     356           6 :                 wpa_printf(MSG_DEBUG, "HS20: Delete all stored icons for "
     357           6 :                            MACSTR, MAC2STR(bssid));
     358             :         else
     359          36 :                 wpa_printf(MSG_DEBUG, "HS20: Delete stored icons for "
     360          36 :                            MACSTR " file name %s", MAC2STR(bssid), file_name);
     361             : 
     362        6777 :         dl_list_for_each_safe(icon, tmp, &wpa_s->icon_head, struct icon_entry,
     363             :                               list) {
     364          11 :                 if ((!bssid || os_memcmp(icon->bssid, bssid, ETH_ALEN) == 0) &&
     365           8 :                     (!file_name ||
     366           8 :                      os_strcmp(icon->file_name, file_name) == 0)) {
     367           9 :                         dl_list_del(&icon->list);
     368           9 :                         hs20_free_icon_entry(icon);
     369           9 :                         count++;
     370             :                 }
     371             :         }
     372        6766 :         return count == 0 ? -1 : 0;
     373             : }
     374             : 
     375             : 
     376          36 : static void hs20_set_osu_access_permission(const char *osu_dir,
     377             :                                            const char *fname)
     378             : {
     379             :         struct stat statbuf;
     380             : 
     381             :         /* Get OSU directory information */
     382          36 :         if (stat(osu_dir, &statbuf) < 0) {
     383           0 :                 wpa_printf(MSG_WARNING, "Cannot stat the OSU directory %s",
     384             :                            osu_dir);
     385           0 :                 return;
     386             :         }
     387             : 
     388          36 :         if (chmod(fname, statbuf.st_mode) < 0) {
     389           0 :                 wpa_printf(MSG_WARNING,
     390             :                            "Cannot change the permissions for %s", fname);
     391           0 :                 return;
     392             :         }
     393             : 
     394          36 :         if (chown(fname, statbuf.st_uid, statbuf.st_gid) < 0) {
     395           0 :                 wpa_printf(MSG_WARNING, "Cannot change the ownership for %s",
     396             :                            fname);
     397             :         }
     398             : }
     399             : 
     400             : 
     401           9 : static void hs20_remove_duplicate_icons(struct wpa_supplicant *wpa_s,
     402             :                                         struct icon_entry *new_icon)
     403             : {
     404             :         struct icon_entry *icon, *tmp;
     405             : 
     406          22 :         dl_list_for_each_safe(icon, tmp, &wpa_s->icon_head, struct icon_entry,
     407             :                               list) {
     408          13 :                 if (icon == new_icon)
     409           9 :                         continue;
     410           8 :                 if (os_memcmp(icon->bssid, new_icon->bssid, ETH_ALEN) == 0 &&
     411           4 :                     os_strcmp(icon->file_name, new_icon->file_name) == 0) {
     412           1 :                         dl_list_del(&icon->list);
     413           1 :                         hs20_free_icon_entry(icon);
     414             :                 }
     415             :         }
     416           9 : }
     417             : 
     418             : 
     419          28 : static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s,
     420             :                                          const u8 *sa, const u8 *pos,
     421             :                                          size_t slen, u8 dialog_token)
     422             : {
     423             :         char fname[256];
     424             :         int png;
     425             :         FILE *f;
     426             :         u16 data_len;
     427             :         struct icon_entry *icon;
     428             : 
     429          31 :         dl_list_for_each(icon, &wpa_s->icon_head, struct icon_entry, list) {
     430          23 :                 if (icon->dialog_token == dialog_token && !icon->image &&
     431          10 :                     os_memcmp(icon->bssid, sa, ETH_ALEN) == 0) {
     432          10 :                         icon->image = os_malloc(slen);
     433          10 :                         if (!icon->image)
     434           1 :                                 return -1;
     435           9 :                         os_memcpy(icon->image, pos, slen);
     436           9 :                         icon->image_len = slen;
     437           9 :                         hs20_remove_duplicate_icons(wpa_s, icon);
     438          63 :                         wpa_msg(wpa_s, MSG_INFO,
     439             :                                 RX_HS20_ICON MACSTR " %s %u",
     440          54 :                                 MAC2STR(sa), icon->file_name,
     441           9 :                                 (unsigned int) icon->image_len);
     442           9 :                         return 0;
     443             :                 }
     444             :         }
     445             : 
     446         108 :         wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " Icon Binary File",
     447         108 :                 MAC2STR(sa));
     448             : 
     449          18 :         if (slen < 4) {
     450           1 :                 wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File "
     451             :                         "value from " MACSTR, MAC2STR(sa));
     452           1 :                 return -1;
     453             :         }
     454             : 
     455          17 :         wpa_printf(MSG_DEBUG, "HS 2.0: Download Status Code %u", *pos);
     456          17 :         if (*pos != 0)
     457           4 :                 return -1;
     458          13 :         pos++;
     459          13 :         slen--;
     460             : 
     461          13 :         if ((size_t) 1 + pos[0] > slen) {
     462           1 :                 wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File "
     463             :                         "value from " MACSTR, MAC2STR(sa));
     464           1 :                 return -1;
     465             :         }
     466          12 :         wpa_hexdump_ascii(MSG_DEBUG, "Icon Type", pos + 1, pos[0]);
     467          12 :         png = os_strncasecmp((char *) pos + 1, "image/png", 9) == 0;
     468          12 :         slen -= 1 + pos[0];
     469          12 :         pos += 1 + pos[0];
     470             : 
     471          12 :         if (slen < 2) {
     472           1 :                 wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File "
     473             :                         "value from " MACSTR, MAC2STR(sa));
     474           1 :                 return -1;
     475             :         }
     476          11 :         data_len = WPA_GET_LE16(pos);
     477          11 :         pos += 2;
     478          11 :         slen -= 2;
     479             : 
     480          11 :         if (data_len > slen) {
     481           2 :                 wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File "
     482             :                         "value from " MACSTR, MAC2STR(sa));
     483           2 :                 return -1;
     484             :         }
     485             : 
     486           9 :         wpa_printf(MSG_DEBUG, "Icon Binary Data: %u bytes", data_len);
     487           9 :         if (wpa_s->conf->osu_dir == NULL)
     488           4 :                 return -1;
     489             : 
     490           5 :         wpa_s->osu_icon_id++;
     491           5 :         if (wpa_s->osu_icon_id == 0)
     492           0 :                 wpa_s->osu_icon_id++;
     493          10 :         snprintf(fname, sizeof(fname), "%s/osu-icon-%u.%s",
     494           5 :                  wpa_s->conf->osu_dir, wpa_s->osu_icon_id,
     495             :                  png ? "png" : "icon");
     496           5 :         f = fopen(fname, "wb");
     497           5 :         if (f == NULL)
     498           3 :                 return -1;
     499             : 
     500           2 :         hs20_set_osu_access_permission(wpa_s->conf->osu_dir, fname);
     501             : 
     502           2 :         if (fwrite(pos, slen, 1, f) != 1) {
     503           0 :                 fclose(f);
     504           0 :                 unlink(fname);
     505           0 :                 return -1;
     506             :         }
     507           2 :         fclose(f);
     508             : 
     509           2 :         wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP_ICON "%s", fname);
     510           2 :         return 0;
     511             : }
     512             : 
     513             : 
     514           5 : static void hs20_continue_icon_fetch(void *eloop_ctx, void *sock_ctx)
     515             : {
     516           5 :         struct wpa_supplicant *wpa_s = eloop_ctx;
     517           5 :         if (wpa_s->fetch_osu_icon_in_progress)
     518           5 :                 hs20_next_osu_icon(wpa_s);
     519           5 : }
     520             : 
     521             : 
     522           5 : static void hs20_osu_icon_fetch_result(struct wpa_supplicant *wpa_s, int res)
     523             : {
     524             :         size_t i, j;
     525             :         struct os_reltime now, tmp;
     526             :         int dur;
     527             : 
     528           5 :         os_get_reltime(&now);
     529           5 :         os_reltime_sub(&now, &wpa_s->osu_icon_fetch_start, &tmp);
     530           5 :         dur = tmp.sec * 1000 + tmp.usec / 1000;
     531           5 :         wpa_printf(MSG_DEBUG, "HS 2.0: Icon fetch dur=%d ms res=%d",
     532             :                    dur, res);
     533             : 
     534           6 :         for (i = 0; i < wpa_s->osu_prov_count; i++) {
     535           6 :                 struct osu_provider *osu = &wpa_s->osu_prov[i];
     536          14 :                 for (j = 0; j < osu->icon_count; j++) {
     537           6 :                         struct osu_icon *icon = &osu->icon[j];
     538           6 :                         if (icon->id || icon->failed)
     539           1 :                                 continue;
     540           5 :                         if (res < 0)
     541           3 :                                 icon->failed = 1;
     542             :                         else
     543           2 :                                 icon->id = wpa_s->osu_icon_id;
     544          10 :                         return;
     545             :                 }
     546             :         }
     547             : }
     548             : 
     549             : 
     550         477 : void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
     551             :                                   struct wpa_bss *bss, const u8 *sa,
     552             :                                   const u8 *data, size_t slen, u8 dialog_token)
     553             : {
     554         477 :         const u8 *pos = data;
     555             :         u8 subtype;
     556         477 :         struct wpa_bss_anqp *anqp = NULL;
     557             :         int ret;
     558             : 
     559         477 :         if (slen < 2)
     560         478 :                 return;
     561             : 
     562         476 :         if (bss)
     563         476 :                 anqp = bss->anqp;
     564             : 
     565         476 :         subtype = *pos++;
     566         476 :         slen--;
     567             : 
     568         476 :         pos++; /* Reserved */
     569         476 :         slen--;
     570             : 
     571         476 :         switch (subtype) {
     572             :         case HS20_STYPE_CAPABILITY_LIST:
     573        1698 :                 wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
     574        1698 :                         " HS Capability List", MAC2STR(sa));
     575         283 :                 wpa_hexdump_ascii(MSG_DEBUG, "HS Capability List", pos, slen);
     576         283 :                 if (anqp) {
     577         283 :                         wpabuf_free(anqp->hs20_capability_list);
     578         283 :                         anqp->hs20_capability_list =
     579         283 :                                 wpabuf_alloc_copy(pos, slen);
     580             :                 }
     581         283 :                 break;
     582             :         case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
     583          66 :                 wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
     584          66 :                         " Operator Friendly Name", MAC2STR(sa));
     585          11 :                 wpa_hexdump_ascii(MSG_DEBUG, "oper friendly name", pos, slen);
     586          11 :                 if (anqp) {
     587          11 :                         wpabuf_free(anqp->hs20_operator_friendly_name);
     588          11 :                         anqp->hs20_operator_friendly_name =
     589          11 :                                 wpabuf_alloc_copy(pos, slen);
     590             :                 }
     591          11 :                 break;
     592             :         case HS20_STYPE_WAN_METRICS:
     593          57 :                 wpa_hexdump(MSG_DEBUG, "WAN Metrics", pos, slen);
     594          57 :                 if (slen < 13) {
     595           1 :                         wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short WAN "
     596             :                                 "Metrics value from " MACSTR, MAC2STR(sa));
     597           1 :                         break;
     598             :                 }
     599         560 :                 wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
     600         336 :                         " WAN Metrics %02x:%u:%u:%u:%u:%u", MAC2STR(sa),
     601          56 :                         pos[0], WPA_GET_LE32(pos + 1), WPA_GET_LE32(pos + 5),
     602         168 :                         pos[9], pos[10], WPA_GET_LE16(pos + 11));
     603          56 :                 if (anqp) {
     604          56 :                         wpabuf_free(anqp->hs20_wan_metrics);
     605          56 :                         anqp->hs20_wan_metrics = wpabuf_alloc_copy(pos, slen);
     606             :                 }
     607          56 :                 break;
     608             :         case HS20_STYPE_CONNECTION_CAPABILITY:
     609         210 :                 wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
     610         210 :                         " Connection Capability", MAC2STR(sa));
     611          35 :                 wpa_hexdump_ascii(MSG_DEBUG, "conn capability", pos, slen);
     612          35 :                 if (anqp) {
     613          35 :                         wpabuf_free(anqp->hs20_connection_capability);
     614          35 :                         anqp->hs20_connection_capability =
     615          35 :                                 wpabuf_alloc_copy(pos, slen);
     616             :                 }
     617          35 :                 break;
     618             :         case HS20_STYPE_OPERATING_CLASS:
     619         132 :                 wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
     620         132 :                         " Operating Class", MAC2STR(sa));
     621          22 :                 wpa_hexdump_ascii(MSG_DEBUG, "Operating Class", pos, slen);
     622          22 :                 if (anqp) {
     623          22 :                         wpabuf_free(anqp->hs20_operating_class);
     624          22 :                         anqp->hs20_operating_class =
     625          22 :                                 wpabuf_alloc_copy(pos, slen);
     626             :                 }
     627          22 :                 break;
     628             :         case HS20_STYPE_OSU_PROVIDERS_LIST:
     629         216 :                 wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
     630         216 :                         " OSU Providers list", MAC2STR(sa));
     631          36 :                 wpa_s->num_prov_found++;
     632          36 :                 if (anqp) {
     633          36 :                         wpabuf_free(anqp->hs20_osu_providers_list);
     634          36 :                         anqp->hs20_osu_providers_list =
     635          36 :                                 wpabuf_alloc_copy(pos, slen);
     636             :                 }
     637          36 :                 break;
     638             :         case HS20_STYPE_ICON_BINARY_FILE:
     639          28 :                 ret = hs20_process_icon_binary_file(wpa_s, sa, pos, slen,
     640             :                                                     dialog_token);
     641          28 :                 if (wpa_s->fetch_osu_icon_in_progress) {
     642           4 :                         hs20_osu_icon_fetch_result(wpa_s, ret);
     643           4 :                         eloop_cancel_timeout(hs20_continue_icon_fetch,
     644             :                                              wpa_s, NULL);
     645           4 :                         eloop_register_timeout(0, 0, hs20_continue_icon_fetch,
     646             :                                                wpa_s, NULL);
     647             :                 }
     648          28 :                 break;
     649             :         default:
     650           4 :                 wpa_printf(MSG_DEBUG, "HS20: Unsupported subtype %u", subtype);
     651           4 :                 break;
     652             :         }
     653             : }
     654             : 
     655             : 
     656         387 : void hs20_notify_parse_done(struct wpa_supplicant *wpa_s)
     657             : {
     658         387 :         if (!wpa_s->fetch_osu_icon_in_progress)
     659         383 :                 return;
     660           4 :         if (eloop_is_timeout_registered(hs20_continue_icon_fetch, wpa_s, NULL))
     661           4 :                 return;
     662             :         /*
     663             :          * We are going through icon fetch, but no icon response was received.
     664             :          * Assume this means the current AP could not provide an answer to avoid
     665             :          * getting stuck in fetch iteration.
     666             :          */
     667           0 :         hs20_icon_fetch_failed(wpa_s);
     668             : }
     669             : 
     670             : 
     671           8 : static void hs20_free_osu_prov_entry(struct osu_provider *prov)
     672             : {
     673           8 : }
     674             : 
     675             : 
     676         803 : void hs20_free_osu_prov(struct wpa_supplicant *wpa_s)
     677             : {
     678             :         size_t i;
     679         811 :         for (i = 0; i < wpa_s->osu_prov_count; i++)
     680           8 :                 hs20_free_osu_prov_entry(&wpa_s->osu_prov[i]);
     681         803 :         os_free(wpa_s->osu_prov);
     682         803 :         wpa_s->osu_prov = NULL;
     683         803 :         wpa_s->osu_prov_count = 0;
     684         803 : }
     685             : 
     686             : 
     687          35 : static void hs20_osu_fetch_done(struct wpa_supplicant *wpa_s)
     688             : {
     689             :         char fname[256];
     690             :         FILE *f;
     691             :         size_t i, j;
     692             : 
     693          35 :         wpa_s->fetch_osu_info = 0;
     694          35 :         wpa_s->fetch_osu_icon_in_progress = 0;
     695             : 
     696          35 :         if (wpa_s->conf->osu_dir == NULL) {
     697           0 :                 hs20_free_osu_prov(wpa_s);
     698           0 :                 wpa_s->fetch_anqp_in_progress = 0;
     699           1 :                 return;
     700             :         }
     701             : 
     702          35 :         snprintf(fname, sizeof(fname), "%s/osu-providers.txt",
     703          35 :                  wpa_s->conf->osu_dir);
     704          35 :         f = fopen(fname, "w");
     705          35 :         if (f == NULL) {
     706           1 :                 wpa_msg(wpa_s, MSG_INFO,
     707             :                         "Could not write OSU provider information");
     708           1 :                 hs20_free_osu_prov(wpa_s);
     709           1 :                 wpa_s->fetch_anqp_in_progress = 0;
     710           1 :                 return;
     711             :         }
     712             : 
     713          34 :         hs20_set_osu_access_permission(wpa_s->conf->osu_dir, fname);
     714             : 
     715          41 :         for (i = 0; i < wpa_s->osu_prov_count; i++) {
     716           7 :                 struct osu_provider *osu = &wpa_s->osu_prov[i];
     717           7 :                 if (i > 0)
     718           1 :                         fprintf(f, "\n");
     719          49 :                 fprintf(f, "OSU-PROVIDER " MACSTR "\n"
     720             :                         "uri=%s\n"
     721             :                         "methods=%08x\n",
     722          42 :                         MAC2STR(osu->bssid), osu->server_uri, osu->osu_methods);
     723           7 :                 if (osu->osu_ssid_len) {
     724          14 :                         fprintf(f, "osu_ssid=%s\n",
     725           7 :                                 wpa_ssid_txt(osu->osu_ssid,
     726           7 :                                              osu->osu_ssid_len));
     727             :                 }
     728           7 :                 if (osu->osu_nai[0])
     729           1 :                         fprintf(f, "osu_nai=%s\n", osu->osu_nai);
     730          17 :                 for (j = 0; j < osu->friendly_name_count; j++) {
     731          10 :                         fprintf(f, "friendly_name=%s:%s\n",
     732          10 :                                 osu->friendly_name[j].lang,
     733          10 :                                 osu->friendly_name[j].text);
     734             :                 }
     735          17 :                 for (j = 0; j < osu->serv_desc_count; j++) {
     736          10 :                         fprintf(f, "desc=%s:%s\n",
     737          10 :                                 osu->serv_desc[j].lang,
     738          10 :                                 osu->serv_desc[j].text);
     739             :                 }
     740          12 :                 for (j = 0; j < osu->icon_count; j++) {
     741           5 :                         struct osu_icon *icon = &osu->icon[j];
     742           5 :                         if (icon->failed)
     743           3 :                                 continue; /* could not fetch icon */
     744           4 :                         fprintf(f, "icon=%u:%u:%u:%s:%s:%s\n",
     745           4 :                                 icon->id, icon->width, icon->height, icon->lang,
     746           2 :                                 icon->icon_type, icon->filename);
     747             :                 }
     748             :         }
     749          34 :         fclose(f);
     750          34 :         hs20_free_osu_prov(wpa_s);
     751             : 
     752          34 :         wpa_msg(wpa_s, MSG_INFO, "OSU provider fetch completed");
     753          34 :         wpa_s->fetch_anqp_in_progress = 0;
     754             : }
     755             : 
     756             : 
     757          40 : void hs20_next_osu_icon(struct wpa_supplicant *wpa_s)
     758             : {
     759             :         size_t i, j;
     760             : 
     761          40 :         wpa_printf(MSG_DEBUG, "HS 2.0: Ready to fetch next icon");
     762             : 
     763          49 :         for (i = 0; i < wpa_s->osu_prov_count; i++) {
     764          14 :                 struct osu_provider *osu = &wpa_s->osu_prov[i];
     765          21 :                 for (j = 0; j < osu->icon_count; j++) {
     766          12 :                         struct osu_icon *icon = &osu->icon[j];
     767          12 :                         if (icon->id || icon->failed)
     768           6 :                                 continue;
     769             : 
     770          42 :                         wpa_printf(MSG_DEBUG, "HS 2.0: Try to fetch icon '%s' "
     771           6 :                                    "from " MACSTR, icon->filename,
     772          36 :                                    MAC2STR(osu->bssid));
     773           6 :                         os_get_reltime(&wpa_s->osu_icon_fetch_start);
     774          12 :                         if (hs20_anqp_send_req(wpa_s, osu->bssid,
     775             :                                                BIT(HS20_STYPE_ICON_REQUEST),
     776           6 :                                                (u8 *) icon->filename,
     777           6 :                                                os_strlen(icon->filename),
     778             :                                                0) < 0) {
     779           1 :                                 icon->failed = 1;
     780           1 :                                 continue;
     781             :                         }
     782          45 :                         return;
     783             :                 }
     784             :         }
     785             : 
     786          35 :         wpa_printf(MSG_DEBUG, "HS 2.0: No more icons to fetch");
     787          35 :         hs20_osu_fetch_done(wpa_s);
     788             : }
     789             : 
     790             : 
     791          29 : static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
     792             :                               const u8 *osu_ssid, u8 osu_ssid_len,
     793             :                               const u8 *pos, size_t len)
     794             : {
     795             :         struct osu_provider *prov;
     796          29 :         const u8 *end = pos + len;
     797             :         u16 len2;
     798             :         const u8 *pos2;
     799             :         u8 uri_len, osu_method_len, osu_nai_len;
     800             : 
     801          29 :         wpa_hexdump(MSG_DEBUG, "HS 2.0: Parsing OSU Provider", pos, len);
     802          29 :         prov = os_realloc_array(wpa_s->osu_prov,
     803          29 :                                 wpa_s->osu_prov_count + 1,
     804             :                                 sizeof(*prov));
     805          29 :         if (prov == NULL)
     806           1 :                 return;
     807          28 :         wpa_s->osu_prov = prov;
     808          28 :         prov = &prov[wpa_s->osu_prov_count];
     809          28 :         os_memset(prov, 0, sizeof(*prov));
     810             : 
     811          28 :         os_memcpy(prov->bssid, bss->bssid, ETH_ALEN);
     812          28 :         os_memcpy(prov->osu_ssid, osu_ssid, osu_ssid_len);
     813          28 :         prov->osu_ssid_len = osu_ssid_len;
     814             : 
     815             :         /* OSU Friendly Name Length */
     816          28 :         if (end - pos < 2) {
     817           1 :                 wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
     818             :                            "Friendly Name Length");
     819           1 :                 return;
     820             :         }
     821          27 :         len2 = WPA_GET_LE16(pos);
     822          27 :         pos += 2;
     823          27 :         if (len2 > end - pos) {
     824           1 :                 wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
     825             :                            "Friendly Name Duples");
     826           1 :                 return;
     827             :         }
     828          26 :         pos2 = pos;
     829          26 :         pos += len2;
     830             : 
     831             :         /* OSU Friendly Name Duples */
     832          64 :         while (pos - pos2 >= 4 && prov->friendly_name_count < OSU_MAX_ITEMS) {
     833             :                 struct osu_lang_string *f;
     834          14 :                 if (1 + pos2[0] > pos - pos2 || pos2[0] < 3) {
     835           2 :                         wpa_printf(MSG_DEBUG, "Invalid OSU Friendly Name");
     836           2 :                         break;
     837             :                 }
     838          12 :                 f = &prov->friendly_name[prov->friendly_name_count++];
     839          12 :                 os_memcpy(f->lang, pos2 + 1, 3);
     840          12 :                 os_memcpy(f->text, pos2 + 1 + 3, pos2[0] - 3);
     841          12 :                 pos2 += 1 + pos2[0];
     842             :         }
     843             : 
     844             :         /* OSU Server URI */
     845          26 :         if (end - pos < 1) {
     846           3 :                 wpa_printf(MSG_DEBUG,
     847             :                            "HS 2.0: Not enough room for OSU Server URI length");
     848           3 :                 return;
     849             :         }
     850          23 :         uri_len = *pos++;
     851          23 :         if (uri_len > end - pos) {
     852           1 :                 wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Server "
     853             :                            "URI");
     854           1 :                 return;
     855             :         }
     856          22 :         os_memcpy(prov->server_uri, pos, uri_len);
     857          22 :         pos += uri_len;
     858             : 
     859             :         /* OSU Method list */
     860          22 :         if (end - pos < 1) {
     861           1 :                 wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Method "
     862             :                            "list length");
     863           1 :                 return;
     864             :         }
     865          21 :         osu_method_len = pos[0];
     866          21 :         if (osu_method_len > end - pos - 1) {
     867           1 :                 wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Method "
     868             :                            "list");
     869           1 :                 return;
     870             :         }
     871          20 :         pos2 = pos + 1;
     872          20 :         pos += 1 + osu_method_len;
     873          47 :         while (pos2 < pos) {
     874           7 :                 if (*pos2 < 32)
     875           6 :                         prov->osu_methods |= BIT(*pos2);
     876           7 :                 pos2++;
     877             :         }
     878             : 
     879             :         /* Icons Available Length */
     880          20 :         if (end - pos < 2) {
     881           2 :                 wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for Icons "
     882             :                            "Available Length");
     883           2 :                 return;
     884             :         }
     885          18 :         len2 = WPA_GET_LE16(pos);
     886          18 :         pos += 2;
     887          18 :         if (len2 > end - pos) {
     888           1 :                 wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for Icons "
     889             :                            "Available");
     890           1 :                 return;
     891             :         }
     892          17 :         pos2 = pos;
     893          17 :         pos += len2;
     894             : 
     895             :         /* Icons Available */
     896          40 :         while (pos2 < pos) {
     897          10 :                 struct osu_icon *icon = &prov->icon[prov->icon_count];
     898             :                 u8 flen;
     899             : 
     900          10 :                 if (2 + 2 + 3 + 1 + 1 > pos - pos2) {
     901           1 :                         wpa_printf(MSG_DEBUG, "HS 2.0: Invalid Icon Metadata");
     902           1 :                         break;
     903             :                 }
     904             : 
     905           9 :                 icon->width = WPA_GET_LE16(pos2);
     906           9 :                 pos2 += 2;
     907           9 :                 icon->height = WPA_GET_LE16(pos2);
     908           9 :                 pos2 += 2;
     909           9 :                 os_memcpy(icon->lang, pos2, 3);
     910           9 :                 pos2 += 3;
     911             : 
     912           9 :                 flen = *pos2++;
     913           9 :                 if (flen > pos - pos2) {
     914           1 :                         wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon Type");
     915           1 :                         break;
     916             :                 }
     917           8 :                 os_memcpy(icon->icon_type, pos2, flen);
     918           8 :                 pos2 += flen;
     919             : 
     920           8 :                 if (pos - pos2 < 1) {
     921           1 :                         wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon "
     922             :                                    "Filename length");
     923           1 :                         break;
     924             :                 }
     925           7 :                 flen = *pos2++;
     926           7 :                 if (flen > pos - pos2) {
     927           1 :                         wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon "
     928             :                                    "Filename");
     929           1 :                         break;
     930             :                 }
     931           6 :                 os_memcpy(icon->filename, pos2, flen);
     932           6 :                 pos2 += flen;
     933             : 
     934           6 :                 prov->icon_count++;
     935             :         }
     936             : 
     937             :         /* OSU_NAI */
     938          17 :         if (end - pos < 1) {
     939           5 :                 wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU_NAI");
     940           5 :                 return;
     941             :         }
     942          12 :         osu_nai_len = *pos++;
     943          12 :         if (osu_nai_len > end - pos) {
     944           1 :                 wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU_NAI");
     945           1 :                 return;
     946             :         }
     947          11 :         os_memcpy(prov->osu_nai, pos, osu_nai_len);
     948          11 :         pos += osu_nai_len;
     949             : 
     950             :         /* OSU Service Description Length */
     951          11 :         if (end - pos < 2) {
     952           2 :                 wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
     953             :                            "Service Description Length");
     954           2 :                 return;
     955             :         }
     956           9 :         len2 = WPA_GET_LE16(pos);
     957           9 :         pos += 2;
     958           9 :         if (len2 > end - pos) {
     959           1 :                 wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
     960             :                            "Service Description Duples");
     961           1 :                 return;
     962             :         }
     963           8 :         pos2 = pos;
     964           8 :         pos += len2;
     965             : 
     966             :         /* OSU Service Description Duples */
     967          28 :         while (pos - pos2 >= 4 && prov->serv_desc_count < OSU_MAX_ITEMS) {
     968             :                 struct osu_lang_string *f;
     969             :                 u8 descr_len;
     970             : 
     971          14 :                 descr_len = *pos2++;
     972          14 :                 if (descr_len > pos - pos2 || descr_len < 3) {
     973           2 :                         wpa_printf(MSG_DEBUG, "Invalid OSU Service "
     974             :                                    "Description");
     975           2 :                         break;
     976             :                 }
     977          12 :                 f = &prov->serv_desc[prov->serv_desc_count++];
     978          12 :                 os_memcpy(f->lang, pos2, 3);
     979          12 :                 os_memcpy(f->text, pos2 + 3, descr_len - 3);
     980          12 :                 pos2 += descr_len;
     981             :         }
     982             : 
     983          48 :         wpa_printf(MSG_DEBUG, "HS 2.0: Added OSU Provider through " MACSTR,
     984          48 :                    MAC2STR(bss->bssid));
     985           8 :         wpa_s->osu_prov_count++;
     986             : }
     987             : 
     988             : 
     989          35 : void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s)
     990             : {
     991             :         struct wpa_bss *bss;
     992             :         struct wpabuf *prov_anqp;
     993             :         const u8 *pos, *end;
     994             :         u16 len;
     995             :         const u8 *osu_ssid;
     996             :         u8 osu_ssid_len;
     997             :         u8 num_providers;
     998             : 
     999          35 :         hs20_free_osu_prov(wpa_s);
    1000             : 
    1001          71 :         dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
    1002          36 :                 if (bss->anqp == NULL)
    1003           0 :                         continue;
    1004          36 :                 prov_anqp = bss->anqp->hs20_osu_providers_list;
    1005          36 :                 if (prov_anqp == NULL)
    1006           1 :                         continue;
    1007         210 :                 wpa_printf(MSG_DEBUG, "HS 2.0: Parsing OSU Providers list from "
    1008         210 :                            MACSTR, MAC2STR(bss->bssid));
    1009          35 :                 wpa_hexdump_buf(MSG_DEBUG, "HS 2.0: OSU Providers list",
    1010             :                                 prov_anqp);
    1011          35 :                 pos = wpabuf_head(prov_anqp);
    1012          35 :                 end = pos + wpabuf_len(prov_anqp);
    1013             : 
    1014             :                 /* OSU SSID */
    1015          35 :                 if (end - pos < 1)
    1016           1 :                         continue;
    1017          34 :                 if (1 + pos[0] > end - pos) {
    1018           1 :                         wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for "
    1019             :                                    "OSU SSID");
    1020           1 :                         continue;
    1021             :                 }
    1022          33 :                 osu_ssid_len = *pos++;
    1023          33 :                 if (osu_ssid_len > SSID_MAX_LEN) {
    1024           1 :                         wpa_printf(MSG_DEBUG, "HS 2.0: Invalid OSU SSID "
    1025             :                                    "Length %u", osu_ssid_len);
    1026           1 :                         continue;
    1027             :                 }
    1028          32 :                 osu_ssid = pos;
    1029          32 :                 pos += osu_ssid_len;
    1030             : 
    1031          32 :                 if (end - pos < 1) {
    1032           1 :                         wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for "
    1033             :                                    "Number of OSU Providers");
    1034           1 :                         continue;
    1035             :                 }
    1036          31 :                 num_providers = *pos++;
    1037          31 :                 wpa_printf(MSG_DEBUG, "HS 2.0: Number of OSU Providers: %u",
    1038             :                            num_providers);
    1039             : 
    1040             :                 /* OSU Providers */
    1041          91 :                 while (end - pos > 2 && num_providers > 0) {
    1042          30 :                         num_providers--;
    1043          30 :                         len = WPA_GET_LE16(pos);
    1044          30 :                         pos += 2;
    1045          30 :                         if (len > (unsigned int) (end - pos))
    1046           1 :                                 break;
    1047          29 :                         hs20_osu_add_prov(wpa_s, bss, osu_ssid,
    1048             :                                           osu_ssid_len, pos, len);
    1049          29 :                         pos += len;
    1050             :                 }
    1051             : 
    1052          31 :                 if (pos != end) {
    1053           3 :                         wpa_printf(MSG_DEBUG, "HS 2.0: Ignored %d bytes of "
    1054             :                                    "extra data after OSU Providers",
    1055           3 :                                    (int) (end - pos));
    1056             :                 }
    1057             :         }
    1058             : 
    1059          35 :         wpa_s->fetch_osu_icon_in_progress = 1;
    1060          35 :         hs20_next_osu_icon(wpa_s);
    1061          35 : }
    1062             : 
    1063             : 
    1064           7 : static void hs20_osu_scan_res_handler(struct wpa_supplicant *wpa_s,
    1065             :                                       struct wpa_scan_results *scan_res)
    1066             : {
    1067           7 :         wpa_printf(MSG_DEBUG, "OSU provisioning fetch scan completed");
    1068           7 :         if (!wpa_s->fetch_osu_waiting_scan) {
    1069           1 :                 wpa_printf(MSG_DEBUG, "OSU fetch have been canceled");
    1070           8 :                 return;
    1071             :         }
    1072           6 :         wpa_s->network_select = 0;
    1073           6 :         wpa_s->fetch_all_anqp = 1;
    1074           6 :         wpa_s->fetch_osu_info = 1;
    1075           6 :         wpa_s->fetch_osu_icon_in_progress = 0;
    1076             : 
    1077           6 :         interworking_start_fetch_anqp(wpa_s);
    1078             : }
    1079             : 
    1080             : 
    1081          43 : int hs20_fetch_osu(struct wpa_supplicant *wpa_s, int skip_scan)
    1082             : {
    1083          43 :         if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
    1084           1 :                 wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - "
    1085             :                            "interface disabled");
    1086           1 :                 return -1;
    1087             :         }
    1088             : 
    1089          42 :         if (wpa_s->scanning) {
    1090           2 :                 wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - "
    1091             :                            "scanning");
    1092           2 :                 return -1;
    1093             :         }
    1094             : 
    1095          40 :         if (wpa_s->conf->osu_dir == NULL) {
    1096           0 :                 wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - "
    1097             :                            "osu_dir not configured");
    1098           0 :                 return -1;
    1099             :         }
    1100             : 
    1101          40 :         if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select) {
    1102           6 :                 wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - "
    1103             :                            "fetch in progress (%d, %d)",
    1104           3 :                            wpa_s->fetch_anqp_in_progress,
    1105           3 :                            wpa_s->network_select);
    1106           3 :                 return -1;
    1107             :         }
    1108             : 
    1109          37 :         wpa_msg(wpa_s, MSG_INFO, "Starting OSU provisioning information fetch");
    1110          37 :         wpa_s->num_osu_scans = 0;
    1111          37 :         wpa_s->num_prov_found = 0;
    1112          37 :         if (skip_scan) {
    1113          32 :                 wpa_s->network_select = 0;
    1114          32 :                 wpa_s->fetch_all_anqp = 1;
    1115          32 :                 wpa_s->fetch_osu_info = 1;
    1116          32 :                 wpa_s->fetch_osu_icon_in_progress = 0;
    1117             : 
    1118          32 :                 interworking_start_fetch_anqp(wpa_s);
    1119             :         } else {
    1120           5 :                 hs20_start_osu_scan(wpa_s);
    1121             :         }
    1122             : 
    1123          37 :         return 0;
    1124             : }
    1125             : 
    1126             : 
    1127           7 : void hs20_start_osu_scan(struct wpa_supplicant *wpa_s)
    1128             : {
    1129           7 :         wpa_s->fetch_osu_waiting_scan = 1;
    1130           7 :         wpa_s->num_osu_scans++;
    1131           7 :         wpa_s->scan_req = MANUAL_SCAN_REQ;
    1132           7 :         wpa_s->scan_res_handler = hs20_osu_scan_res_handler;
    1133           7 :         wpa_supplicant_req_scan(wpa_s, 0, 0);
    1134           7 : }
    1135             : 
    1136             : 
    1137        6062 : void hs20_cancel_fetch_osu(struct wpa_supplicant *wpa_s)
    1138             : {
    1139        6062 :         wpa_printf(MSG_DEBUG, "Cancel OSU fetch");
    1140        6062 :         interworking_stop_fetch_anqp(wpa_s);
    1141        6062 :         wpa_s->fetch_osu_waiting_scan = 0;
    1142        6062 :         wpa_s->network_select = 0;
    1143        6062 :         wpa_s->fetch_osu_info = 0;
    1144        6062 :         wpa_s->fetch_osu_icon_in_progress = 0;
    1145        6062 : }
    1146             : 
    1147             : 
    1148           1 : void hs20_icon_fetch_failed(struct wpa_supplicant *wpa_s)
    1149             : {
    1150           1 :         hs20_osu_icon_fetch_result(wpa_s, -1);
    1151           1 :         eloop_cancel_timeout(hs20_continue_icon_fetch, wpa_s, NULL);
    1152           1 :         eloop_register_timeout(0, 0, hs20_continue_icon_fetch, wpa_s, NULL);
    1153           1 : }
    1154             : 
    1155             : 
    1156           4 : void hs20_rx_subscription_remediation(struct wpa_supplicant *wpa_s,
    1157             :                                       const char *url, u8 osu_method)
    1158             : {
    1159           4 :         if (url)
    1160           3 :                 wpa_msg(wpa_s, MSG_INFO, HS20_SUBSCRIPTION_REMEDIATION "%u %s",
    1161             :                         osu_method, url);
    1162             :         else
    1163           1 :                 wpa_msg(wpa_s, MSG_INFO, HS20_SUBSCRIPTION_REMEDIATION);
    1164           4 : }
    1165             : 
    1166             : 
    1167           4 : void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code,
    1168             :                                     u16 reauth_delay, const char *url)
    1169             : {
    1170           4 :         if (!wpa_sm_pmf_enabled(wpa_s->wpa)) {
    1171           1 :                 wpa_printf(MSG_DEBUG, "HS 2.0: Ignore deauthentication imminent notice since PMF was not enabled");
    1172           1 :                 return;
    1173             :         }
    1174             : 
    1175           3 :         wpa_msg(wpa_s, MSG_INFO, HS20_DEAUTH_IMMINENT_NOTICE "%u %u %s",
    1176             :                 code, reauth_delay, url);
    1177             : 
    1178           3 :         if (code == HS20_DEAUTH_REASON_CODE_BSS) {
    1179           1 :                 wpa_printf(MSG_DEBUG, "HS 2.0: Add BSS to blacklist");
    1180           1 :                 wpa_blacklist_add(wpa_s, wpa_s->bssid);
    1181             :                 /* TODO: For now, disable full ESS since some drivers may not
    1182             :                  * support disabling per BSS. */
    1183           1 :                 if (wpa_s->current_ssid) {
    1184             :                         struct os_reltime now;
    1185           1 :                         os_get_reltime(&now);
    1186           2 :                         if (now.sec + reauth_delay <=
    1187           1 :                             wpa_s->current_ssid->disabled_until.sec)
    1188           0 :                                 return;
    1189           1 :                         wpa_printf(MSG_DEBUG, "HS 2.0: Disable network for %u seconds (BSS)",
    1190             :                                    reauth_delay);
    1191           2 :                         wpa_s->current_ssid->disabled_until.sec =
    1192           1 :                                 now.sec + reauth_delay;
    1193             :                 }
    1194             :         }
    1195             : 
    1196           3 :         if (code == HS20_DEAUTH_REASON_CODE_ESS && wpa_s->current_ssid) {
    1197             :                 struct os_reltime now;
    1198           2 :                 os_get_reltime(&now);
    1199           4 :                 if (now.sec + reauth_delay <=
    1200           2 :                     wpa_s->current_ssid->disabled_until.sec)
    1201           0 :                         return;
    1202           2 :                 wpa_printf(MSG_DEBUG, "HS 2.0: Disable network for %u seconds",
    1203             :                            reauth_delay);
    1204           4 :                 wpa_s->current_ssid->disabled_until.sec =
    1205           2 :                         now.sec + reauth_delay;
    1206             :         }
    1207             : }
    1208             : 
    1209             : 
    1210         695 : void hs20_init(struct wpa_supplicant *wpa_s)
    1211             : {
    1212         695 :         dl_list_init(&wpa_s->icon_head);
    1213         695 : }
    1214             : 
    1215             : 
    1216         733 : void hs20_deinit(struct wpa_supplicant *wpa_s)
    1217             : {
    1218         733 :         eloop_cancel_timeout(hs20_continue_icon_fetch, wpa_s, NULL);
    1219         733 :         hs20_free_osu_prov(wpa_s);
    1220         733 :         if (wpa_s->icon_head.next)
    1221         695 :                 hs20_del_icon(wpa_s, NULL, NULL);
    1222         733 : }

Generated by: LCOV version 1.10